redis限速器的幾種方法

Redis Rate Limiter

redis 實現限速器的幾種方式。html

GET + INCR + EXPIRE

先獲取 key 的當前值,若是沒有超出限制再執行 INCR 增1,若是 key 不存在,使用 redis 的事務初始化 key 和過時時間。redis

僞代碼:併發

count = redis.GET(key)
if redis return nil {
  redis.MULTI
  	redis.INCR(key)
  	redis.EXPIRE(key, expire_time)
  redis.EXEC
  count = 1
}
if count > limit {
  return 超出限制
} else {
  redis.INCR(key)
}

高併發下的問題:高併發

若是同時10個併發程序執行 GET 返回了 nil, 那麼這10個併發程序都會執行 redis 的事務將 key 增一,但每一個程序的 count 值都爲1,若是 limit 設置的值小於10,那麼真正執行的程序就超過限制了。若是執行完事務後再查一次 redis 賦值給 count,那麼每一個程序可能都會返回10,從而沒有程序可以繼續執行。lua

key 已經存在的狀況下,先 GETINCR 的邏輯也可能會出現實際執行的程序數多於 limit 的狀況。code

INCR + EXPIRE

INCR, 若是值爲1說明是 key 剛設置的,此時再執行 EXPIREhtm

僞代碼:事務

count = redis.INCR(key)
if count == 1 {
  redis.EXPIRE(key, expire_time)
}
if count > limit {
  return 超出限制
}

慎用get

若是 INCR 以後程序掛掉了,沒有執行 EXPIRE, 那麼這個 key 就沒有過時時間了,具體的影響視需求而定。string

lua腳本

摘自 http://redisdoc.com/string/incr.html, 我不會lua

local current
current = redis.call("incr",KEYS[1])
if tonumber(current) == 1 then
    redis.call("expire",KEYS[1],1)
end
相關文章
相關標籤/搜索