最近中文字幕高清中文字幕无,亚洲欧美高清一区二区三区,一本色道无码道dvd在线观看 ,一个人看的www免费高清中文字幕

首頁 慕課教程 Zookeeper 入門教程 Zookeeper 入門教程 ZooKeeper 實(shí)現(xiàn)分布式鎖

ZooKeeper 實(shí)現(xiàn)分布式鎖

1. 前言

在我們的應(yīng)用中,經(jīng)常會碰見多個請求去訪問同一個資源的情況。如果請求 A 拿到這個資源數(shù)據(jù),想要對它進(jìn)行修改,但是還沒有進(jìn)行事務(wù)提交,此時請求 B 訪問這個資源就會拿到修改前的數(shù)據(jù),很顯然請求 B 拿到的是歷史數(shù)據(jù),是不正確的。

在單個服務(wù)器的應(yīng)用中,我們可以使用系統(tǒng)的線程來對這個資源進(jìn)行加鎖。那么在分布式環(huán)境中我們有什么方案來解決這個問題呢?答案就是使用分布式鎖。那么什么是分布式鎖?分布式鎖又是如何實(shí)現(xiàn)的呢?本節(jié)我們就來講解如何使用 Zookeeper 實(shí)現(xiàn)分布式鎖,以及它的實(shí)現(xiàn)原理。

2. 分布式鎖

在講解 Zookeeper 實(shí)現(xiàn)的分布式鎖之前,我們先來了解什么是分布式鎖,分布式鎖的實(shí)現(xiàn)技術(shù),以及分布式鎖常用的類型。

2.1 分布式鎖的特點(diǎn)

顧名思義,分布式鎖就是實(shí)現(xiàn)在分布式網(wǎng)絡(luò)環(huán)境中的鎖。也就是說,在鎖的基礎(chǔ)上加上分布式的特性,我們來分析一下分布式鎖實(shí)現(xiàn)的必要條件:

  1. 在分布式環(huán)境中,多個進(jìn)程對資源的訪問必須具有順序性;
  2. 獲取鎖和釋放鎖的過程需要高可用和高性能;
  3. 具有鎖失效的機(jī)制,避免死鎖;
  4. 非阻塞的鎖,沒有獲取到鎖直接返回獲取鎖失敗。

介紹了分布式鎖的特點(diǎn),那么有哪些技術(shù)能夠?qū)崿F(xiàn)分布式鎖呢?

2.2 分布式鎖的實(shí)現(xiàn)技術(shù)

  1. Memcached: 使用 add 命令來添加 key,key 添加成功說明當(dāng)前無人使用此 key,也就是說無人使用此資源,相當(dāng)于獲取鎖。再次使用 add 命令來添加相同的 key 時,此時 key 已存在就會添加失敗,說明有人已經(jīng)使用了這個 key,也就是說此資源被人占用,相當(dāng)于獲取鎖失??;
  2. Redis: 使用 setnx 命令來添加 key,key 添加成功說明當(dāng)前無人使用此 key,也就是說無人使用此資源,相當(dāng)于獲取鎖。再次使用 setnx 命令來添加相同的 key 時,此時 key 已存在就會添加失敗,說明有人已經(jīng)使用了這個 key,也就是說此資源被人占用,相當(dāng)于獲取鎖失??;
  3. Chubby: Google 使用 Paxos 一致性算法實(shí)現(xiàn)的粗粒度分布式鎖;
  4. Zookeeper: 使用 Zookeeper 臨時順序節(jié)點(diǎn)的特性,實(shí)現(xiàn)分布式鎖和鎖的等待隊列。

介紹了分布式鎖的實(shí)現(xiàn)技術(shù),接下來我們來介紹分布式鎖常用的類型。

2.3 分布式鎖常用的類型

分布式鎖常用的類型有兩種:一種是排他鎖,一種是共享鎖。接下來我們分別介紹這兩鎖的特點(diǎn)。

  • 排他鎖

排他鎖也叫獨(dú)占鎖,顧名思義,也就是對資源進(jìn)行獨(dú)占。排他鎖只允許獲取了該鎖的線程,對具有排他鎖的資源進(jìn)行訪問,無論是寫操作還是讀操作,直到該線程主動釋放掉排他鎖。

  • 共享鎖

共享鎖也就是把資源進(jìn)行共享,當(dāng)然共享的只有讀操作。共享鎖只對寫操作進(jìn)行加鎖,其它線程的讀操作不做加鎖操作,這樣的共享機(jī)制提高了對資源訪問的性能。

介紹完分布式鎖的常用類型,接下來我們開始學(xué)習(xí)如何使用 Zookeeper 實(shí)現(xiàn)分布式鎖。

3. Zookeeper 實(shí)現(xiàn)分布式鎖

上面我們提到,Zookeeper 是根據(jù)它的臨時順序節(jié)點(diǎn)來實(shí)現(xiàn)的分布式鎖,這里我們來回顧一下臨時順序節(jié)點(diǎn)的特性。

3.1 臨時順序節(jié)點(diǎn)

臨時順序節(jié)點(diǎn):

  • 節(jié)點(diǎn)具有臨時性,創(chuàng)建該節(jié)點(diǎn)的 Zookeeper 客戶端與 Zookeeper 服務(wù)端斷開連接時,該節(jié)點(diǎn)會自動被 Zookeeper 服務(wù)端刪除;
  • 節(jié)點(diǎn)具有順序性,創(chuàng)建該節(jié)點(diǎn)時,Zookeeper 服務(wù)端會根據(jù)創(chuàng)建時間的順序在該節(jié)點(diǎn)名稱后面加上順序編號。

回顧了臨時順序節(jié)點(diǎn)的特性,接下來我們就使用 Zookeeper 的 Java 客戶端 Curator 來創(chuàng)建臨時順序節(jié)點(diǎn),我們可以使用在 Zookeeper Curator 一節(jié)創(chuàng)建的 Spring Boot 測試項(xiàng)目來進(jìn)行測試。

我們可以在測試類 CuratorDemoApplicationTests 中編寫測試用例:

@SpringBootTest
class CuratorDemoApplicationTests {

    @Autowired
    private CuratorService curatorService;

    @Test
    void contextLoads() throws Exception {
        // 獲取客戶端
        CuratorFramework client = curatorService.getCuratorClient();
        // 開啟會話
        client.start();
        
        // 第一次創(chuàng)建臨時順序節(jié)點(diǎn)
        String s1 = client.create()
            // 如果有父節(jié)點(diǎn)會一起創(chuàng)建
            .creatingParentsIfNeeded()
            // 節(jié)點(diǎn)類型:臨時順序節(jié)點(diǎn)
            .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
            // 節(jié)點(diǎn)路徑 /wiki
            .forPath("/wiki-");
        // 輸出
        System.out.println(s1);
        
        // 第二次創(chuàng)建臨時順序節(jié)點(diǎn)
        String s2 = client.create()
            // 如果有父節(jié)點(diǎn)會一起創(chuàng)建
            .creatingParentsIfNeeded()
            // 節(jié)點(diǎn)類型:臨時順序節(jié)點(diǎn)
            .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
            // 節(jié)點(diǎn)路徑 /wiki
            .forPath("/wiki-");
        // 輸出
        System.out.println(s2);
        
        // 關(guān)閉客戶端
        client.close();
    }
}

執(zhí)行測試方法,控制臺輸出:

/wiki-0000000000
/wiki-0000000001

我們可以發(fā)現(xiàn),控制臺一共輸出了兩個 /wiki 節(jié)點(diǎn),而且每個 /wiki 節(jié)點(diǎn)后面都增加了編號,此時我們?nèi)?zkCli 命令行客戶端查看所有節(jié)點(diǎn),發(fā)現(xiàn)并沒有 /wiki 節(jié)點(diǎn)。因?yàn)樵谖覀兊臏y試程序中,我們關(guān)閉了客戶端,所以臨時節(jié)點(diǎn)會被移除。

Tips: 如果這里創(chuàng)建失敗,請同學(xué)們注意父節(jié)點(diǎn)是否存在 ACL 訪問控制。

回顧了臨時順序節(jié)點(diǎn),那么如何使用 Zookeeper 的臨時順序節(jié)點(diǎn)來實(shí)現(xiàn)分布式鎖呢?接下來我們就開始介紹如何使用 Zookeeper 的臨時順序節(jié)點(diǎn)來控制它們的訪問順序。

3.2 分布式鎖實(shí)現(xiàn)

本節(jié)我們來介紹分布式鎖實(shí)現(xiàn)的具體步驟:

  1. 創(chuàng)建臨時順序節(jié)點(diǎn): 每一次獲取資源的請求,我們都需要使用 Zookeeper 客戶端創(chuàng)建一個臨時順序節(jié)點(diǎn),用這個臨時順序節(jié)點(diǎn)在 Zookeeper 服務(wù)端中獲取鎖。

  2. 獲取鎖: 這里的鎖并不具體指代什么,而是根據(jù) Zookeeper 的臨時順序節(jié)點(diǎn)的順序來決定是否獲取了鎖。如果該節(jié)點(diǎn)的順序編號是最小的,則說明該節(jié)點(diǎn)是排在最前面的,在它之前無人占領(lǐng)資源,也就可以說該節(jié)點(diǎn)獲取了鎖,具有訪問資源的權(quán)限。

圖片描述

  1. 監(jiān)聽鎖: 如果獲取鎖這一步發(fā)現(xiàn) Zookeeper 客戶端創(chuàng)建的臨時順序節(jié)點(diǎn)的順序編號不是最小的,也就是在這個臨時順序節(jié)點(diǎn)之前存在其它臨時順序節(jié)點(diǎn),那么就可以說這個節(jié)點(diǎn)獲取鎖失敗了,它會進(jìn)入等待隊列。我們可以監(jiān)聽它的前一個節(jié)點(diǎn),只要它的前一個臨時順序節(jié)點(diǎn)的刪除事件觸發(fā),我們就可以獲取臨時順序節(jié)點(diǎn)的列表來重新確認(rèn)這個節(jié)點(diǎn)的順序。

圖片描述

  1. 釋放鎖: 當(dāng)一個請求對資源的操作結(jié)束后,我們可以使用 Zookeeper 客戶端的節(jié)點(diǎn)刪除 API 來刪除這個請求創(chuàng)建的臨時順序節(jié)點(diǎn)。除了使用 API 來主動釋放鎖之外,根據(jù)臨時順序節(jié)點(diǎn)的特性,當(dāng)創(chuàng)建這個臨時順序節(jié)點(diǎn)的 Zookeeper 客戶端與 Zookeeper 服務(wù)端斷開連接時,這個臨時順序節(jié)點(diǎn)會被 Zookeeper 服務(wù)端移除。這兩種方式都會觸發(fā)臨時節(jié)點(diǎn)的刪除事件,讓下一個臨時順序節(jié)點(diǎn)來確認(rèn)自身的順序。

4. 總結(jié)

本節(jié)內(nèi)容中,我們學(xué)習(xí)了什么是分布式鎖,以及它的特點(diǎn)和類型,還學(xué)習(xí)了使用 Zookeeper 實(shí)現(xiàn)分布式鎖的主要步驟。以下是本節(jié)內(nèi)容的總結(jié):

  1. 分布式鎖的特點(diǎn)和常用類型。
  2. 臨時順序節(jié)點(diǎn)的特性。
  3. 使用 Zookeeper 實(shí)現(xiàn)分布式鎖的主要步驟。