1. 程式人生 > 其它 >【28期】ZooKeeper面試那些事兒

【28期】ZooKeeper面試那些事兒

ZooKeeper是什麼?

ZooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,是Google的Chubby一個開源的實現,它是叢集的管理者,監視著叢集中各個節點的狀態根據節點提交的反饋進行下一步合理操作。最終,將簡單易用的介面和效能高效、功能穩定的系統提供給使用者。

客戶端的讀請求可以被叢集中的任意一臺機器處理,如果讀請求在節點上註冊了監聽器,這個監聽器也是由所連線的zookeeper機器來處理。對於寫請求,這些請求會同時發給其他zookeeper機器並且達成一致後,請求才會返回成功。因此,隨著zookeeper的叢集機器增多,讀請求的吞吐會提高但是寫請求的吞吐會下降。

有序性是zookeeper中非常重要的一個特性,所有的更新都是全域性有序的,每個更新都有一個唯一的時間戳,這個時間戳稱為zxid(Zookeeper Transaction Id)。而讀請求只會相對於更新有序,也就是讀請求的返回結果中會帶有這個zookeeper最新的zxid。

ZooKeeper提供了什麼?

檔案系統

通知機制

Zookeeper檔案系統

Zookeeper提供一個多層級的節點名稱空間(節點稱為znode)。與檔案系統不同的是,這些節點都可以設定關聯的資料,而檔案系統中只有檔案節點可以存放資料而目錄節點不行。Zookeeper為了保證高吞吐和低延遲,在記憶體中維護了這個樹狀的目錄結構,這種特性使得Zookeeper不能用於存放大量的資料,每個節點的存放資料上限為1M。

四種類型的znode

1、PERSISTENT- 持久化目錄節點

客戶端與zookeeper斷開連線後,該節點依舊存在

2、PERSISTENT_SEQUENTIAL - 持久化順序編號目錄節點

客戶端與zookeeper斷開連線後,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號

3、EPHEMERAL - 臨時目錄節點

客戶端與zookeeper斷開連線後,該節點被刪除

4、EPHEMERAL_SEQUENTIAL - 臨時順序編號目錄節點

客戶端與zookeeper斷開連線後,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號。

Zookeeper通知機制

client端會對某個znode建立一個watcher事件,當該znode發生變化時,這些client會收到zk的通知,然後client可以根據znode變化來做出業務上的改變等。

Zookeeper做了什麼?

  • 命名服務
  • 配置管理
  • 叢集管理
  • 分散式鎖
  • 佇列管理

zk的命名服務(檔案系統)

命名服務是指通過指定的名字來獲取資源或者服務的地址,利用zk建立一個全域性的路徑,即是唯一的路徑,這個路徑就可以作為一個名字,指向叢集中的叢集,提供的服務的地址,或者一個遠端的物件等等。

zk的配置管理(檔案系統、通知機制)

程式分散式的部署在不同的機器上,將程式的配置資訊放在zk的znode下,當有配置發生改變時,也就是znode發生變化時,可以通過改變zk中某個目錄節點的內容,利用watcher通知給各個客戶端,從而更改配置。

Zookeeper叢集管理(檔案系統、通知機制)

所謂叢集管理無在乎兩點:是否有機器退出和加入、選舉master。

對於第一點,所有機器約定在父目錄下建立臨時目錄節點,然後監聽父目錄節點的子節點變化訊息。一旦有機器掛掉,該機器與 zookeeper的連線斷開,其所建立的臨時目錄節點被刪除,所有其他機器都收到通知:某個兄弟目錄被刪除,於是,所有人都知道:它上船了。

新機器加入也是類似,所有機器收到通知:新兄弟目錄加入,highcount又有了,對於第二點,我們稍微改變一下,所有機器建立臨時順序編號目錄節點,每次選取編號最小的機器作為master就好。

Zookeeper分散式鎖(檔案系統、通知機制)

有了zookeeper的一致性檔案系統,鎖的問題變得容易。鎖服務可以分為兩類,一個是保持獨佔,另一個是控制時序。

對於第一類,我們將zookeeper上的一個znode看作是一把鎖,通過createznode的方式來實現。所有客戶端都去建立 /distribute_lock 節點,最終成功建立的那個客戶端也即擁有了這把鎖。用完刪除掉自己建立的distribute_lock 節點就釋放出鎖。

對於第二類, /distribute_lock 已經預先存在,所有客戶端在它下面建立臨時順序編號目錄節點,和選master一樣,編號最小的獲得鎖,用完刪除,依次方便。

獲取分散式鎖的流程

在獲取分散式鎖的時候在locker節點下建立臨時順序節點,釋放鎖的時候刪除該臨時節點。客戶端呼叫createNode方法在locker下建立臨時順序節點,

然後呼叫getChildren(“locker”)來獲取locker下面的所有子節點,注意此時不用設定任何Watcher。客戶端獲取到所有的子節點path之後,如果發現自己建立的節點在所有建立的子節點序號最小,那麼就認為該客戶端獲取到了鎖。

如果發現自己建立的節點並非locker所有子節點中最小的,說明自己還沒有獲取到鎖,此時客戶端需要找到比自己小的那個節點,然後對其呼叫exist()方法,同時對其註冊事件監聽器。之後,讓這個被關注的節點刪除,則客戶端的Watcher會收到相應通知,此時再次判斷自己建立的節點是否是locker子節點中序號最小的,如果是則獲取到了鎖,如果不是則重複以上步驟繼續獲取到比自己小的一個節點並註冊監聽。當前這個過程中還需要許多的邏輯判斷。

程式碼的實現主要是基於互斥鎖,獲取分散式鎖的重點邏輯在於BaseDistributedLock,實現了基於Zookeeper實現分散式鎖的細節。

Zookeeper佇列管理(檔案系統、通知機制)

兩種型別的佇列:

  • 同步佇列,當一個佇列的成員都聚齊時,這個佇列才可用,否則一直等待所有成員到達。
  • 佇列按照 FIFO 方式進行入隊和出隊操作。

第一類,在約定目錄下建立臨時目錄節點,監聽節點數目是否是我們要求的數目。

第二類,和分散式鎖服務中的控制時序場景基本原理一致,入列有編號,出列按編號。在特定的目錄下建立PERSISTENT_SEQUENTIAL節點,建立成功時Watcher通知等待的佇列,佇列刪除序列號最小的節點用以消費。此場景下Zookeeper的znode用於訊息儲存,znode儲存的資料就是訊息佇列中的訊息內容,SEQUENTIAL序列號就是訊息的編號,按序取出即可。由於建立的節點是持久化的,所以不必擔心佇列訊息的丟失問題。

Zookeeper資料複製