MySQL學習記錄
1. 基本介紹
存在的問題:
Redis執行指令過程中,多條連續執行的指令被幹擾,打斷,插隊 ,例如, 當客戶端一 set一個name為張三時,在取的一刻, 另一個客戶端set另外一個值,將打亂原先的設定
所以就需要事務的控制
redis事務就是一個命令執行的佇列,將一系列預定義命令包裝成一個整體(一個佇列)。當執行時,一次性 按照新增順序依次執行,中間不會被打斷或者干擾。
2. 基本操作
Redis 通過 MULTI
、EXEC
、DISCARD
、WATCH
、UNWATCH
來實現事務功能
-
multi
開始事務,設定事務的開啟位置,此指令執行後,後續的所有指令均加入到事務中
-
exec
執行事務 ,設定事務的結束位置,同時執行事務。與multi成對出現,成對使用
加入事務的命令暫時進入到任務佇列中,並沒有立即執行,只有執行exec命令才開始執行
-
discard
取消事務 ,終止當前事務的定義,發生在multi之後,exec之前
-
watch
監視這個某個或者某些 key 在該事務期間是否被修改過,如果有至少一個 key 被修改了,那麼在 EXEC 命令執行時會拒絕執行,(java cas樂觀鎖)
-
unwatch
取消監控
事務的工作流程
示意圖:
- 當執行一個命令時,若此時不是事務狀態,將普通的執行此指令
- 若識別到執行了mutil 指令,將建立一個佇列,並返回"OK"
- 後面如果繼續會執行普通的指令,但是此時在事務狀態,將會把這些指令放到佇列中
- 如執行到exec指令,則會依次執行佇列中的命令,並關閉事務狀態
注意事項
若在事務的過程中,命令發生錯誤怎麼辦?
-
語法錯誤 , 指命令書寫格式有誤 .那麼整體事務中所有命令均不會執行。包括那些語法正確的命令。
-
執行錯誤 指命令格式正確,但是無法正確的執行。那麼能夠正確執行的命令會執行,執行錯誤的命令不會被執行 (需要手動回滾即手動set回原來的值,意味著Redis的事務不支援原子性)
3. Redis 事務的 ACID 原則
原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、永續性(Durability) 是關係型資料庫中事務的最基本要求, 那麼Redis的事務又支援幾種呢
結論:Redis 的事務滿足一致性和隔離性,但是原子性和永續性就不支援了。下面詳細分析。
原子性:
定義:
- 整個事務中的所有操作,要麼全部完成,要麼全部不完成,不可能停滯在中間某個環節。
- 事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
但是在上面的介紹中, Redis在執行事務過程中,若是執行命令錯誤(非語法錯誤),將繼續執行其他命令,很明顯不符合原子性定義
永續性:
定義:
- 在事務完成以後,該事務對資料庫所作的更改便持久的儲存在資料庫之中,並不會被回滾
Redis採用不同的持久化規則,結果不同,若使用RDB模式和always策略除外的AOF 模式,Redis將會有丟失資料的風險,不具有永續性,
若採用AOF的 always策略, 則命令將同步到硬碟中,具有永續性
隔離性 :
定義:
- 隔離狀態執行事務,使它們好像是系統在給定時間內執行的唯一操作
通俗點將就是多個事務併發執行互不干擾。由於 Redis 使用的單執行緒方式來執行事務的且可以保證在整個事務執行期間不會中斷去執行其他命令,所以 Redis 的事務總是可以保證隔離性的。
一致性 :
定義:
- 一個事務可以封裝狀態改變(除非它是一個只讀的)。事務必須始終保持系統處於一致的狀態,不管在任何給定的時間併發事務有多少。 (即執行結果滿足期望,)
首先,如果一個事務的指令結果全部執行成功,則資料庫的狀態滿足一致性
如果一個事務的指令有錯誤,則資料庫的狀態也滿足一致性
最後,如果事務執行到某條指令時,程序被kill掉了,那麼要分下面幾種情況討論:
-
如果當前redis採用的是記憶體模式,那麼重啟之後redis資料庫是空的,那麼滿足一致性條件
-
如果當前採用RDB模式儲存的 ,在執行事務時,Redis 不會中斷事務去執行儲存 RDB 的工作 ,所以在重啟後,會恢復到事務開啟前的狀態
-
如果當前採用的是AOF儲存的,那麼可能事務的內容還未寫入到AOF檔案,那麼此時肯定是滿足一致性的,但是事務的內容有部分寫入到AOF檔案中,那麼這部分的資料是不確定的了, 不滿足一致性
那麼需要用工具把AOF中事務執行部分成功的指令移除,這時,移除之後的AOF檔案也是滿足一致性的
所以,總體redis事務滿足一致性約束
4. 使用Redis命令實現分散式鎖
-
使用 setnx 設定一個公共鎖
setnx lock-key value
利用setnx命令的返回值特徵,有值則返回設定失敗,無值則返回設定成功
- 對於返回設定成功的,擁有控制權,進行下一步的具體業務操作
- 對於返回設定失敗的,不具有控制權,排隊或等待
操作完畢通過del操作釋放鎖
業務場景:
解決多個微服務同時讀取同一個庫存,並進行修改,解決同步問題
但是此時又有問題,由於鎖操作由使用者控制加鎖解鎖,必定會存在加鎖後未解鎖的風險 .
例如某個使用者操作時對應客戶端宕機,且此時已經獲取到鎖。如何解決?
解決方案:
-
使用 expire 為鎖key新增時間限定,到時不釋放,放棄鎖
expire lock-key second pexpire lock-key milliseconds
由於操作通常都是微秒或毫秒級,因此該鎖定時間不宜設定過大。具體時間需要業務測試後確認。
- 例如:持有鎖的操作最長執行時間127ms,最短執行時間7ms。
- 測試百萬次最長執行時間對應命令的最大耗時,測試百萬次網路延遲平均耗時
- 鎖時間設定推薦:最大耗時120%+平均網路延遲110%
- 如果業務最大耗時<<網路平均延遲,通常為2個數量級,取其中單個耗時較長即可
相關框架: redssion