zookeeper系列(五)zookeeper在大型分佈式系統中的應用

做者:leesf    掌控之中,纔會成功;掌控以外,註定失敗。 出處:http://www.cnblogs.com/leesf456/p/6063694.html 尊重原創感謝博主公開這麼好的博文,奇文共欣賞、你們一塊兒學習。html

1、前言node

  上一篇博文講解了Zookeeper的典型應用場景,在大數據時代,各類分佈式系統層出不窮,其中,有不少系統都直接或間接使用了Zookeeper,用來解決諸如配置管理、分佈式通知/協調、集羣管理和Master選舉等一系列分佈式問題。算法

2、 Hadoop數據庫

  Hadoop的核心是HDFS(Hadoop Distributed File System)和MapReduce,分別提供了對海量數據的存儲和計算能力,後來,Hadoop又引入了全新MapReduce框架YARN(Yet Another Resource Negotiator)。在Hadoop中,Zookeeper主要用於實現HA(High Availability),這部分邏輯主要集中在Hadoop Common的HA模塊中,HDFS的NameNode與YARN的ResourceManager都是基於此HA模塊來實現本身的HA功能,YARN又使用了Zookeeper來存儲應用的運行狀態。安全

 YARN服務器

  YARN是一種新的 Hadoop 資源管理器,它是一個通用資源管理系統,可爲上層應用提供統一的資源管理和調度,它的引入爲集羣在利用率、資源統一管理和數據共享等方面帶來了巨大好處。其能夠支持MapReduce模型,同時也支持Tez、Spark、Storm、Impala、Open MPI等網絡

YARN主要由ResourceManager(RM)、NodeManager(NM)、ApplicationManager(AM)、Container四部分構成。其中,ResourceManager爲全局資源管理器,負責整個系統的資源管理和分配。由YARN體系架構能夠看到ResourceManager的單點問題,ResourceManager的工做情況直接決定了整個YARN架構是否能夠正常運轉。數據結構

ResourceManager HA架構

  爲了解決ResourceManager的單點問題,YARN設計了一套Active/Standby模式的ResourceManager HA架構。併發

由上圖可知,在運行期間,會有多個ResourceManager並存,而且其中只有一個ResourceManager處於Active(活動)狀態,另一些(容許一個或者多個)則處於Standby(備用)狀態,當Active(活動)節點沒法正常工做時,其他處於Standby(備用)狀態的節點則會經過競爭選舉產生新的Active節點。

主備切換

  ResourceManager使用基於Zookeeper實現的ActiveStandbyElector組件來肯定ResourceManager的狀態。具體步驟以下

  1. 建立鎖節點。在Zookeeper上會有一個相似於/yarn-leader-election/pseudo-yarn-rm-cluster的鎖節點,全部的ResourceManager在啓動時,都會去競爭寫一個Lock子節點(/yarn-leader-election/pseudo-yarn-rm-cluster/ActiveStandbyElectorLock),子節點類型爲臨時節點,利用Zookeeper的特性,建立成功的那個ResourceManager切換爲Active狀態,其他的爲Standby狀態。

       2. 註冊Watcher監聽。全部Standby狀態的ResourceManager都會向/yarn-leader-election/pseudo-yarn-rm-cluster/ActiveStandbyElectorLock節點註冊一個節點變動監聽,利用臨時節點的特性,可以快速感知到Active狀態的ResourceManager的運行狀況。

       3. 主備切換。當Active的ResourceManager沒法正常工做時,其建立的Lock節點也會被刪除,此時,其他各個Standby的ResourceManager都會收到通知,而後重複步驟1。

隔離(Fencing)

  在分佈式環境中,常常會出現諸如單機假死(機器因爲網絡閃斷或是其自身因爲負載太高,常見的有GC佔用時間過長或CPU負載太高,而沒法正常地對外進行及時響應)狀況。假設RM集羣由RM1和RM2兩臺機器構成,某一時刻,RM1發生了假死,此時,Zookeeper認爲RM1掛了,而後進行主備切換,RM2會成爲Active狀態,可是在隨後,RM1恢復了正常,其依然認爲本身還處於Active狀態,這就是分佈式腦裂現象,即存在多個處於Active狀態的RM工做,可使用隔離來解決此類問題。

  YARN引入了Fencing機制,藉助Zookeeper的數據節點的ACL權限控制機制來實現不一樣RM之間的隔離。在上述主備切換時,多個RM之間經過競爭建立鎖節點來實現主備狀態的肯定,此時,只須要在建立節點時攜帶Zookeeper的ACL信息,目的是爲了獨佔該節點,以防止其餘RM對該節點進行更新。

仍是上述案例,若RM1出現假死,Zookeeper會移除其建立的節點,此時RM2會建立相應的鎖節點並切換至Active狀態,RM1恢復以後,會試圖去更新Zookeeper相關數據,可是此時其沒有權限更新Zookeeper的相關節點數據,由於節點不是由其建立的,因而就自動切換至Standby狀態,這樣就避免了腦裂現象的出現。

ResourceManager狀態存儲

  在ResourceManager中,RMStateStore能夠存儲一些RM的內部狀態信息,包括Application以及Attempts信息、Delegation Token及Version Information等,值得注意的是,RMStateStore的絕大多數狀態信息都是不須要持久化存儲的(如資源使用狀況),由於其很容易從上下文信息中重構,,在存儲方案設計中,提供了三種可能的實現。

  1. 基於內存實現,通常用於平常開發測試。

  2. 基於文件系統實現,如HDFS。

  3. 基於Zookeeper實現。

  因爲存儲的信息不是特別大,Hadoop官方建議基於Zookeeper來實現狀態信息的存儲,在Zookeeper中,ResourceManager的狀態信息都被存儲在/rmstore這個根節點下,其數據結構以下。

在RMAppRoot節點下存儲的是與各個Application相關的信息,RMDTSecretManagerRoot存儲的是與安全相關的Token信息。每一個Active狀態的ResourceManager在初始化節點都會從Zookeeper上讀取到這些信息,並根據這些狀態信息繼續後續的處理。

3、HBase

  HBase(Hadoop Database)是一個基於Hadoop的文件系統設計的面向海量數據的高可靠、高性能、面向列、可伸縮的分佈式存儲系統,其針對數據寫入具備強一致性,索引列也實現了強一致性,其採用了Zookeeper服務來完成對整個系統的分佈式協調工做,其架構以下

 

HBase架構中,Zookeeper是串聯起HBase集羣與Client的關鍵所在,Zookeeper在HBase中的系統容錯、RootRegion管理、Region狀態管理、分佈式SplitLog任務管理、Replication管理都扮演重要角色

  系統容錯(使用zookeeper自動選舉主服務的性質容錯)

  在HBase啓動時,每一個RegionServer服務器都會到Zookeeper的/hbase/rs節點下建立一個信息節點,例如/hbase/rs/[Hostname],同時,HMaster會對這個節點進行監聽,當某個RegionServer掛掉時,Zookeeper會由於在一段時間內沒法接收其心跳信息(Session失效),而刪除掉該RegionServer服務器對應的節點,與此同時,HMaster則會接收到Zookeeper的NodeDelete通知,從而感知到某個節點斷開,並當即開始容錯工做,HMaster會將該RegionServer所處理的數據分片(Region)從新路由到其餘節點上,並記錄到Meta信息中供客戶端查詢。

RootRegion管理(zookeeper的znode節點註冊 Watcher監聽來管理rootRegion)

  數據存儲的位置信息是記錄在元數據分片上的,即在RootRegion上,每次客戶端發起新的請求,就會查詢RootRegion來肯定數據的位置,而RootRegion自身的位置則記錄在Zookeeper上(默認狀況下在/hbase/root-region-server節點中)。當RootRegion發生變化時,如Region手工移動、Balance或者是RootRegion所在服務器發生了故障,就能經過Zookeeper來感知到這一變化並作出一系列相應的容災措施,從而保障客戶端總可以拿到正確的RootRegion信息。

Region狀態管理

  Region是HBase中數據的物理切片,每一個Region記錄了全局數據的一小部分,而且不一樣的Region之間的數據是相互不重複的。但對於一個分佈式系統來講,Region是會發生變動的,緣由多是系統故障、負載均衡、配置修改、Region分裂合併等,一旦Region發生變更,它必然經歷離線和從新在線的過程。在離線期間,數據是不能被訪問的,而且Region的狀態變化必須讓全局知曉,不然可能會出現某些事務性的異常,而對於HBase集羣而言,Region的數量可能會多達10萬級別,所以這樣規模的Region狀態管理只有依靠Zookeeper才能作到。

分佈式SplitLog任務管理(zookeeper節點的相互通知)

  當某臺RegionServer服務器掛掉後,因爲總有一部分新寫入的數據尚未持久化到HFile中(在內存中),所以在遷移該RegionServer的服務時,應該從HLog中恢復這部分還在內存中的數據,此時HMaster須要遍歷該RegionServer服務器的HLog(SplitLog),並按照Region切分紅小塊移動到新的地址,並進行數據的Replay。因爲單個RegionServer的日誌量相對龐大(可能存在上千個Region,上GB的日誌),而用戶每每但願系統可以快速完成日誌的恢復工做,所以,須要將處理HLog的任務分配給多臺RegionServer服務器共同處理,而這又須要一個持久化組件來輔助HMaster完成任務的分配,當前作法以下,HMaster會在Zookeeper上建立一個splitlog節點(默認爲/hbase/splitlog節點),將"哪一個RegionServer處理哪一個Region"的信息以列表的形式存放在該節點上,而後由各個RegionServer服務器自行到該節點上去領取任務並在任務執行成功或失敗後再更新該節點的信息以通知HMaster繼續後續步驟,Zookeeper起到了相互通知和信息持久化的角色。

Replication管理

  Replication是實現HBase中主備集羣間的實時同步的重要模塊,與傳統關係型數據庫不一樣的是,HBase的Replication是多對多的,且每一個節點隨時都有可能掛掉,所以其會複雜得多。HBase也藉助了Zookeeper來完成Replication功能,作法是在Zookeeper上記錄一個replication節點(默認是/hbase/replication節點),而後把不一樣的RegionServer服務器對應的HLog文件名稱記錄到相應的節點上,HMaster集羣會將新增的數據推送給Slave集羣,並同時將推送信息記錄到Zookeeper上(稱爲斷點記錄),而後重複上述步驟,當服務器掛掉時,因爲Zookeeper上已經保存了斷點信息,所以只要有HMaster可以根據這些信息來協同用來推送HLog數據的主節點服務器就能夠進行繼續複製操做。

4、Kafka

  kafka是一個吞吐量極高的分佈式消息系統,其總體設計是典型的發佈與訂閱系統模式,在Kafka集羣中,沒有中心主節點概念,全部服務器都是對等的,所以,能夠在不作任何配置更改的狀況下實現服務器的添加與刪除,一樣,消息的生產者和消費者也可以隨意重啓和機器的上下線。

       生產者(Producer):消息產生的源頭,負責生成消息併發送到Kafka服務器。

  消費者(Consumer):消息的使用方,負責消費Kafka服務器上的消息。

  主題(Topic):由用戶定義並配置在Kafka服務端,用於創建生產者和消費者之間的訂閱關係,生產者發送消息到指定Topic下,消費者從這個Topic中消費消息。

  消息分區(Partition):一個Topic下會分爲多個分區,如"kafka-test"這個Topic能夠分爲10個分區,分別由兩臺服務器提供,那麼一般能夠配置讓每臺服務器提供5個分區,假設服務器ID爲0和1,那麼分區爲0-0、0-一、0-二、0-三、0-4和1-0、 1-一、1-二、1-三、1-4。消息分區機制和分區的數量與消費者的負載均衡機制有很大的關係。

  服務器(Broker):用於存儲信息,在消息中間件中一般被稱爲Broker。

  消費者分組(Group):歸組同類消費者,多個消費者能夠共同消費一個Topic下的消息,每一個消費者消費其中的部分消息,這些消費者組成了消費者分組,擁有同一個分組名稱,一般也被稱爲消費者集羣。

  偏移量(Offset):消息存儲在Kafka的Broker上,消費者拉取消息數據的過程當中須要知道消息在文件中的偏移量。

  Broker註冊

  Broker是分佈式部署而且相互之間相互獨立,可是須要有一個註冊系統可以將整個集羣中的Broker管理起來,此時就使用到了Zookeeper。在Zookeeper上會有一個專門用來進行Broker服務器列表記錄的節點/brokers/ids。每一個Broker在啓動時,都會到Zookeeper上進行註冊,即到/brokers/ids下建立屬於本身的節點,如/brokers/ids/[0...N]。Kafka使用了全局惟一的數字來指代每一個Broker服務器,不一樣的Broker必須使用不一樣的Broker ID進行註冊,建立完節點後,每一個Broker就會將本身的IP地址和端口信息記錄到該節點中去。其中,Broker建立的節點類型是臨時節點,一旦Broker宕機,則對應的臨時節點也會被自動刪除。

  Topic註冊

  在Kafka中,同一個Topic的消息會被分紅多個分區並將其分佈在多個Broker上,這些分區信息及與Broker的對應關係也都是由Zookeeper在維護,由專門的節點來記錄,如/borkers/topics。Kafka中每一個Topic都會以/brokers/topics/[topic]的形式被記錄,如/brokers/topics/login和/brokers/topics/search等。Broker服務器啓動後,會到對應Topic節點(/brokers/topics)上註冊本身的Broker ID並寫入針對該Topic的分區總數,如/brokers/topics/login/3->2,這個節點表示Broker ID爲3的一個Broker服務器,對於"login"這個Topic的消息,提供了2個分區進行消息存儲,一樣,這個分區節點也是臨時節點。

  生產者負載均衡

  因爲同一個Topic消息會被分區並將其分佈在多個Broker上,所以,生產者須要將消息合理地發送到這些分佈式的Broker上,那麼如何實現生產者的負載均衡,Kafka支持傳統的四層負載均衡,也支持Zookeeper方式實現負載均衡。

  ① 四層負載均衡,根據生產者的IP地址和端口來爲其肯定一個相關聯的Broker。一般,一個生產者只會對應單個Broker,而後該生產者產生的消息都發往該Broker。這種方式邏輯簡單,每一個生產者不須要同其餘系統創建額外的TCP鏈接,只須要和Broker維護單個TCP鏈接便可。可是,其沒法作到真正的負載均衡,由於實際系統中的每一個生產者產生的消息量及每一個Broker的消息存儲量都是不同的,若是有些生產者產生的消息遠多於其餘生產者的話,那麼會致使不一樣的Broker接收到的消息總數差別巨大,同時,生產者也沒法實時感知到Broker的新增和刪除。

  ② 使用Zookeeper進行負載均衡,因爲每一個Broker啓動時,都會完成Broker註冊過程,生產者會經過該節點的變化來動態地感知到Broker服務器列表的變動,這樣就能夠實現動態的負載均衡機制。

  消費者負載均衡

  與生產者相似,Kafka中的消費者一樣須要進行負載均衡來實現多個消費者合理地從對應的Broker服務器上接收消息,每一個消費者分組包含若干消費者,每條消息都只會發送給分組中的一個消費者,不一樣的消費者分組消費本身特定的Topic下面的消息,互不干擾。

  消費分區與消費者的關係

  對於每一個消費者分組,Kafka都會爲其分配一個全局惟一的Group ID,同一個消費者分組內部的全部消費者共享該ID。同時,Kafka爲每一個消費者分配一個Consumer ID,一般採用"Hostname:UUID"形式表示。在Kafka中,規定了每一個消息分區有且只能同時有一個消費者進行消費,所以,須要在Zookeeper上記錄消息分區與消費者之間的關係,每一個消費者一旦肯定了對一個消息分區的消費權力,須要將其Consumer ID 寫入到對應消息分區的臨時節點上,例如/consumers/[group_id]/owners/[topic]/[broker_id-partition_id],其中,[broker_id-partition_id]就是一個消息分區的標識,節點內容就是該消費分區上消息消費者的Consumer ID。

  消息消費進度Offset記錄

  在消費者對指定消息分區進行消息消費的過程當中,須要定時地將分區消息的消費進度Offset記錄到Zookeeper上,以便在該消費者進行重啓或者其餘消費者從新接管該消息分區的消息消費後,可以從以前的進度開始繼續進行消息消費。Offset在Zookeeper中由一個專門節點進行記錄,其節點路徑爲/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id],節點內容就是Offset的值。

  消費者註冊

  消費者服務器在初始化啓動時加入消費者分組的步驟以下

  ① 註冊到消費者分組。每一個消費者服務器啓動時,都會到Zookeeper的指定節點下建立一個屬於本身的消費者節點,例如/consumers/[group_id]/ids/[consumer_id],完成節點建立後,消費者就會將本身訂閱的Topic信息寫入該臨時節點。

  ② 對消費者分組中的消費者的變化註冊監聽。每一個消費者都須要關注所屬消費者分組中其餘消費者服務器的變化狀況,即對/consumers/[group_id]/ids節點註冊子節點變化的Watcher監聽,一旦發現消費者新增或減小,就觸發消費者的負載均衡。

  ③ 對Broker服務器變化註冊監聽。消費者須要對/broker/ids/[0-N]中的節點進行監聽,若是發現Broker服務器列表發生變化,那麼就根據具體狀況來決定是否須要進行消費者負載均衡。

  ④ 進行消費者負載均衡。爲了讓同一個Topic下不一樣分區的消息儘可能均衡地被多個消費者消費而進行消費者與消息分區分配的過程,一般,對於一個消費者分組,若是組內的消費者服務器發生變動或Broker服務器發生變動,會發出消費者負載均衡。

  負載均衡

  Kafka藉助Zookeeper上記錄的Broker和消費者信息,採用消費者均衡算法進行負載均衡,其具體步驟以下。假設一個消息分組的每一個消費者記爲C1,C2,Ci,...,Cn。那麼對於消費者Ci,其對應的消息分區分配策略以下:

  1. 設置Pr爲指定Topic全部的消息分區。

  2. 設置Cg爲統一消費者分組中的全部消費者。

  3. 對Pr進行排序,使分佈在同一個Broker服務器上的分區儘可能靠在一塊兒。

  4. 對Cg進行排序。

  5. 設置i爲Ci在Cg中的位置索引,同時設置N = size (Pr) / size (Cg)。

  6. 將編號爲i * N ~ (i + 1) * N - 1的消息分區分配給Ci。

  7. 從新更新Zookeeper上消息分區與消費者Ci的關係。

5、總結

  本篇博客講解了Zookeeper在大型分佈式系統中的應用,也體現了Zookeeper做爲一款分佈式協調器的優秀特色,至於Zookeeper在各個系統的詳細應用,讀者能夠自行查閱資料。

相關文章
相關標籤/搜索