分布式鎖使用場景
- 解決業務層冪等性,防止雙次點擊(譬如更新接口)
- 解決 MQ 消費端多端接受同一消息時保證只有一端處理消息
- 使用 schedule 執行定時任務時,多實例部署時只有一台實例執行任務
Redis
特點
- 單線程串行處理
- 獲取鎖性能特別好
- setnx 不存在則設置成功否則失敗
- 沒有心跳機制,需要設置失效時間
- CAP 中的 AP 模型,因為用的是 gossip 協議,所以不是強一致性
多個業務獲取鎖場景
鎖失效時間設置問題
鎖定了10s后過期,但業務執行了30s(可能碰到fullgc,死循環等場景)。
主從切換問題
業務1從主獲取鎖,此時主掛機了,從晉升為主,恰好此時從未同步這個鎖的值 。
Zookeeper
特點
- 有序節點,按排序命名節點
- 臨時節點,客戶端斷連后自動消失
- 事件監聽,節點下發生更新時會有事件通知
- ZAB 協議,強一致,屬於 CP 模型
- zk 集群變大后,性能持續下降
多個業務獲取鎖場景
客戶端掛掉或假死
客戶端斷連會把臨時節點刪除,鎖也就隨着釋放。另一個業務即可獲取鎖。
但其實客戶端沒掛,只是心跳維持間斷了。原因有好多,譬如fullgc,網絡問題(redis碰到網絡問題最多獲取鎖失敗)等。
Etcd
特點
- 如果存在 Key 的話就不能寫入,也就意味着不能獲取到鎖,如果集群中,可以寫入 Key,就意味着獲取得到鎖。
- Raft 保證了集群的一致性,強一致性,並且數據是可以進行持久化
- 沒有心跳機制,需要設置失效時間
多個業務獲取鎖場景
鎖失效時間設置問題
鎖定了10s后過期,但業務執行了30s(可能碰到fullgc,死循環等場景)。
使用失效時間的鎖時間續租問題
在獲取到鎖的業務線程,可以開啟一個子線程去維護和輪訓這把鎖的有效時間,並定時的對這把鎖進行續租。
假設業務線程獲取到一把鎖,鎖的 Expire 時間為 10s,業務線程會開啟一個子線程通過輪訓的方式每 2 秒鍾去把這把鎖進行續租,每次都將鎖的 Expire 還原到 10s。
存在的問題
- 業務死循環
- 業務 fullgc
這些問題都會導致續租線程無法執行,從而導致鎖提前失效。