天天看點

zookeeper分布式鎖原理及實作

zookeeper分布式鎖原理及實作

前言

寫zookeeper分布式鎖之前,先說下CAP理論吧

C 一緻性、A 可用性、P分區容錯性。三者不能同時存在,由于P是必要因素,是以分為CP和AP兩種模型

前段時間寫了redis怎樣實作分布式鎖,redis實作分布式鎖效率是比較高的,但是什麼事情都是相對性的,因為redis支援了 AP那麼就放棄了CP。

當我們對一緻性要求特别高的時候,就需要考慮一種别的分布式鎖技術了,

zookeeper因為它叢集的選舉和同步機制,使得它是支援CP,而放棄了AP,接下來來看看zookeeper是怎麼實作分布式鎖的吧。

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分布式鎖實作

歡迎大家一起交流一起學習,風裡雨裡我在這裡等你

繼續閱讀