Redis拔高篇——Redis事務和鎖

事務

什麼是事務

redis事務就是一個命令執行的隊列,將一系列預定義命令包裝成一個整體(一個隊列)。當執行時,一次性
按照添加順序依次執行,中間不會被打斷或者干擾。

簡言之,事務就是一個隊列中,一次性、順序性、排他性的執行一系列命令

事務的基本操作
  • 開啓事務
    multi
  • 作用
    設定事務的開啓位置,此指令執行後,後續的所有指令均加入到事務中
  • 執行事務
    exec
  • 作用
    設定事務的結束位置,同時執行事務。與multi成對出現, 成對使用

操作演示
在這裏插入圖片描述

事務的工作流程

在這裏插入圖片描述

  • 服務器接收指令,先判斷是否是事務狀態
    • 如果不是,那麼去識別命令
      • 如果是普通指令,那麼直接執行指令,返回執行結果
      • 如果是MULTI指令,創建隊列,返回OK結果
    • 如果是事務狀態,那麼開始識別命令
      • 如果是EXEC指令,執行事務,返回執行結果
      • 如果是普通指令,把命令加入隊列,返回QUEUE結果
      • 如果是DISCARD指令,銷燬隊列,返回OK結果

我之前好像沒有介紹過discard指令,現在補上:

手動進行事務回滾

實現功能

  • 記錄操作過程中被影響的數據之前的狀態
    • 單數據: string
    • 多數據:hash. list. set. zset
  • 設置指令恢復所有的被修改的項
    • 單數據:直接set (注意周邊屬性,例如時效)
    • 多數據:修改對應值或整體克隆複製、

執行指令discard

事務的注意事項

問題一:定義事務的過程中, 命令格式輸入錯誤怎麼辦?

  • 語法錯誤
    指命令書寫格式有誤
  • 處理結果
    如果定義的事務中所包含的命令存在語法錯誤,整體事務中所有命令均不會執行。包括那些語法正確的命令。

問題二:定義事務的過程中, 命令執行出現錯誤怎麼辦?

  • 運行錯誤
    指命令格式正確,但是無法正確的執行。例如對list進行incr操作
  • 處理結果
    能夠正確運行的命令會執行,運行錯誤的命令不會被執行
    注意:已經執行完畢的命令對應的數據不會自動回滾,需要程序員自己在代碼中實現回滾。

基於特定條件的事務執行

業務場景一
天貓雙11熱賣過程中,對已經售罄的貨物追加補貨,4個業務員都有權限進行補貨。補貨的操作可能是一系列的操作,牽扯到多個連續操作,如何保障不會重複操作?

業務分析

  • 多個客戶端有可能同時操作同一組數據,並且該數據一旦被操作修改後, 將不適用於繼續操作
  • 在操作之前鎖定要操作的數據,一旦發生變化,終止當前操作。

業務場景二
依賴分佈式鎖的機制,某個用戶操作時對應客戶端宕機,且此時已經獲取到鎖。如何解決?

業務分析

  • 由於鎖操作由用戶控制加鎖解鎖,必定會存在加鎖後未解鎖的風險需要解鎖操作不能僅依賴用戶控制,系統級別要給出對應的保底處理方案

業務場景三
天貓雙11熱賣過程中,對已經售罄的貨物追加補貨,且補貨完成。客戶購買熱情高漲,3秒內將所有商品購買完畢。本次補貨已經將庫存全部清空,如何避免最後一件商品不被多人同時購買? 【超賣問題】

業務分析

  • 使用watch監控一個key有沒有改變已經不能解決問題, 此處要監控的是具體數據
  • 雖然redis是單線程的,但是多個客戶端對同一數據同時進行操作時,如何避免不被同時修改?
基於特定條件的事務執行——鎖
  • 對key添加監視鎖,在執行exec前如果key發生了變化,終止事務執行
    watch key1 [key2...]
  • 取消對所有key的監視
    unwatch

操作演示
在這裏插入圖片描述
如果說發生了業務場景1的情況,多個人修改同一個值,會發生什麼情況?
在這裏插入圖片描述
加了一個watch之後再開啓事務,當有別的客戶端再次修改這個值的時候,本次的事務就失效了,也就相當於一個店員已經上貨了,另外一個和他同時的店員就不用再上貨了。這樣就解決了重複操作的問題。

那麼你會不會有疑問,在只有multi的情況下是不是也會發生這種情況,非要加watch嗎??
那麼來看一下只有multi的情況,執行的結果如何:
在這裏插入圖片描述
使用注意:可以在watch之後加上multi,但是不能在multi後面加上watch,那是執行不了的。

基於特定條件的事務執行一分佈式鎖
  • 使用setnx設置一個公共鎖
    setnx lock-key value
    利用setnx命令的返回值特徵,有值則返回設置失敗,無值則返回設置成功
  • 對於返回設置成功的,擁有控制權,進行下一步的具體業務操作
  • 對於返回設置失敗的,不具有控制權,排隊或等待,操作完畢通過del操作釋放鎖

操作演示
在這裏插入圖片描述
業務二當中提到的加了鎖但是宕機的問題,這樣的話,這個鎖會一直存在,對其他用戶就一直會等待獲取到鎖,進程就會整個的阻塞在那裏。那麼有沒有一種方式可以讓這個鎖在多久之後自動失效,這樣的話,不至於整個進程都阻塞在那裏。

基於特定條件的事務執行一分佈式鎖改良
  • 使用expire爲鎖key添加時間限定,到時不釋放,放棄鎖
    expire lock-key second
    pexpire lock-key milliseconds

由於操作通常都是微秒或毫秒級,因此該鎖定時間不宜設置過大。具體時間需要業務測試後確認。

  • 例如:持有鎖的操作最長執行時間127ms,最短執行時間7ms。
  • 測試百萬次最長執行時間對應命令的最大耗時,測試百萬次網絡延遲平均耗時
  • 鎖時間設定推薦:最大耗時120%+平均網絡延遲110%
  • 如果業務最大耗時<<網絡平均延遲,通常爲2個數量級,取其中單個耗時較長即可

給鎖設置一個時間限制,到了時間自動解開,這樣的話進程就不會長時間阻塞住了。

演示樣例
在這裏插入圖片描述
事務的話我就學到了這麼多,若有不足,希望大家幫忙補充。能看到這裏的,真的是萬分感謝,阿里嘎多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章