Redis中的事務

提到事務大家一定都不陌生,在關(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就會不斷刪除設置了過期時間中,使用最近使用最少的鍵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容