工做中咱们常常利用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 "发送频率超限"; }