Redis经过Lua实现原子操做

工做中咱们常常利用redis来实现限速, 好比限制一个手机号60秒最多发送3条短信.java

伪代码以下:redis

long count = incr('手机号') ; spring

if count==1  expire('手机号',60) ; bash

if count>3   return "发送频率超限" ; 测试

上面代码在执行时, 客户端先后可能调用redis两次, 虽然不影响限速的功能, 但整个操做的原子性可能被破坏掉. lua

咱们能够利用Lua脚本把incr和expire的调用封装在一块儿, 就能够保证整个操做的原子性. code

定义脚本文件rate_limit.lua,内容以下:ip

-- incr
local count = redis.call('incr',KEYS[1])

-- 第一次时,设置expire
if count == 1 then
  redis.call('expire',KEYS[1],ARGV[1])
end

-- 返回目前次数
return count

经过redis-cli调用lua测试:it

redis-cli --eval rate_limit.lua 手机号 , 60
(integer) 1
redis-cli --eval rate_limit.lua 手机号 , 60
(integer) 2

若是项目是Java编写,且使用了spring-data-redis, 可参考代码以下:class

String lua = "";
lua += "local count = redis.call('incr',KEYS[1]) ";
lua += "if count == 1 then ";
lua += "redis.call('expire',KEYS[1],ARGV[1]) ";
lua += "end ";
lua += "return count";
RedisScript redisScript=new DefaultRedisScript(lua,Long.TYPE);
Long count=(Long)redisTemplate.execute(redisScript, Arrays.asList("手机号"), 60);
if(count>3){
   return "发送频率超限";
}
相关文章
相关标签/搜索