參考分布式鎖用 Redis 還是 Zookeeper?
分布式鎖
當一個單點機器上有多個行程或者多個執行緒需要互斥訪問一個共享資源時,就需要用到鎖,這種情況下,只需要用各個編程語言庫的鎖即可,比如C++的pthread_mutex_lock,Java的synchronized和ReentrantLock等等來加鎖,
但是本機的鎖只能被本機的行程訪問,而現實中的許多業務的訪問量一般都比較大,單點機器無法支撐,必須多點部署,此時如果不同機器上的行程/執行緒仍然需要互斥訪問一個全域的共享資源的話,就必須使用分布式鎖,即為整個系統提供一個全域、唯一的獲取鎖的服務,然后每臺機器節點在需要加鎖時,都向這個服務請求一把鎖,這樣不同的機器節點拿到的就可以認為是同一把鎖,
目前分布式鎖可以用redis、zookeeper甚至資料庫服務來實作,
Redis實作分布式鎖
一種非常常見的方案就是用redis實作分布式鎖,思路非常簡單:
- 需要加鎖時,client在redis中設定一個key來表示加了鎖,其中設定的value需要具備唯一性,
- 完成業務邏輯后,client洗掉這個key來表示釋放這個鎖,注意洗掉key時需要校驗client的value跟加鎖時設定的value是否相同,防止其他client誤刪這個key,
輪詢方式獲取鎖
如果client想要獲取鎖時,發現鎖已經被占用了,就會周期性地重復訪問redis,直到鎖被釋放或者過時了,可見redis分布式鎖這種輪詢獲取鎖的方式會有較大的cpu開銷,

RedLock演算法
用redis實作分布式鎖還需要考慮redis的部署方式
- 單點部署:只要redis故障,立刻就無法提供分布式鎖的服務了,所有請求分布式鎖的機器都會報錯影響業務,
- 哨兵模式:主從模式,主節點故障宕機時需要進行主從切換,此時也會有鎖丟失的問題,
- 集群模式(cluster):有多個主節點,他們地位平等,存盤的資料不重疊,(每個主節點對應有一些從節點,來保證主節點掛掉也能進行切換,從而正常提供服務)
RedLock演算法基于cluster模式,有多個master節點,比如5個master節點的情況下,演算法步驟為:
- 并發地在每個master節點上創建key(過期時間設定較短,一般就幾十毫秒)
- 如果有超過一半的節點上創建key成功,比如5個節點就要求是3個節點(n / 2 +1),而且建立鎖的時間小于超時時間,就算成功創建鎖了
- 如果鎖建立失敗了,那么就依次洗掉這個鎖
- 只要別人建立了一把分布式鎖,你就得不斷輪詢去嘗試獲取鎖

但RedLock演算法也不一定能保證安全性,假設5個節點是A, B, C, D, E,客戶端1在A, B, C上面拿到鎖,D, E沒有拿到鎖,客戶端1拿鎖成功, 此時,C掛了重啟,C上面鎖的資料丟失(假設機器斷電,資料還沒來得及刷盤),客戶端2去取鎖,從C, D, E 3個節點拿到鎖,A, B沒有拿到(還被客戶端1持有),客戶端2也超過多數派,也會拿到鎖,
zookeeper實作分布式鎖
zookeeper的基礎知識參考我的另一篇文章:zookeeper概念、原理與應用場景,其中,zookeeper實作分布式鎖主要利用了znode的這三種特性:
- 有序節點:在zookeeper的目錄下創建子節點時可以指定有序,那么生成的子節點就會自動添加整數序號,如果是第一個創建的子節點,那么生成的子節點為
/lock/node-0000000000,下一個節點則為/lock/node-0000000001,依次類推, - 臨時節點:client可以選擇創建臨時節點,那么會話結束時zookeeper就會自動洗掉該臨時節點,
- 事件監聽:client讀取資料時可以對節點設定事件監聽,發生指定的事件時zookeeper會通知client,總共有四種事件:節點創建、節點洗掉、節點資料修改、子節點變更
借助這三種特性,分布式鎖的實作方案為:
- 使用zookeeper的臨時節點和有序節點,每個client獲取鎖就是在zk創建一個臨時有序的節點,比如在/lock/目錄下,
- 創建節點成功后,獲取/lock目錄下的所有臨時節點,再判斷當前client創建的節點是否是所有的節點中序號最小的節點
- 如果當前client創建的節點是所有節點序號最小的節點,則認為獲取鎖成功,
- 如果當前client創建的節點不是所有節點序號最小的節點,則對節點序號的前一個節點添加一個節點洗掉的事件監聽,事件發生并且通知client后,再判斷自己的節點是否最小節點,是則獲取鎖成功,

對比總結
| - | 優點 | 缺點 |
|---|---|---|
| redis分布式鎖 | 速度快,性能強,可以支撐高并發的獲取分布式鎖的場景 | 1、redis不是強一致性的,即使用了redlock演算法也不能保證沒有鎖丟失(但是一般也不會出現這些極端情況), 2、輪詢訪問redis獲取鎖的方式開銷比較大, |
| zookeeper分布式鎖 | 1、zookeeper不僅為分布式系統提供協同,而且zookeeper服務本身就是一個分布式系統,具有強一致性,值得信任, 2、鎖被占用時只需設定監聽器即可,不用一直輪詢,開銷較小, | zk只有一個主節點負責寫請求,高并發場景下有非常多的創建、洗掉操作都需要主節點處理,壓力會很大 |
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/397594.html
標籤:其他
