Redis通过Lua实现原子操作
Posted 程序员爱学习
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis通过Lua实现原子操作相关的知识,希望对你有一定的参考价值。
工作中我们经常利用 redis 来实现限速, 比如限制一个手机号 60秒最多发送3条短信.
如果不考虑原子性, 伪代码如下:
long count = incr('手机号') ;
if count==0 expire('手机号',60) ;
if count>3 return "发送频率超限" ;
上面代码在执行时, 前后可能调用 redis 两次, 网络耗时的问题,忽略不说, 但另外一个问题应该被重视, 就是整个执行的原子性, 假如 incr 执行成功,而 expire 执行失败, 那么 reids 里面就会存在不主动失效的脏数据.
为了保证整个执行的原子性, 我们来利用 Lua.
首先把 incr 和 expire 的调用逻辑一起封装在 Lua 里, 然后再通过 redis 调用.
定义脚本文件 rate_limit.lua ,内容如下:
-- 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 测试:
redis-cli --eval rate_limit.lua 手机号 , 60
(integer) 1
redis-cli --eval rate_limit.lua 手机号 , 60
(integer) 2
如果项目是 Java 编写,且使用了 spring-data-redis, 可参考代码如下:
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 "发送频率超限";
}
以上是关于Redis通过Lua实现原子操作的主要内容,如果未能解决你的问题,请参考以下文章