可基於以下三種原則來進行鎖設計
獨享,無死鎖,容錯(大部分Redis節點都活着,客戶端就可以獲取和釋放鎖.)
1. Redis分佈式鎖
簡單版: 1. setNx key value 原子操作,只有當key不存在時才能設置成功(獨享)
2. expire key aliveTime 如果獲得鎖的客戶端宕機,則鎖會在aliveTime後釋放(無死鎖)
簡單版存在的問題
1. setNx和expire合在一起時,非原子性操作
2. 過期時間到了,但結點1任務未執行完畢還沒主動釋放鎖(時間到了,已被被動刪除),結點2會拿到鎖。
矛盾所在處:兩個結點都擁有鎖,且都以爲只有自己擁有鎖。
2.1)結點1的JVM進程執行完畢,要釋放鎖,執行del命令,但此時刪除的可能是結點2的鎖
2.2)此時確實有兩個結點拿到鎖了(不符合獨佔原則)
3. 如果在redis主從複製異步模式下,當結點1在master上剛設置了鎖,但還沒同步到slaver就宕機了。此時結點2在新master上設置了鎖,這就導致有多個結點擁有了鎖(不符合獨佔原則)
進化版Redis分佈式鎖
1.SET resource_name my_random_value NX PX 30000
2. 使用Lua腳本,驗證和刪除過程就是原子操作
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
3.獲得鎖的線程開啓一個守護線程,給快要過期的鎖續航,當結點1斷電或宕機,由於守護線程和獲得鎖的線程在一個進程裏,所以守護線程也會停止,由於沒有守護線程給它續航,到期後會自動釋放鎖
2. Zookeeper分佈式鎖
Zookeeper中的四種類型的結點
1. 持久化目錄結點:創建結點的客戶端與zk斷開連接後,結點仍存在
2. 持久化順序編號目錄結點:創建節點時zk根據創建的時間順序給該節點名稱進行編號
3. 臨時目錄結點:創建結點的客戶端與zk斷開連接後,結點就被刪除了
4. 臨時順序編號目錄結點
結點也就是ZNode裏包含了什麼?
1.data: Znode存儲的數據信息
2.acl:Znode的訪問權限
3.stat:Znode的各種元數據,事務id,版本號,時間戳等
4.child:當前結點的子節點引用
zookeeper分佈式鎖實現原理
每一個要獲得鎖的客戶端都要經歷如下過程
1. 創建臨時順序結點
2. 獲得當前根節點下的子節點,由小到大進行排序
3. 判斷自己是否是第一個結點,即最小的
3.1)是,則成功獲得鎖
3.2)不是,則watch前一個結點(排好序的),如果watch到前一個結點發生刪除事件,則重複第三步驟
4. 釋放鎖
4.1)正常執行結束,顯示釋放鎖,即刪除結點
4.2)拿到鎖的客戶端在執行任務中宕機了,那也沒關係,因爲隨着該客戶端與zk斷開連接,所創建的結點會被自動刪除