zookeeper分布式鎖原理及實作
前言
寫zookeeper分布式鎖之前,先說下CAP理論吧
C 一緻性、A 可用性、P分區容錯性。三者不能同時存在,由于P是必要因素,是以分為CP和AP兩種模型
前段時間寫了redis怎樣實作分布式鎖,redis實作分布式鎖效率是比較高的,但是什麼事情都是相對性的,因為redis支援了 AP那麼就放棄了CP。
當我們對一緻性要求特别高的時候,就需要考慮一種别的分布式鎖技術了,
zookeeper因為它叢集的選舉和同步機制,使得它是支援CP,而放棄了AP,接下來來看看zookeeper是怎麼實作分布式鎖的吧。
zookeeper的資料結構

類似liux系統的檔案目錄結構,根節點是/ 下邊有很多的子節點 子節點下邊也可以有自己的子節點,這個節點叫做znode,當然除了節點以外每個節點都可以存儲資料,今天咱們就來說下節點znode
節點類型
1,持久化目錄節點–用戶端與zookeeper斷開連接配接後,該節點依舊存在
2,持久化順序目錄節點–用戶端與zookeeper斷開連接配接後,該節點依舊存在,隻是Zookeeper給該節點名稱進行順序編号
3,臨時節點–用戶端與zookeeper斷開連接配接後,節點被删除
4,臨時順序節點–用戶端與zookeeper斷開連接配接後,隻是Zookeeper給該節點名稱進行順序編号
5,容器節點–3.5.3新增的特性,沒有子節點的容器節點會被清除掉。
6,TTL節點–3.5.3新增的特性,位節點設定了失效時間。具體失效時間卻決于背景檢測失效線程的輪詢頻率
分布式鎖的實作
分布式鎖的實作就是根據臨時順序節點這個點來實作的
具體步驟如下
1、每個線程都會在zookeeper中的一個持久節點生成一個臨時順序節點
2、然後判斷自己的節點是不是目前順序最靠前的
3、如果是那麼擷取到鎖,如果不是那麼監視它上一個臨時順序節點
4、擷取到鎖的線程執行完邏輯後,删除目前節點
Curator是Netflix公司開源的一個Zookeeper用戶端,Curator架構在zookeeper原生API接口上進行了包裝,大大降低了我們操作zookeeper的複雜度,下面來看下Curator是怎麼實作的分布式鎖
依賴
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
代碼如下
//這段代碼放在啟動類用于初始化Curator用戶端
public CuratorFramework getZkClient() {
String zkServerAddress = "127.0.0.1:2181";
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);
CuratorFramework zkClient = CuratorFrameworkFactory.builder()
.connectString(zkServerAddress)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
.build();
zkClient.start();
return zkClient;
}
@Service
public class testService {
@Resource
private CuratorFramework zkClient;
//操作庫存業務
public String stock() {
String lockPath = "/lock1";
//在根節點上建立lock1節點
InterProcessMutex lock = new InterProcessMutex(zkClient, lockPath);
try {
//加鎖 這塊參數2000代表時間,後邊機關,代表線程等待時間,如果傳-1代表永久等待
boolean flag=lock.acquire(2000, TimeUnit.SECONDS);
if (flag) {
//操作庫存業務
return "";
} else {
return "業務繁忙請稍後重試";
}
} catch (Exception e) {
e.printStackTrace();
return "";
} finally {
//解鎖
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果對redis分布式鎖感興趣的請點選redis分布式鎖實作
歡迎大家一起交流一起學習,風裡雨裡我在這裡等你