Java - 深度學習 - 分佈式鎖

前言

整理了一下自己日常中使用到的一些分佈式鎖功能,特別說明,因爲還在整理知識點,有些東西我直接使用之前寫的PythonDemo一筆蓋過,望體諒,最近有點忙。

分佈式鎖

分佈式鎖是通過互訴等手段,來實現分佈式系統之間同步訪問共享資源,以保證數據的一致性。

一般實現分佈式鎖都有哪種方式

方法 優勢 優劣對比 備註
Redis 性能高 可靠性低,爭議多 不推薦,但業務不需要太嚴謹時可以考慮
ZooKeeper 性能一般 可靠性高 推薦,但性能未必出色

鎖衝突情況

  • Redis:如果沒有獲取到這把鎖,只能自己每個一秒嘗試一下,看能否拿到這把鎖,開銷大

  • ZooKeeper:如果沒有獲取到這把鎖,對這個鎖註冊監聽器,被釋放時通知節點掛掉的情況,開銷小

異常情況

  • Redis非redis-cluster模式下,如單節點,哨兵Sentinel,節點掛掉後,需要通過過期時間自動釋放
  • zk的話,因爲創建的是臨時znode,只要客戶端掛了,znode就沒了,此時就自動釋放鎖

Redis分佈鎖

官方叫做RedLock算法,是redis官方支持的分佈式鎖算法。

Redis 2.8 版本中作者加入了 set 指令的擴展參數,使得 setnx 和 expire 指令可以一起執行

三個重要的考量點

  • 互斥(只能有一個客戶端獲取鎖)
  • 不能死鎖
  • 容錯(大部分redis節點或者這個鎖就可以加可以釋放)

爲什麼key要用隨機值?

因爲如果某個客戶端獲取到了鎖,但是阻塞了很長時間才執行完,此時可能已經自動釋放鎖了,此時可能別的客戶端已經獲取到了這個鎖,要是你這個時候直接刪除key的話會有問題,所以得用隨機值加上面的lua腳本來釋放鎖。

最普通的實現方式,如果就是在redis裏創建一個key算加鎖

參數 說明
nx 只有key不存在的時候才能設置成功
px 多少秒後自動釋放
set mykey 隨機值 nx px 5

釋放鎖就是刪除key,但是一般可以用lua腳本刪除,判斷value一樣才刪除

if redis.call("get",KEYS[1]) == ARGV[1] then
		return redis.call("del",KEYS[1])
else
    return 0
end

風險

  1. 如果是普通的redis單實例,那就是單點故障。
  2. 比如在 Sentinel 集羣中,主節點掛掉時,從節點會取而代之,客戶端上卻並沒有明顯感知。從節點還沒來得及同步過來,主節點就掛掉了,這樣就會導致系統中同樣一把鎖被兩個客戶端同時持有,不安全性由此產生。

在這裏插入圖片描述

使用RedLock算法

針對以上問題,可以使用redis cluster,假設有5個redis master實例。然後執行如下步驟獲取一把鎖:

1)獲取當前時間戳,單位是毫秒

2)跟上面類似,輪流嘗試在每個master節點上創建鎖,過期時間較短,一般就幾十毫秒

3)嘗試在大多數節點上建立一個鎖,比如5個節點就要求是3個節點(n / 2 +1)

4)客戶端計算建立好鎖的時間,如果建立鎖的時間小於超時時間,就算建立成功了

5)要是鎖建立失敗了,那麼就依次刪除這個鎖

6)只要別人建立了一把分佈式鎖,你就得不斷輪詢去嘗試獲取鎖

討論

其實在正常工作中,我們不太推薦這個鎖,而且這個官方發佈的RedLock算法有很多爭議,國外不乏大牛質疑這個做法,我找到了兩篇文章,我覺得寫的很好

部署

ZooKeeper實現分佈式鎖

**鎖定義:**Zookeeper通過創建臨時數據節點來表示一個鎖,並且是順序節點

**獲取鎖:**成功創建數據節點的客戶端即爲獲取鎖。未獲取鎖的客戶端通過監聽該節點變更情況,以便重新獲取鎖

釋放鎖:

  • 當前客戶端發生宕機的情況下,臨時節點自動刪除
  • 正常業務邏輯處理完畢後,客戶端自動刪除自己創建的臨時節點

在這裏插入圖片描述

簡單示例

以下代碼只是簡單實現,基於zookeeper的臨時順序節點去實現的,不建議這個,下面有高級用法

源碼地址

Curator - 實現分佈式鎖

它的實現也是通過創建臨時的順序節點機制

類型 說明
InterProcessMutex 互斥鎖

zk客戶端登錄,創建節點

create /orderNo 1000

代碼實現,輕鬆實現分佈式鎖

// 獲得鎖
interProcessMutex.acquire();
// 生成訂單
int order = generateOrder(orderNoPath, curatorFramework);
System.out.println("當前訂單號:" + order);
// 釋放
interProcessMutex.release();

完整代碼
Java Zookeeper - Curator的使用

Java Zookeeper - 分佈式鎖

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