掌握之分佈式-2.Zookeeper

掌握高併發、高可用架構

第三章 分佈式

本章介紹分佈式架構的底層技術。主要說明面試過程中可能被問到的技術點。

第二節 Zookeeper

Zookeeper 分佈式

1. Zookeeper是什麼

Zookeeper是一個分佈式的、開源的分佈式應用程序協調服務。它是集羣的管理者,監視着集羣中各個節點的狀態,並根據節點提交的反饋進行下一步合理的操作。

對於客戶端的讀操作,可以被集羣中任意一臺機器處理。如果讀請求在節點上註冊了監聽器,這個監聽器也是由所連接的機器來執行

對於客戶端的寫操作,這些請求會同時發給其他的zookeeper機器並達成一致後,請求才會返回成功

因此,隨着集羣機器的增多,讀請求的吞吐會提高,而寫請求的吞吐會下降

有序性是Zookeeper的另一個特點,所有的更新操作都是全局有序的;每個更新都有唯一的時間戳,稱爲zxid(Zookeeper Transaction Id);而讀請求只會相對於更新有序,也就是讀請求的返回結果中會帶有這個zookeeper的最新zxid

2. Zookeeper提供了什麼

文件系統 和 通知機制

3. Zookeeper文件系統

Zookeeper提供了一個多層級的節點命名空間(節點稱爲znode)

與文件系統不同的是,它的每個節點都可以設置關聯數據,而文件系統只有文件節點可以存放數據而目錄節點不行

Zookeeper爲了保證高吞吐和低延遲,在內存中維護了這個樹狀的目錄結構,所以它不能存放大量的數據,每個節點的存放數據上限是1M

4. 四種類型的znode
  1. PERSISTENT,持久化目錄節點:客戶端與Zookeeper斷開連接後,該節點依舊存在
  2. PERSISTENT_SEQUENTIAL,持久化順序編號目錄節點:客戶端與Zookeeper斷開連接後,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號
  3. EPHEMERAL,臨時目錄節點:客戶端與Zookeeper斷開連接後,該節點被刪除
  4. EPHEMERAL_SEQUENTIAL,臨時順序編號目錄節點:客戶端與Zookeeper斷開連接後,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號
5. Zookeeper通知機制

客戶端註冊監聽它關心的目錄節點,會對該znode建立一個watcher事件,當該znode發生變化(數據刪除、被刪除、子目錄節點增加刪除等)時,Zookeeper會通知客戶端

img

6. Zookeeper可以做什麼
  1. 命名服務(利用文件系統的功能):

​ 命名服務是指通過指定的名字來獲取資源或服務的地址,即利用Zookeeper創建一個全局的路徑,也就是唯一的路徑,這個路徑可以作爲一個名字,指向集羣中的機器、提供服務的地址、一個遠程對象等

  1. 配置管理(利用文件系統、通知機制):

​ 程序分佈式的部署在不同的機器上,將程序的配置信息放在zookeeper的znode下,當配置發生變化時,也就是znode發生變化時,利用watcher通知各個客戶端,從而更改配置

  1. 集羣管理(文件系統、通知機制):

​ 所謂集羣管理無非兩點,是否有機器退出或加入、選舉master

​ 第一點,所有機器約定在父目錄下創建臨時目錄節點,然後監聽父目錄節點的子節點變化信息;如果有機器掛了,該機器就會與Zookeeper斷開連接,其創建的臨時目錄就會刪除,此時就會通知所有機器,有個兄弟機器掛了;同理,機器加入也是一樣

​ 第二點,所有機器創建臨時順序編號目錄節點,每次都選取編號最小的機器作爲master

  1. 分佈式鎖(文件系統、通知機制):

​ 有了Zookeeper的一致性文件系統,鎖變得簡單。鎖服務可以分爲兩類:保持獨佔控制時序

​ 對於保持獨佔,我們將znode看作一把鎖,通過createznode的方式來實現;所有客戶端都去創建/distribute_lock節點,最終成功創建的那個客戶端也就獲取了這把鎖,用完刪掉/distribute_lock節點,即可釋放鎖

​ 對於控制時序,/distribute_lock已經預先存在,所有客戶端在它下面創建臨時順序編號目錄節點,和選舉master一樣,編號最小的獲得鎖,用完刪除自己的臨時順序編號目錄節點

  1. 隊列管理(文件系統、通知機制):
    • 同步隊列,只有隊列成員都聚齊時纔可用,否則一直等待:在約定目錄下創建臨時目錄節點,查看監聽節點的數量是否是我們要求的數量
    • 隊列按照FIFO方式進行入隊和出隊操作:和分佈式鎖的控制時序的基本原理一致,在特定目錄下創建持久順序編號目錄節點,創建成功則Watcher通知等待的隊列,刪除最小號的節點用於消費
7. 獲取分佈式鎖的過程

在分佈式鎖的場景下,會提前在Zookeeper中創建一個持久節點ParentLocker(名字叫什麼都可以)

當客戶端要獲取鎖時,需要在ParentLocker下創建一個臨時順序編號節點Locker-n,首先,查找ParentLocker下的所有臨時子節點並排序,並且判斷自己創建的Locker-n是不是順序編號最小的,如果是,則臨時節點Locker-n創建成功,也就是獲取鎖成功;如果不是最小的,此時找到排序僅比自己靠前的節點,向其註冊監聽Watcher,監聽其是否存在(exist),也就是該客戶端獲取鎖失敗,進入等待;當前一個節點被刪除時,客戶端會收到通知,然後再次判斷自己是不是最小的,如果是則獲取鎖成功,如果不是,則再重複以上步驟

clipboard.png

zookeeper简ä

8. Zookeeper的工作原理

Zookeeper的核心是原子廣播,保證了各個Server之間的同步;實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,恢復模式(選主)廣播模式(同步)。當服務啓動或者領導者崩潰後,Zab進入恢復模式;當選舉了新的領導者,並且大多數Server和leader的狀態同步完成之後,恢復模式就結束了。狀態同步保證了leader和server之間有相同的系統狀態

9. Zookeeper如何保證事務的一致性

採用遞增的事務ID:zxid來標識,所有的proposal(提議)都會加上zxid。zxid是64位的數字,高32位是epoch,用來標識leader是否發生變化,如果是新選舉的leader,則epoch會遞增;低32位是遞增計數的。當有新的proposal提出時,首先向其他server發出事務執行請求,如果有超過半數的機器都能執行且能夠執行成功,然後纔會開始執行

10. Zookeeper的Server工作狀態
  • LOOKING,當前server不知道leader是誰,正在搜索
  • LEADING,當前server爲leader
  • FOLLOWING,普通server,與leader進行同步
11. Zookeeper是如何選舉leader的

當leader崩潰或失去大多數follower,這時會進入恢復模式。選舉算法有兩種:一種是基於basic paxos實現的,一種是基於fast paxos實現的,默認是fast paxos。

  • basic paxos算法

    a) 每個Server上的選舉線程由當前Server發起選舉的線程擔任,主要職責是對各個投票結果進行統計,選舉 出新的leader

    b) 選舉線程向所有Server發起一次詢問(包括自己)

    c) 選舉線程收到回覆後,驗證是否是自己發出的詢問(驗證zxid是否一致),然後獲取對方的myid,將之存儲到當前詢問的對象列表中,最後獲取對方提議的leader相關信息(myid,zxid),存儲到當次選舉的投票記錄中

    d) 收到所有的Server回覆後,計算出zxid最大的Server,然後統計它的票數,如果它獲得了n/2+1的Server票數,則設置爲新的leader。否則,重新再次選舉

    通過該選舉流程可以得出,要使leader獲得多數Server的支持,Server的總數必須是奇數2n+1,且存活的Server數目不得少於n+1

    clipboard.png

  • fast paxos算法

    在選舉時,首先向所有Server提議自己要成爲leader,當其他Server收到提議後,會進行PK(zxid大myid大的獲勝),並回復同意還是拒絕,重複這個流程,就會選擇出一個新的leader

12. 同步流程

選完leader後,進入同步流程

  1. leader等待server連接
  2. follower連接leader,將自己最大的zxid發送給leader
  3. leader根據follower的zxid判斷同步點
  4. 完成同步後通知follower已成爲uptodate狀態
  5. follower收到uptodate通知後,就可以接收客戶端的請求了
13. Zookeeper的負載均衡和NGINX的負載均衡

zk的負載均衡可以調控,nginx只能調權重,其他的都要自己寫插件,但是nginx的吞吐量比zk大得多

14. watch機制

一個watch事件是一個一次性的觸發器,當被設置了watch的數據發生了變化時,服務器會將這個變化發送給設置了watch的客戶端

  1. 數據發生改變時,一個watch event會被髮送給客戶端,但是隻會發送一次
  2. watch event從server發送到client是異步的,只保證數據的最終一致性
  3. getData()、exists()設置數據監控,getChildren()設置子節點監控
  4. 註冊watcher:getData、exists、getChildren
  5. 觸發watcher:create、delete、setData
  6. setData()成功的話會觸發當前znode的數據監控;create()成功的話會觸發當前znode的數據監控,以及父節點的子節點監控;delete()成功的話會觸發當前znode的數據監控和子節點監控(因爲子節點也發生了變化),以及其父節點的子節點監控
  7. 當客戶端與服務器斷開連接後,是無法收到watch事件的,而當客戶端重新連接後,如果有需要的話,之前註冊的watch會被重新註冊的
  8. Watch是輕量級的,其實就是本地的Callback(客戶端創建連接時,public Zookeeper(String connStr, int sessionTimeout, Watcher watcher)),服務器端只是存儲了是否設置了watch的布爾變量
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章