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 "發送頻率超限";
}
相關文章
相關標籤/搜索