成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

很遺憾,沒有一篇文章能講清楚ZooKeeper

原創
開源
互聯網時代是信息爆發的時代,信息的高并發催生了分布式系統的廣泛應用。

【51CTO.com原創稿件】互聯網時代是信息爆發的時代,信息的高并發催生了分布式系統的廣泛應用。

[[283428]] 

圖片來自 Pexels

作為分布式系統解決方案的 ZooKeeper,被廣泛應用于多個分布式場景。例如:數據發布/訂閱,負載均衡,命名服務,集群管理等等。

因此,ZooKeeper 在分布式系統中扮演著重要的角色,今天通過一個簡單的例子來看看它的實現原理。

從一個簡單的例子開始

在分布式系統中經常會遇到這種情況,多個應用讀取同一個配置。例如:A,B 兩個應用都會讀取配置 C 中的內容,一旦 C 中的內容出現變化,會通知 A 和 B。

一般的做法是在 A,B 中按照時鐘頻率詢問 C 的變化,或者使用觀察者模式來監聽 C 的變化,發現變化以后再更新 A 和 B。那么 ZooKeeper 如何協調這種場景?

ZooKeeper 會建立一個 ZooKeeper 服務器,暫且稱為 ZServer,用它來存放 C 的值。為 A,B 兩個應用分別生成兩個客戶端,稱作 ClientA 和 ClientB。

這兩個客戶端連接到 ZooKeeper 的服務器,并獲取其中存放的 C。保存 C 值的地方在 ZooKeeper 服務端(Server)中稱為 ZNode。

 

ClientA 和 ClientB 通過 ZooKeeper Server 獲取 C 的值

ZNode

通過上面的例子,客戶端 ClientA 和 ClientB 需要讀取 C 的內容。這個 C 就作為樹的葉子節點存放在 ZooKeeper 的 ZNode 中。

通常來說,為了提高效率 ZNode 是被存放在內存中的。ZNode 的數據模型是一棵樹(ZNode Tree)。

好像我們從上圖中看到的一樣,樹中的每個節點都可以存放數據,并且每個節點下面都可以存放葉子節點。

ZooKeeper 客戶端通過 “/” 作為訪問路徑,訪問數據。例如可以通過路徑 “/RootNode/C” 來訪問 C 變量。

為了方便客戶端調用,ZooKeeper 會暴露一些命令:

 

訪問 Znode 命令

作為存儲媒介來說,ZNode分為持久節點和臨時節點:

  • 持久節點(PERSISTENT),該數據節點被創建后,就一直存在于 ZooKeeper 服務器上,除非刪除操作(delete)清除該節點。
  • 臨時節點(EPHEMERAL),該數據節點的生命周期會和客戶端(Client)會話(Session)綁定在一起。如果客戶端(Client)會話丟失了,那么節點就自動清除掉。

如果把臨時節點看成資源的話,當客戶端和服務端產生會話并生成臨時節點,一旦客戶端與服務器中斷聯系,節點資源會被從 ZNode 中刪除。

順序節點(SEQUENTIAL),ZNode 節點被分配唯一個單調遞增的整數。例如多個客戶端在服務器 /tasks 上申請節點時,根據客戶端申請的先后順序,將數字追加到 /tasks/task 后面。

如果有三個客戶端申請節點資源,那么在 /tasks 下面建立三個順序節點,分別是 /tasks/task1,/tasks/task2,/tasks/task3。

順序節點,在處理分布式事務的時候非常有幫助,當多個客戶端(Client)協作工作的時候,會按照一定的順序執行。

如果將上面的兩類節點和順序節點進行組合的話,就有四種節點類型,分別是持久節點,持久順序節點,臨時節點,臨時順序節點。

Watcher

上面說了 ZooKeeper 用來存放數據的 ZNode,并且把 C 的值存儲在里面。如果 C 被更新了,兩個客戶端(ClientA、ClientB)如何獲得通知呢?

ZooKeeper 客戶端(Client)會在指定的節點(/RootNote/C)上注冊一個 Watcher,ZNode 上的 C 被更新的時候,服務端就會通知 ClientA 和 ClientB。

通過三步來實現:

  • 客戶端注冊 Watcher
  • 服務端處理 Watcher
  • 客戶端回調 Watcher

 

Watcher 注冊,處理,回調

①客戶端注冊 Watcher

ZooKeeper 客戶端創建 Watcher 的實例對象:

 

同時這個 Watcher 會保存在客戶端本地,一直作為和服務端會話的 Watcher。

 

客戶端可以通過 getData,getChildren 和 exist 方法來向服務端注冊 Watcher。

 

客戶端注冊 Watcher 簡圖

同時需要注意的是在客戶端發送 Watcher 到服務端注冊的時候,會將這個要發送的 Watcher 在本地的 ZKWatchManager 中保存。

這樣做的好處,就是當獲得服務端的注冊成功的信息以后,就不用將 Watcher 的具體內容回傳給客戶端了。

客戶端只用在接到服務端響應以后,從本地的 ZKWatchManager 中獲取 Watch 的信息進行處理即可。

②服務端處理 Watcher

服務端收到客戶端的請求以后,交給 FinalRequestProcessor 處理,這個進程會去 ZNode 中獲取對應的數據,同時會把 Watch 加入到 WatchManager 中。

這樣下次這節點上的數據被更改了以后,就會通知注冊 Watch 的客戶端了。 


服務端處理 Watch 過程

③客戶端回調 Watcher

客戶端在響應客戶端 Watcher 注冊以后,會發送 WathcerEvent 事件。作為客戶端有對應的回調函數接受這個消息。

這里會通過 readResponse 方法統一處理: 


在 SendTread 接受到服務端的通知以后,會將事件通過 EventThread.queueEvent 發送給 EventThread。

正如前面提到的,在客戶端注冊時,已經將 Watcher 的具體內容保存在 ZKWatchManager 一樣了。

所以,EventTread 通過 EventType 就可以知道哪個 Watcher 被響應了(數據變化了)。

然后從 ZKWatchManager 取出具體 Watch 放到 waitingEvent 隊列等待處理。

最后,由 EventThread 中的 processEvent 方法依次處理數據更新的響應。

 

版本(Version)

介紹完了 Watcher 機制,回頭再來談談 ZNode 的版本(Version)。如果有一個客戶端(ClientD),它嘗試修改 C 的值,此時其他兩個客戶端會收到通知,并且進行后續的業務處理了。

 

那么在分布式系統中,會出現這么一種情況:在 ClientD 對 C 進行寫入操作的時候,又有一個 ClientE 也對 C 進行寫入操作。這兩個 Client 會去競爭 C 資源,通常這種情況需要對 C 進行加鎖操作。

 

兩個 Client 競爭一個資源

因此引入 ZNode 版本(Version)概念。版本是用來保證分布式數據原子性操作的。

ZNode 的版本(Version)信息保存在 ZNode 的 Stat 對象中。有如下三種:

 

本例只關注“數據節點內容的版本號”,也就是 Version。

如果說 ClientD 和 ClientE 對 C 進行寫入操作視作是一個事務的話。在執行寫入操作之前,兩個事務分別會獲取節點上的值,即節點保存的數據和節點的版本號(Version)。

以樂觀鎖為例,對數據的寫入會分成以下三個階段:數據讀取,寫入校驗和數據寫入。例如 C 上的數據是 1, Version 是 0。

此時 ClientD 和 ClientE 都獲取了這些信息。假設 ClientD 先做寫入操作,在做寫入校驗的時候,發現之前獲得的 Version 和節點上的 Version 是相同的,都是 1,因此直接執行數據寫入。

寫入以后,Version 由原來的 1 變成了 2。當 ClientE 做寫入校驗時,發現自己持有的 Version=1 和節點當前的 Version=2,不一樣。于是,寫入失敗,重新獲取 Version 和節點數據,再次嘗試寫入。

除了上述方案以外,還可以利用 ZNode 的有序性。在 C 下面建立多個有序的子節點。每當一個 Client 準備寫入數據的時候,創建一個臨時有序的節點。

節點的順序根據 FIFO 算法,保證先申請寫入的 Client 排在其前面。每個節點都有一個序號,后面申請的節點按照序號依次遞增。

 

ClientD,ClientE 分別建立子 ZNode

每個 Client 在執行修改 C 操作的時候,都要檢查有沒有比自己序號小的節點,如果存在那么就進入等待。

直到比自己序號小的節點進行完畢以后,才輪到自己執行修改操作。從而保證了事物處理的順序性。

會話(Session)

說完版本(Version)的概念,例子從原來的 ClientAB 已經擴充到了 ClientDE。這些客戶端都會和 ZooKeeper 的服務端進行通信,或讀取數據或修改數據。

我們將客戶端與服務端完成的這種連接稱為會話。ZooKeeper 的會話有 Connecting,Connected,Reconnecting,Reconnected 和 Close 這幾種狀態。

并且在服務端由專門的進程來管理他們,客戶端初始化的時候就會根據配置自動連接服務器,從而建立會話,客戶端連接服務器時會話處于 Connecting 狀態。

一旦連接完成,就會進入 Connected 狀態。如果出現延遲或者短暫失聯,客戶端會自動重連,Reconnecting 和 Reconnected 狀態也就應運而生。

如果長時間超時,或者客戶端斷開服務器,ZooKeeper 會清理掉會話,以及該會話創建的臨時數據節點,并且關閉和客戶端的連接。

  • Session 作為會話實體,用來代表客戶端會話,其包括 4 個屬性:
  • SessionID,用來全局唯一識別會話。
  • TimeOut,會話超時事件。客戶端在創造 Session 實例的時候,會設置一個會話超時的時間。
  • TickTime,下次會話超時時間點。后面“分桶策略”會用到。

isClosing,當服務端如果檢測到會話超時失效了,會通過設置這個屬性將會話關閉。

既然,會話是客戶端與服務器之間的連接。在服務器端由 SessionTracker 管理會話。

SessionTracker 有一個工作就是,將超時的會話清除掉。于是“分桶策略”就登場了。

由于每個會話在生成的時候都會定義超時時間,通過當前時間+超時時間可以算出會話的過期時間。

由于 SessionTracker 不是實時監聽會話超時,它是按照一定時間周期來監聽的。

也就是說,如果沒有到達 SessionTracker 的檢查時間周期,即使有會話過期,SessionTracker 也不會去清除。由此,就引入會話超時計算公式,也就是 TickTime 的計算公式。

TickTime=((當前時間+會話過期時間)/檢查時間間隔+1)*檢查時間間隔。

將這個值計算出來以后,SessionTracker 會把對應的會話按照這個時間放在對應的時間軸上面。SessionTracker 在對應的 TickTime 檢查會話是否過期。

 

計算會話下次的過期時間

每當客戶端連接上服務器都會做激活操作,同時每隔一段時間客戶端會向服務器發送心跳檢測。

服務器收到激活或者心跳檢測以后,會重新計算會話過期時間,根據“分桶策略”進行重新調整。把會話從“老的區塊“放到”新的區塊“中去。

 

重新計算過期時間并且調整“分桶策略”

對于超時的會話,SessionTracker 也會做如下清理工作:

  • 標記會話狀態為“已關閉”,也就是設置 isClosing 為 True。
  • 發起“會話關閉”的請求,讓關閉操作在整個集群生效。
  • 收集需要清理的臨時節點。
  • 添加“節點刪除”的事務變更。
  • 刪除臨時節點
  • 移除會話
  • 關閉客戶端與服務端的連接

會話關閉以后客戶端就無法從服務端獲取/寫入數據了。

服務群組(Leader,Follower,Observer)

前面提到了客戶端如何通過會話與服務端保持聯系,以及服務端是如何管理客戶端會話(Session)的。

我們繼續思考一下,這么多的服務端都依賴一個 ZooKeeper 服務器。一旦服務掛了,客戶端就無法工作了。

為了提高 ZooKeeper 服務的可靠性,引入服務器集群的概念。從原來的單個服務器,擴充成多個服務器,即使某一臺服務器掛了,其他的服務器也可以頂上來。

 

ZooKeeper 的服務器集群

這樣看起來不錯了,新的問題是,存在多個 ZooKeeper 服務器,那么客戶端的請求發給哪臺呢?服務器之間如何同步數據呢?如果一個服務掛掉了其他的服務器如何替代?這里介紹兩個概念 Leader 和 Follower。

Leader 服務器,是事務請求(寫操作)的唯一調度者和處理者,保證集群事務處理的順序性。也是集群內部服務器的調度者。

它是整個集群的老大,其他的服務器接到事務請求都會轉交給它,讓它協調處理。

Follower 服務器,處理非事務請求(讀操作),轉發事務請求給 Leader 服務器。參與選舉 Leader 的投票和事務請求 Proposal 的投票。

既然 Leader 是集群的老大,那么這個老大是如何產生的。ZooKeeper 有仲裁機制,通過服務器的選舉產生這個 Leader,按照少數服從多數的原則。

因此,集群中服務器的個數一般都是奇數,例如:1,3,5。當然這里是建議。關于選舉和仲裁都有一定的算法,一起來看看吧。

當眾多服務器啟動的時候,互相都不知道誰是 Leader,因此都會進入 Looking 狀態,也就是在網絡中尋找 Leader。

尋找的過程也是投票的過程,每個服務器會將服務器 ID 和事務 ID 作為投票信息發送給網絡中其他的服務器。假設稱它為投票信息 VOTE,它包括:(ServerID,ZXID)。

其中,ServerID 是服務器注冊的 ID,隨著服務器啟動的順序自動增加,后啟動的服務器 ServerID 就大;ZXID 是服務器處理事物的 ID,隨著事物的增加自動增加,同樣后提交的事務 ZXID 也大一些。

其他的服務器收到 VOTE 信息以后會和自己的 VOTE 信息(ServerID,ZXID)進行比較。

如果收到的 VOTE(ServerID,ZXID)中的 ZXID 比自己的 ZXID 要大,那么把自己的 VOTE 修改成收到的 VOTE。

如果 ZXID 一樣大,那么就比較 ServerID,將大的那個 ServerID 作為自己 VOTE 的 ServerID,轉發給其他服務器。

再簡單點說,如果事務 ID(ZXID)比自己的事務 ID(ZXID)要大,就把票投給這個服務器。如果事務 ID 一樣,就把票投給 ServerID 大的服務器。

來個具體的例子,有三個服務器,他們的投票值分別是:

  • S1 (1,6)
  • S2 (2,5)
  • S3 (3,5)

三個服務器分別把自己的 VOTE 發給其他兩臺服務器,S2 和 S3 收到 VOTE 以后發現 ZXID 為 6 的來自 S1 的 VOTE 比自己持有的 ZXID 要大,因此把自己的 VOTE 修改為(1,6)投出去,因此 S1 稱為 Leader。

 

Leader 選舉實例

同樣,如果 S1 作為 Leader,因為某種原因掛掉或者長時間沒有響應請求,其他的服務器也會進入 Looking 狀態,開啟投票仲裁模式尋找下一個 Leader。

成為新 Leader 以后會通過廣播的方式將 ZNode 上的數據同步到其他的 Follower。

Leader 有了,整個服務器集群有了領袖,它可以處理客戶端的事物請求。客戶端的請求可以發給集群中任意一臺服務器,無論是哪個服務器都會將事物請求轉交給 Leader。

Leader 在將數據寫入 ZNode 之前會向 ZooKeeper 的其他 Follower 進行廣播。

這里廣播用到了 ZAB 協議(Atomic Broadcast Protocol)是 Paxos 協議的實踐。說白了就是一個兩段提交。

PS:對分布式事務比較了解的同學應該知道兩段提交和三段提交。

這里 ZooKeeper 通過以下方式實現兩段提交:

  • Leader 向所有 Follower 發送一個 PROPOSAL。
  • 當 Follower 接收到 PROPOSAL 后,返回給 Leader 一個 ACK 消息,表示我收到 PROPOSAL,并且準備好了。
  • Leader 仲裁數量(過半數)的 Follower 發送的 ACK 后(包括 Leader 自己),會發送消息通知 Follower 進行 COMMIT。
  • 收到 COMMIT 以后,Follower 就開始干活,將數據寫入到 ZNode 中。

 

ZAB 廣播 PROPOSAL

選舉了 Leader 領導集群,Leader 接受到 Client 的請求以后,也可以協調 Follower 工作了。

 

那么如果 Client 很多的情況下,特別是這些客戶端都是做讀操作的時候,ZooKeeper 服務器如何處理如此多的請求呢?這里引入 Observer 的概念。

Observer 和 Follower 基本一致,對于非事務請求(讀操作),可以直接返回節點中的信息(數據從 Leader 中同步過來的)。

對于事務請求(寫操作),會轉交給 Leader 做統一處理。Observer 的存在就是為了解決大量客戶端讀請求。

Observer 和 Follower 的區別是,Observer 不參與仲裁投票,選舉 Leader。

 

Observer 加入 Leader 和 Follower 大家庭

總結

全文用了一個簡單的例子講 ZooKeeper 的主要特性和實現原理,最后做個總結。

ZooKeeper 被用來協調和管理分布式系統,發揮著重要的作用。分布式系統由于其特性,應用分布在不同的物理主機或者網絡中。

為了讓它們協同工作,ZooKeeper 中的 ZNode 成為統一協調的重要部分,客戶端通過 Client 間接到服務端的 ZNode 上,監聽 ZNode 數據的變化。

同時 ZNode 支持的持久,臨時和順序性,以及版本(Version)控制,這些特性支持了分布式事務和鎖的功能。

如果說,每一個 ZooKeeperClient 對 Server 的寫入操作都是一次事務的話,ZooKeeper 服務端維護了大量的事務,并且通過“分桶策略”來管理它們,保證了 Client 與 Server 端協調工作。

為了提高 Server 的可靠性,ZooKeeper 引入了 Server 集群的概念。通過仲裁機制選舉 Leader 來領導其他 Follower。

事物都由 Leader 來處理,通過兩段提交的方式對其他 Server 發起廣播。為了增強對非事務請求的處理效率,ZooKeeper 加入了 Observer 來幫忙。

ZooKeeper 包含的內容遠不止上面說的這些,由于篇幅的原因無法一一道來。

為了方便大家理解,文中將一些原理做了簡化處理,希望有機會和大家做深入的探討,咱們下次見。

作者:崔皓

簡介:十六年開發和架構經驗,曾擔任過惠普武漢交付中心技術專家,需求分析師,項目經理,后在創業公司擔任技術/產品經理。善于學習,樂于分享。目前專注于技術架構與研發管理。

【51CTO原創稿件,合作站點轉載請注明原文作者和出處為51CTO.com】

 

責任編輯:武曉燕 來源: 51CTO技術棧
相關推薦

2018-08-13 09:20:21

NoSQLSQL數據

2017-12-17 20:17:23

NoSQLSQL數據

2019-07-01 15:01:44

NVMe接口存儲

2021-04-21 10:00:08

MySQL索引數據庫

2018-03-20 14:14:48

NB-IoT物聯網終端

2017-11-17 08:39:40

人工智能機器學習深度學習

2019-01-31 09:20:36

架構容錯架構分布式容錯

2024-02-27 14:27:16

2018-07-04 09:42:19

Docker概念容器

2019-11-07 11:08:16

Linux操作系統目錄

2019-12-06 09:16:23

Linux 開源操作系統

2022-07-21 21:19:48

元宇宙

2019-12-03 08:22:42

JWTJWSJWE

2024-02-19 00:00:00

后管系統權限

2020-10-09 08:15:11

JsBridge

2018-09-12 09:34:11

ZooKeeper概念集群

2021-08-20 16:13:40

機器學習人工智能計算機

2020-04-15 16:34:48

大數據質量標準

2019-08-22 10:07:37

SSL協議TCP

2017-09-05 08:52:37

Git程序員命令
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲精品永久免费 | 国产精品呻吟久久av凹凸 | 天堂免费 | 成人亚洲精品 | 一区二区三区国产精品 | 国产精品视频免费观看 | 蜜桃免费一区二区三区 | 欧美精品三区 | 国产成人精品在线 | 国产一区二区三区四区 | 一区二区三区亚洲 | 三级高清| 国内久久| 韩国精品一区二区三区 | 国产1区2区3区 | 久久青| 日韩福利电影 | 激情久久网 | 在线中文字幕av | 日韩精品一区二区三区视频播放 | 欧美天堂 | 欧美日韩一本 | 97影院在线午夜 | 久久精品二区亚洲w码 | 久久中文字幕一区 | 欧美一区二区三区在线免费观看 | 日韩精品在线免费 | 97视频在线观看免费 | 99久久精品视频免费 | 午夜影院在线观看免费 | 一区| 日韩欧美中文 | 欧美精品导航 | 久久久.com| 欧美日韩在线免费 | 狠狠av| 成人一区二区三区 | 成人欧美一区二区三区视频xxx | 国产精品小视频在线观看 | 91污在线| 欧美日韩综合视频 |