提到事務大家一定都不陌生,在關(guān)系型數(shù)據(jù)庫MySql、Oracle中都存在事物,最常見的就是事物的提交(commit)和事物的回滾(rollback)。
但是Redis中并沒有類似于關(guān)系型數(shù)據(jù)庫的回滾(rollback)。Redis中是事務是一組命令的集合,事務同Redis中的其他命令一樣也是最小執(zhí)行單位。
MULTI命令
從MULTI命令開始,直到EXEC,之間的所有命令就是被事務管理的一組命令。
MULTI
SADD "user:1:following" 2
SADD "user:2:following" 1
EXEC
錯誤處理
- 語法錯誤:命令不存在或者命令參數(shù)個數(shù)不對
MULTI
SET key value
SET key
ERRORCOMMAND key
EXEC
這種情況下,Redis直接 返回錯誤錯誤,即使命令集合中有正確的命令也不會執(zhí)行。
- 運行錯誤:運行錯誤是指命令在執(zhí)行過程中出現(xiàn)的錯誤,如散列類型的命令操作集合類型的鍵,這種情況下命令集合中有命令執(zhí)行出錯,其他命令還會繼續(xù)執(zhí)行,包括錯誤命令之后的命令。
MULTI
HSET key field1 value
SADD key 2
HSET key field1 value2
EXEC
HGET key field1
WATCH命令
WATCH命令可以控制一個或多個鍵,一旦其中有一個鍵被修改或刪除,之后的事務就不會執(zhí)行。監(jiān)控一直持續(xù)到EXEC命令(其實事務中的命令是在EXEC之后執(zhí)行的,所以在MULTI之后可以修改WATCH監(jiān)控的鍵值)。
SET key 1
WATCH key
SET key 2
MULTI
SET key 3#不會執(zhí)行
EXEC
GET key
UNWATCH:取消監(jiān)控
設置過期時間
EXPIRE key seconds:設置鍵的過期時間,秒為單位
當鍵不存在時返回-1
PEXPIRE key mseconds:設置鍵的過期時間,毫秒為單位
TTL獲取剩余過期時間
當鍵沒有設置過期時間返回-1,鍵不存在時返回-2(2.6版本中以上兩種情況都會返回-1,2.8版本及以后才分為以上兩種情況返回)
PERSIST:取消過期時間設置
成功返回1,失敗返回0(鍵不存在或鍵本身就是永久的)
實現(xiàn)訪問頻率限制之一
每分鐘同一個用戶訪問次數(shù)不能超過100
$isKeyExists = EXISTS rate.limiting:$IP
if $isKeyExists is 1
$times = INCR rate.limiting:$IP
if $times > 100
print 訪問頻率超過限制,請稍后再試
exit
else
INCR rate.limiting:$IP
EXPIRE $keyName, 60
上面這段代碼存在一個不太明顯的問題,就是當代碼運行到倒數(shù)第二行后,由于某種原因中斷運行了,那么就會來一個很嚴重的問題:對應IP的用戶在管理員手動刪除該鍵之前,最多只能訪問該站100次!
為了保證鍵的建立和鍵設置過期時間一起執(zhí)行,可以使用上面學習的事物功能,修改后的代碼如下:
$isKeyExists = EXISTS rate.limiting:$IP
if $isKeyExists is 1
$times = INCR rate.limiting:$IP
if $times > 100
print 訪問頻率超過限制,請稍后再試
exit
else
NULTI
INCR rate.limiting:$IP
EXPIRE $keyName, 60
EXEC
實現(xiàn)訪問控制之二
上面的做法確實能做到每分鐘控制用戶訪問100次,但如果用戶在上一分鐘的第一秒訪問1次,最后一秒訪問99次,在下一分鐘的第一秒訪問100次,這樣的話在兩秒內(nèi)就訪問了199次,這與每分鐘訪問100次相差太大了!所以要想做到絕對的沒分鐘訪問100次,就必須記錄用戶的訪問歷史,將訪問歷史紀錄到list中,根據(jù)list的長度和最早一次訪問的時間,控制訪問頻率:
$listLength = LLEN rate..limiting.$IP
if $listLength < 100
LPUSH rate.limiting:$IP,now()
else
$time = LINDEX rate.limiting:$IP,-1
if now() - $time < 60
print 訪問頻率超過限制,請稍后再試
else
LPUSH rate.limiting:$IP,now()
LTRIM rate.limiting:$IP,0,9
實現(xiàn)緩存
為了提高網(wǎng)站的負載能力,常常需要將一些訪問頻率較高但是對CPU或IO資源消耗較大的操作緩存起來,并希望緩存一段時間后自動過期。偽代碼如下:
$rank = GET cache:rank
if not $rank
$rank = 計算排名...
MUITI
SET cache:rank,$rank
EXPIRE cache:rank,7200
EXEC
但實際使用場景中,緩存過期時間的設置是一大難題:設置過久保證不了數(shù)據(jù)的真實性,還會占用內(nèi)存,設置短了會導致緩存命中率過低,而拜拜浪費了內(nèi)存。
Reidis中可以限制其使用的最大內(nèi)存:修改配置文件中的maxmemory參數(shù),限制Redis最大使用的內(nèi)存大?。▎挝皇莃yte)。當占用內(nèi)存超過限制最大內(nèi)存時Redis會依據(jù)maxmemory-policy參數(shù)指定的策略來刪除不必要的鍵直至Redis占用的內(nèi)存小于指定最大占用內(nèi)存。maxmemory-policy支持的規(guī)則如下表:
| 規(guī)則 | 說明 |
|---|---|
| volatile-lru | 使用LRU算法刪除一個鍵(只刪除設置了過期時間的鍵) |
| allkeys-lru | 使用LRU算法刪除一個鍵 |
| volatile-random | 隨機刪除一個鍵(只刪除設置了過期時間的鍵) |
| allkeys-random | 隨機刪除一個鍵 |
| volatile-ttl | 刪除過期時間最近的一個鍵 |
| noteviction | 不刪除鍵,只返回錯誤 |
如當設置maxmomory-policy的值為volatile-lur,當redis占用內(nèi)存超過最大內(nèi)存時,redis就會不斷刪除設置了過期時間中,使用最近使用最少的鍵。