Redis Lua Scripting

Posted 搜狗测试

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis Lua Scripting相关的知识,希望对你有一定的参考价值。

对需要存储数据的需求来说,查询效率是一个必须解决的问题,redis的出现有一点点瑕疵的完美解决了这个问题,今天就来说一下后端大神是怎么干掉这个瑕疵的;

redis特性

  • 支持多种数据结构

  • 支持多种语言

  • 主从复制

  • 支持过期时间

  • 等等

支持的数据类型及基本命令

  • 字符串/数字

Set / get / append / strlen 
Getrange / setrange 
Incrby / decrby

  • hash

Hget / hset / hdel / hlen / hexists 
Hmset / hmget / hgetall 
Hkeys / hvals 
Hincrby / hstrlen

  • 双向列表/队列

Lpush / lpop / rpush / rpop 
Len / lrange / lset / lrem

  • 集合

Sadd / srem / smembers / sismember 
Sdiff / sinter / sunion / smove

  • 有序集合 / 优先队列

Zadd / zcard / zrem 
Zrange / zrangebyscore / zcount / zrank

具体用法就不在这一一赘述了,大家可以自行搜狗,今天主要说一个问题

redis的问题

有一个场景:

  • 需求是这样:需要给1000万的用户下发A开关,500万个用户下发B配置;

  • 实现可以这样:前1000万个用户请求时下发A开关(其中每个请求来的时候通过redis方法hlen查一下这个set的长度是多少,如果<1000万就下发A配置,如果>1000w就下发B配置,当>1500w的时候取消下发配置)

  • 对于测试来说验证这个需求有一条case,就是A开关下发的人数是否是1000万,如果按上述的方法实现,当请求并发时,这个数量很大可能不会正好=1000万,大概率会是1000万多一点;

  • 为什么呢?因为由于redis是单进程多线程操作内存,当多个客户端并发的做redis查询时,相当于多个客户端共享内存,这样就可能出现接近1000万时,10个客户端同时调用hlen查询当前长度,都返回了9999999,那么就会同时给这10个客户端都下发A开关,所以就不能做到精准控制,由于redis查询效率太快,各个客户端之间几乎没办法做数据同步;

解决方案

使用Redis Lua Scripting可以完美解决这个问题;如何解决呢?

local res = red:eval(script, 2, userSetKey, userPushKey, uid, 10000000, 86400)

if res[1] == 1 then

ngx.print("ok")

else

ngx.log(ngx.ERR, "do not push, reason:", res[2])

end

local script = [[

local userSetKey, userPushKey, uid, maxNum, expire = KEYS[1], KEYS[2], ARGV[1], ARGV[2], ARGV[3]

   maxNum = tonumber(maxNum) or 0

   local res = redis.call("exists", userPushKey)

   if res == 1 then

       return {0, "has pushed today"}

   end

   local num = redis.call("hlen", userSetKey)

   local res = redis.call("hexists", userSetKey, uid)

   if num >= maxNum and res == 0 then

       return {0, "exceed Maxnum"}

   end

   res = redis.call("setex", userPushKey, expire, 1)

   res = redis.call("hset", userSetKey, uid, 1)

   return {1, ""}

]]

通过定义script完成多次关联查询和业务逻辑,每个客户端打包执行redis查询,利用redis单线程的特性实现加锁的功能; 
此外,利用script打包执行查询还可以节省网络请求;


以上是关于Redis Lua Scripting的主要内容,如果未能解决你的问题,请参考以下文章

SeedLab - Cross-Site Scripting Attack

redis Lua学习与坑

cocos2dx 启用cjson

Redis+Lua实现限流

PHP 中Lua嵌入redis

Nginx + Lua + redis (转)