同是ZooKeeper,你和架構師的理解差在哪里?

前言

提到ZooKeeper,相信大家都不會陌生。DubboKafka,Hadoop等等項目里都能看到它的影子。但是你真的了解 ZooKeeper 嗎?如果面試官讓你給他講講 ZooKeeper 是個什么東西,你能回答到什么地步呢?

而且,同樣是ZooKeeper,一線架構師和你的理解又有哪些不同呢?

  • 如何從一個問題及思考方式了解架構的本質?
  • 如何剖析ZooKeeper為什么這么設計?
  • ZooKeeper到底能干嘛?

如果你已經工作了2-3年,有沒有思考過上述3個問題?

——如果有,你的答案會是?
——如果沒有,為什么?

下面,我主要介紹一下ZooKeeper是什么以及ZooKeeper的作用,前面兩個問題,我會在文末給出答案。

一、ZooKeeper是什么

ZooKeeper 是一個分布式的,開放源碼的分布式應用程序協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要組件。它是一個為分布式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分布式同步、組服務等。

官網:http://zookeeper.apache.org/
源碼:https://github.com/apache/zookeeper

ZooKeeper翻譯成中文是“動物園管理員”,至于為什么這么翻譯,感興趣的話可以去看看《從Paxos到Zookeeper 》 ,本文中很多的名詞介紹也來自本書。

三、ZooKeeper的特性

  • 順序一致性,從同一個客戶端發起的事務請求,最終將會嚴格地按照其發起順序被應用到Zookeeper中去。

  • 原子性,所有事務請求的處理結果在整個集群中所有機器上的應用情況是一致的,即整個集群要么都成功應用了某個事務,要么都沒有應用。

  • 單一視圖,無論客戶端連接的是哪個 Zookeeper 服務器,其看到的服務端數據模型都是一致的。

  • 可靠性,一旦服務端成功地應用了一個事務,并完成對客戶端的響應,那么該事務所引起的服務端狀態變更將會一直被保留,除非有另一個事務對其進行了變更。

  • 實時性,Zookeeper 保證在一定的時間段內,客戶端最終一定能夠從服務端上讀取到最新的數據狀態。

四、ZooKeeper的設計目標

  • 簡單的數據結構
    Zookeeper 使得分布式程序能夠通過一個共享的樹形結構的名字空間來進行相互協調,即Zookeeper 服務器內存中的數據模型由一系列被稱為ZNode的數據節點組成,Zookeeper 將全量的數據存儲在內存中,以此來提高服務器吞吐、減少延遲的目的。

  • 可以構建集群
    Zookeeper 集群通常由一組機器構成,組成 Zookeeper 集群的而每臺機器都會在內存中維護當前服務器狀態,并且每臺機器之間都相互通信。

  • 順序訪問
    對于來自客戶端的每個更新請求,Zookeeper 都會分配一個全局唯一的遞增編號,這個編號反映了所有事務操作的先后順序。

  • 高性能
    Zookeeper 和Redis一樣全量數據存儲在內存中,100%讀請求壓測QPS 12-13W。

五、關于 ZooKeeper 的一些重要概念

5.1 Zookeeper 集群:

Zookeeper 是一個由多個 server 組成的集群,一個 leader,多個 follower。(這個不同于我們常見的Master/Slave模式)leader 為客戶端服務器提供讀寫服務,除了leader外其他的機器只能提供讀服務。
每個 server 保存一份數據副本全數據一致,分布式讀 follower,寫由 leader 實施更新請求轉發,由 leader 實施更新請求順序進行,來自同一個 client 的更新請求按其發送順序依次執行數據更新原子性,一次數據更新要么成功,要么失敗。全局唯一數據視圖,client 無論連接到哪個 server,數據視圖都是一致的實時性,在一定事件范圍內,client 能讀到最新數據。


image

5.2 集群角色

Leader:是整個 Zookeeper 集群工作機制中的核心 。Leader 作為整個 ZooKeeper 集群的主節點,負責響應所有對 ZooKeeper 狀態變更的請求。
主要工作:

  • 事務請求的唯一調度和處理,保障集群處理事務的順序性。
  • 集群內各服務器的調度者。

Leader 選舉是 Zookeeper 最重要的技術之一,也是保障分布式數據一致性的關鍵所在。我們以三臺機器為例,在服務器集群初始化階段,當有一臺服務器Server1啟動時候是無法完成選舉的,當第二臺機器 Server2 啟動后兩臺機器能互相通信,每臺機器都試圖找到一個leader,于是便進入了 leader 選舉流程.

  1. 每個 server 發出一個投票
    投票的最基本元素是(SID-服務器id,ZXID-事物id)
  2. 接受來自各個服務器的投票
  3. 處理投票
    優先檢查 ZXID(數據越新ZXID越大),ZXID比較大的作為leader,ZXID一樣的情況下比較SID
  4. 統計投票
    這里有個過半的概念,大于集群機器數量的一半,即大于或等于(n/2+1),我們這里的由三臺,大于等于2即為達到“過半”的要求。
    這里也有引申到為什么 Zookeeper 集群推薦是單數。
集群數量 至少正常運行數量 允許掛掉的數量
2 2的半數為1,半數以上最少為2 0
3 3的半數為1.5,半數以上最少為2 1
4 4的半數為2,半數以上最少為3 1
5 5的半數為2.5,半數以上最少為3 2
6 6的半數為3,半數以上最少為4 2

通過以上可以發現,3臺服務器和4臺服務器都最多允許1臺服務器掛掉,5臺服務器和6臺服務器都最多允許2臺服務器掛掉,明顯4臺服務器成本高于3臺服務器成本,6臺服務器成本高于5服務器成本。這是由于半數以上投票通過決定的。

  1. 改變服務器狀態
    一旦確定了 leader,服務器就會更改自己的狀態,且一半不會再發生變化,比如新機器加入集群、非 leader 掛掉一臺。

Follower :是 Zookeeper 集群狀態的跟隨者。他的邏輯就比較簡單。除了響應本服務器上的讀請求外,follower 還要處理leader 的提議,并在 leader 提交該提議時在本地也進行提交。另外需要注意的是,leader 和 follower 構成ZooKeeper 集群的法定人數,也就是說,只有他們才參與新 leader的選舉、響應 leader 的提議。

Observer :服務器充當一個觀察者的角色。如果 ZooKeeper 集群的讀取負載很高,或者客戶端多到跨機房,可以設置一些 observer 服務器,以提高讀取的吞吐量。Observer 和 Follower 比較相似,只有一些小區別:首先 observer 不屬于法定人數,即不參加選舉也不響應提議,也不參與寫操作的“過半寫成功”策略;其次是 observer 不需要將事務持久化到磁盤,一旦 observer 被重啟,需要從 leader 重新同步整個名字空間。

5.3會話(Session)

Session 指的是 ZooKeeper 服務器與客戶端會話。在 ZooKeeper 中,一個客戶端連接是指客戶端和服務器之間的一個 TCP 長連接。客戶端啟動的時候,首先會與服務器建立一個 TCP 連接,從第一次連接建立開始,客戶端會話的生命周期也開始了。通過這個連接,客戶端能夠通過心跳檢測與服務器保持有效的會話,也能夠向Zookeeper 服務器發送請求并接受響應,同時還能夠通過該連接接收來自服務器的Watch事件通知。 Session 的 sessionTimeout 值用來設置一個客戶端會話的超時時間。當由于服務器壓力太大、網絡故障或是客戶端主動斷開連接等各種原因導致客戶端連接斷開時,只要在sessionTimeout規定的時間內能夠重新連接上集群中任意一臺服務器,那么之前創建的會話仍然有效。在為客戶端創建會話之前,服務端首先會為每個客戶端都分配一個sessionID。由于 sessionID 是 Zookeeper 會話的一個重要標識,許多與會話相關的運行機制都是基于這個 sessionID 的,因此,無論是哪臺服務器為客戶端分配的 sessionID,都務必保證全局唯一。

5.3.1 會話(Session)

在Zookeeper客戶端與服務端成功完成連接創建后,就創建了一個會話,Zookeeper會話在整個運行期間的生命周期中,會在不同的會話狀態中之間進行切換,這些狀態可以分為CONNECTING、CONNECTED、RECONNECTING、RECONNECTED、CLOSE等。

一旦客戶端開始創建Zookeeper對象,那么客戶端狀態就會變成CONNECTING狀態,同時客戶端開始嘗試連接服務端,連接成功后,客戶端狀態變為CONNECTED,通常情況下,由于斷網或其他原因,客戶端與服務端之間會出現斷開情況,一旦碰到這種情況,Zookeeper客戶端會自動進行重連服務,同時客戶端狀態再次變成CONNCTING,直到重新連上服務端后,狀態又變為CONNECTED,在通常情況下,客戶端的狀態總是介于CONNECTING 和CONNECTED 之間。但是,如果出現諸如會話超時、權限檢查或是客戶端主動退出程序等情況,客戶端的狀態就會直接變更為CLOSE狀態。

5.3.2 會話創建

Session是Zookeeper中的會話實體,代表了一個客戶端會話,其包含了如下四個屬性

  1. sessionID。會話ID,唯一標識一個會話,每次客戶端創建新的會話時,Zookeeper都會為其分配一個全局唯一的sessionID。
  2. TimeOut。會話超時時間,客戶端在構造Zookeeper實例時,會配置sessionTimeout參數用于指定會話的超時時間,Zookeeper客戶端向服務端發送這個超時時間后,服務端會根據自己的超時時間限制最終確定會話的超時時間。
  3. TickTime。下次會話超時時間點,為了便于Zookeeper對會話實行”分桶策略”管理,同時為了高效低耗地實現會話的超時檢查與清理,Zookeeper會為每個會話標記一個下次會話超時時間點,其值大致等于當前時間加上TimeOut。
  4. isClosing。標記一個會話是否已經被關閉,當服務端檢測到會話已經超時失效時,會將該會話的isClosing標記為”已關閉”,這樣就能確保不再處理來自該會話的心情求了。

Zookeeper為了保證請求會話的全局唯一性,在SessionTracker初始化時,調用initializeNextSession方法生成一個sessionID,之后在Zookeeper運行過程中,會在該sessionID的基礎上為每個會話進行分配,初始化算法如下

    public static long initializeNextSession(long id) {
      long nextSid = 0;
      // 無符號右移8位使為了避免左移24后,再右移8位出現負數而無法通過高8位確定sid值
      nextSid = (System.currentTimeMillis() << 24) >>> 8;
      nextSid = nextSid | (id << 56);
      return nextSid;
    }

5.3.3 會話管理

Zookeeper的會話管理主要是通過SessionTracker來負責,其采用了分桶策略(將類似的會話放在同一區塊中進行管理)進行管理,以便Zookeeper對會話進行不同區塊的隔離處理以及同一區塊的統一處理。

分捅策略

5.4 數據節點 Znode

在Zookeeper中,“節點"分為兩類,第一類同樣是指構成集群的機器,我們稱之為機器節點;第二類則是指數據模型中的數據單元,我們稱之為數據節點一一ZNode。
Zookeeper將所有數據存儲在內存中,數據模型是一棵樹(Znode Tree),由斜杠(/)的進行分割的路徑,就是一個Znode,例如/foo/path1。每個上都會保存自己的數據內容,同時還會保存一系列屬性信息。


節點
5.4.1 節點類型

在Zookeeper中,node可以分為持久節點和臨時節點和順序節點三大類。
可以通過組合生成如下四種類型節點
1. PERSISTENT
持久節點,節點創建后便一直存在于Zookeeper服務器上,直到有刪除操作來主動清楚該節點。
2. PERSISTENT_SEQUENTIAL
持久順序節點,相比持久節點,其新增了順序特性,每個父節點都會為它的第一級子節點維護一份順序,用于記錄每個子節點創建的先后順序。在創建節點時,會自動添加一個數字后綴,作為新的節點名,該數字后綴的上限是整形的最大值。
3.EPEMERAL
臨時節點,臨時節點的生命周期與客戶端會話綁定,客戶端失效,節點會被自動清理。同時,Zookeeper規定不能基于臨時節點來創建子節點,即臨時節點只能作為葉子節點。
4.EPEMERAL_SEQUENTIAL
臨時順序節點,在臨時節點的基礎添加了順序特性。

5.5 版本——保證分布式數據原子性操作

每個數據節點都具有三種類型的版本信息,對數據節點的任何更新操作都會引起版本號的變化。

version– 當前數據節點數據內容的版本號
cversion– 當前數據子節點的版本號
aversion– 當前數據節點ACL變更版本號

上述各版本號都是表示修改次數,如version為1表示對數據節點的內容變更了一次。即使前后兩次變更并沒有改變數據內容,version的值仍然會改變。version可以用于寫入驗證,類似于CAS。

5.6watcher事件監聽器

ZooKeeper允許用戶在指定節點上注冊一些Watcher,當數據節點發生變化的時候,ZooKeeper服務器會把這個變化的通知發送給感興趣的客戶端


監聽

5.7 ACL 權限控制——保障數據的安全

ACL是Access Control Lists 的簡寫, ZooKeeper采用ACL策略來進行權限控制,有以下權限:
CREATE:創建子節點的權限
READ:獲取節點數據和子節點列表的權限
WRITE:更新節點數據的權限
DELETE:刪除子節點的權限
ADMIN:設置節點ACL的權限

5.8 Paxos算法

Paxos算法是基于消息傳遞且具有高度容錯特性的一致性算法,是目前公認的解決分布式一致性問題最有效的算法之一。(其他算法有二階段提交、三階段提交等)

六、ZooKeeper 可以做什么?

  • 分布式服務注冊與訂閱

    在分布式環境中,為了保證高可用性,通常同一個應用或同一個服務的提供方都會部署多份,達到對等服務。而消費者就須要在這些對等的服務器中選擇一個來執行相關的業務邏輯,比較典型的服務注冊與訂閱,代表:dubbo。


    注冊中心
  • 分布式配置中心
    發布與訂閱模型,即所謂的配置中心,顧名思義就是發布者將數據發布到ZK節點上,供訂閱者獲取數據,實現配置信息的集中式管理和動態更新。代表:百度的disconf。
    github:https://github.com/knightliao/disconf

  • 命名服務
    在分布式系統中,通過使用命名服務,客戶端應用能夠根據指定名字來獲取資源或服務的地址,提供者等信息。被命名的實體通??梢允羌褐械臋C器,提供的服務地址,進程對象等等——這些我們都可以統稱他們為名字(Name)。其中較為常見的就是一些分布式服務框架中的服務地址列表。通過調用ZK提供的創建節點的API,能夠很容易創建一個全局唯一的path,這個path就可以作為一個名稱。

    命名

  • 分布式鎖
    分布式鎖,這個主要得益于ZooKeeper為我們保證了數據的強一致性。鎖服務可以分為兩類,一個是保持獨占,另一個是控制時序。
    所謂保持獨占,就是所有試圖來獲取這個鎖的客戶端,最終只有一個可以成功獲得這把鎖。通常的做法是把zk上的一個znode看作是一把鎖,通過create znode的方式來實現。所有客戶端都去創建 /distribute_lock 節點,最終成功創建的那個客戶端也即擁有了這把鎖。
    控制時序,就是所有視圖來獲取這個鎖的客戶端,最終都是會被安排執行,只是有個全局時序了。做法和上面基本類似,只是這里 /distribute_lock 已絆預先存在,客戶端在它下面創建臨時有序節點(這個可以通過節點的屬性控制:CreateMode.EPHEMERAL_SEQUENTIAL來指定)。Zk的父節點(/distribute_lock)維持一份sequence,保證子節點創建的時序性,從而也形成了每個客戶端的全局時序

  • Master選舉

  • 負載均衡

    負載均衡

參考

  • 《從Paxos到Zookeeper 》
  • 《ZooKeeper深入淺出 》

不知道大家是否還記的文章開頭的兩個問題,礙于本文篇幅的原因這里不再一一解答,想要了解答案,想往架構師進發的小伙伴可以加群895244712一起交流學習,視頻我已經整理好放在群文件了。

最后,如有幫助請轉發,點贊。您的拇指是對我最好的支持!

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,626評論 2 370

推薦閱讀更多精彩內容