前言
一般工作中常用的分散式鎖,就是基於 Redis 和 ZooKeeper,前面已經介紹完了 Redisson 鎖相關的原始碼,下面一起看看基於 ZooKeeper 的鎖。也就是 Curator 這個框架。
Curator 的鎖也分為很多種,本文分析共享可重入鎖。
考慮到如果文章篇幅較長,不太適合閱讀,所以對文章做了適當的拆分。
環境配置
本機三個節點
版本:3.7.0
系統:macOS
安裝方式:brew install zookeeper
Curator Maven 依賴版本:5.1.0
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
加鎖示例
詳細資訊可參考官方文件。
加鎖前
在加鎖之前,ZooKeeper 僅有一個節點 /zookeeper
。
加鎖中
在 /locks/lock_01
路徑上加鎖。
加鎖之後:
- 建立了一個
/locks/lock_01
的持久節點,節點下有一個子節點_c_cc4fc045-5a1e-4378-b3c7-8a8d3fb9a37c-lock-0000000000
- 節點
/locks/lock_01/_c_cc4fc045-5a1e-4378-b3c7-8a8d3fb9a37c-lock-0000000000
是臨時節點 - 節點
/locks/lock_01/_c_cc4fc045-5a1e-4378-b3c7-8a8d3fb9a37c-lock-0000000000
的資料是機器 IP 地址
加鎖原始碼
PS:下面程式碼截圖中的程式碼風格就是 Curator 原始碼的程式碼風格。
入口
InterProcessMutex#internalLock
開始先從 threadData 中獲取當前執行緒,這裡肯定是沒有的,所以進入 attemptLock 方法。
本方法中還包含了鎖重入的邏輯,後面也會介紹。
加鎖
LockInternals#attemptLock
核心部分就是這兩行:
- createsTheLock 建立臨時順序節點
- internalLockLoop 判斷是否建立成功
建立臨時順序節點
StandardLockInternalsDriver#createsTheLock
可以看出節點的 mode 是 CreateMode.EPHEMERAL_SEQUENTIAL
,表示這是一個臨時順序節點!
進入 CreateBuilderImpl#forPath(java.lang.String, byte[])
client.getDefaultData()
就是本機 IP 地址。
這個 adjustPath 方法看名字就是在調整路徑之類的。會生成一個 UUID 拼接到 /locks/lock_01
中,變成 /locks/lock_01/_c_UUID-lock-
。
因為建立的是臨時順序節點,所以會自動在後面新增順序,最終變為 /locks/lock_01/_c_UUID-lock-0000000000
。
具體建立節點是在 CreateBuilderImpl#pathInForeground
中。
- 建立臨時節點,如果路徑存在,會建立成功,如果路徑不存在會建立失敗;
- 建立失敗後,先建立路徑,再建立節點。
總結
本篇文章主要介紹了基於 ZooKeeper 的分散式鎖框架 Curator 的使用,以及加鎖流程,原始碼分析。
下面對內容做下總結:
重點需要關注的是:
- 基於 ZooKeeper 的分散式鎖,是使用的臨時順序節點,父節點是持久節點;
- 建立臨時節點時,父節點不存在,會先建立父節點(路徑);
- 鎖的組成結構為:對
/locks/lock_01
加鎖,實際鎖住的是/locks/lock_01/_c_UUID-lock-序號
,舉例為/locks/lock_01/_c_cc4fc045-5a1e-4378-b3c7-8a8d3fb9a37c-lock-0000000000