用法
incrkey,可以將key值原子自增1,並返回遞增操作後key對應的新值。如果指定的key不存在,那麼在執行incr操作之前,會先將它的值設定為0。
/*測試前,清除當前資料庫所有key*/
127.0
.0.1:6379> flushdb
ok/*沒有key*/
127.0
.0.1:6379> keys *
(empty list or
set)
/*使用incr 乙個不存在的key,有返回為1(如果指定的key不存在,那麼在執行incr操作之前,會先將它的值設定為0,並返回自增後的值1)*/
127.0
.0.1:6379> incr incrkey
(integer) 1
127.0
.0.1:6379> get incrkey
"1"/*自增1,返回增加後的值2*/
127.0
.0.1:6379> incr incrkey
(integer) 2
127.0
.0.1:6379> get incrkey
"2"
使用場景1 - 計數器
例如:乙個web應用,我們想記錄每個使用者每天訪問這個**的次數。就可以使用這個使用者的id和當天日期拼接乙個key,每訪問一次只用incr對該key操作,從而獲得該使用者當天的訪問**次數。比如使用者id為9eda3e419e6eadb99293f5c9105816c93a0ca760,今日是20161015,則可以使用incr 9eda3e419e6eadb99293f5c9105816c93a0ca760:20161015作為統計該使用者在2016-10-15當天的訪問次數。
該場景的擴充套件:統計該使用者在某個時間範圍之內的訪問次數,可以結合incr、expire來達到目標。
使用場景2 - 限制訪問次數(一)
假設我們有這樣的需求:每個api介面,每秒每個ip的訪問次數不能超過10次。
我們可以為ip:時間戳(到秒)設定key,以下使用偽碼展示:
function limit_access_count(ip)
currsecond = current_unix_time()
keyname = ip+":"+currsecond
currentcnt = get(keyname)
if currentcnt != null
and currentcnt > 10
then
error "一秒內訪問次數過多"
else
multi
/*比如10.192.168.27在2016-10-15 15:20:19時訪問次數不到10,一直自增*/
incr(keyname,1)
/*計數器每次遞增的時候都設定了10秒的過期時間,這樣在進入下一秒時,redis會自動刪除前一秒的計數器。
* 鍵 10.192.168.27:2016-10-15 15:20:19將會在2016-10-15 15:20:29之後刪除
*/expire(keyname,10)
exec
do_job()
end
使用場景2 - 限制訪問次數(二)
前面例子是每個ip每一秒都生成乙個key。在此例中,我們乙個ip只會生成乙個key,但是實際使用中需要注意競態條件的出現。
具體思路是:從第乙個請求開始設定過期時間為1秒。如果1秒內請求數超過了10個,那麼會提示錯誤資訊。到了下一秒,計數器會清零後重新開始計數。
function limit_access_count(ip)
keyname = ip
currentcnt = get(keyname)
if currentcnt != null
and currentcnt > 10
then
error "一秒內訪問次數過多"
else
multi
/*比如10.192.168.27在2016-10-15 15:20:19時訪問次數不到10,一直自增*/
currentcnt = incr(ip)
if currentcnt == 1
then
/*計數器每次遞增的時候都設定了1秒的過期時間,只有在第一次訪問時才設定超時時間為1秒
* 鍵 10.192.168.27:2016-10-15 15:20:19將會在2016-10-15 15:20:20之後刪除
*/expire(keyname,1)
endexec
do_job()
end
處理競態條件: 使用lua指令碼。
在前面的例子中,如果使用incr後,沒有成功執行expire,會導致這個ip的key引起記憶體洩漏,知道下次有同乙個ip傳送相同請求過來。可以將可能發生競態條件的邏輯放在lua指令碼中,再使用eval解決(要求redis2.6版本以上)
/*lua指令碼*/
local currentcnt
currentcnt = redis.call("incr",keys[1])
if tonumber(currentcnt) == 1
then
redis.call("expire",keys[1],1)
end
getsetkey value 會將value設定為key的值,但是返回的是key原來的值。如果key存在但是對應的value不是字串,就返回錯誤。如果之前key不存在將返回nil。
127.0
.0.1:6379> flushdb
ok127.0
.0.1:6379> keys *
(empty list or
set)
/*使用incr實現計數器自增,使用getset可以重置為0*/
127.0
.0.1:6379> incr testkey
(integer) 1
127.0
.0.1:6379> incr testkey
(integer) 2
127.0
.0.1:6379> getset testkey 0
"2"127.0
.0.1:6379> get testkey
"0"/*key不存在返回nil*/
127.0
.0.1:6379> getset testkey2 0
(nil)
多種方式實現http服務
在對伺服器實現web服務的時候,面對多個使用者的請求時,我們可以採取多程序或者多執行緒。下面是他們的實現 import urllib.request import multiprocessing import re import socket def service client new socke...
redis實現訪問頻次限制的幾種方式
頻次限制器模式是一種特殊的計數器,它常被用來限制某個操作可以被執行的頻次。這個模式的實質其實是限制對乙個公共api執行訪問請求的次數限制。我們使用incr命令提供該模式的兩種實現。這裡我們假設需要解決的問題是 對每個ip,限制對某api的呼叫次數最高位10次每秒。對該模式乙個相對簡單和直接的實現,請...
redis實現訪問頻次限制的幾種方式
頻次限制器模式是一種特殊的計數器,它常被用來限制某個操作可以被執行的頻次。這個模式的實質其實是限制對乙個公共api執行訪問請求的次數限制。我們使用incr命令提供該模式的兩種實現。這裡我們假設需要解決的問題是 對每個ip,限制對某api的呼叫次數最高位10次每秒。對該模式乙個相對簡單和直接的實現,請...