《從Paxos到ZooKeeper 分佈式一致性原理與實踐》讀書筆記

1、分佈式架構

一、分佈式特色

  • 分佈性
  • 對等性。分佈式系統中的全部計算機節點都是對等的
  • 併發性。多個節點併發的操做一些共享的資源
  • 缺少全局時鐘。節點之間經過消息傳遞進行通訊和協調,由於缺少全局時鐘,很難定義兩個事件誰先誰後
  • 故障老是會發生。系統設計時,須要考慮到任何異常狀況

二、分佈式環境的各類問題

  • 通訊異常。分佈式系統中的某些節點之間沒法正常通訊
  • 網絡分區。這有部分節點能夠正常通訊,有些沒法正常通訊。這種現象稱爲網絡分區,也稱爲「腦裂」
  • 三態。節點之間的一次通訊存在三種狀態:成功、失敗、超時
  • 節點故障。節點機器宕機、失去迴應

三、傳統事務的ACID理論。

  • 原子性(Atomicity)。事務內的全部操做要麼所有成功,要麼所有失敗
  • 一致性(Consistency)。事務的執行不能破壞數據庫的一致性。若是事務執行一半停了,一部分的修改寫入的數據庫。這時候,數據庫就處於一種不正確的狀態,或者說不一致的狀態
  • 隔離性(Isolation)。多個事務併發執行,彼此不會受影響。事務的隔離級別:讀未提交(可能發生髒讀、重複讀、幻象讀)、讀已提交(肯能發生重複讀、幻象讀)、可重複讀(可能發生幻象讀)、串行化。隔離級別越高,對併發的性能影響越大,越能保證數據庫的一致性。
  • 持久性(Durablility)。一旦事務成功提交,它對於數據的修改就被永久保存下來

四、分佈式事務的CAP理論和BASE理論

  • CAP理論。一致性(Consistency)、可用性(Availability)、分區容錯性(Partition tolerance),在分佈式系統中,最多隻能知足其中的兩項。
  • BASE理論。基本可用(Basically Available)、軟狀態(Soft state)、最終一致性(Eventually consistent)。基本可用指系統出現故障時,容許損失部分可用性,包括響應時間的損失和功能上的系統降級;軟狀態指容許節點間的通信出現中間狀態;最終一致指系統的全部的數據副本,在必定時間的同步後,最終可以達到一致的狀態

2、一致性協議

一、2PC。二階段提交協議

階段一,執行事務node

  • 事務詢問。協調者向全部參與者發送事務內容,等待參與者迴應
  • 執行事務。參與者執行事務,記錄Undo和Redo日誌
  • 反饋事務詢問響應,參與者返回給協調者Yes或No響應。所有返回Yes,進入提交事務階段;存在No返回或者超時,進入中斷事務階段

階段二,提交事務git

  • 發送事務提交請求
  • 各個參與者提交事務
  • 參與者反饋事務提交結果
  • 若是參與者所有返回Yes,完成事務;存在返回No,進入中斷事務階段

中斷事務階段github

  • 發送回滾請求
  • 事務回滾
  • 反饋事務回滾結果
  • 完成中斷事務

2PC的缺點算法

  • 同步阻塞。各個參與者在等待其餘參與者響應的同時,沒法進行任何操做,處於阻塞狀態
  • 單點問題。過分依賴協調者,一旦協調者出現問題,系統將沒法正常運轉
  • 數據不一致。同上一條,一旦協調者出現問題,就可能出現各個參與者數據不一致的問題
  • 太過保守。一旦參與者出現故障,協調者只能經過本身的超時機制發現。

二、3PC。三階段提交協議

 階段一,CanCommit,事務詢問數據庫

  • 事務詢問,詢問各個參與者可否完成事務
  • 各個參與者返回響應,所有返回Yes,進入PreCommit階段

階段二,PreCommit,事務預提交apache

  • 發送預提交請求
  • 事務預提交。參與者執行事務操做,記錄Undo和Redo日誌
  • 參與者返回響應。所有返回Yes,繼續三階段;返回No,進入中斷事務階段

階段三,DoCommit,真正的事務提交編程

  • 發送提交請求
  • 參與者正式執行事務提交操做
  • 返回協調者事務執行結果
  • 協調者完成事務。若是存在返回No或者返回超時,進入中斷事務階段

中斷事務階段緩存

  • 發送回滾請求
  • 事務回滾
  • 反饋事務回滾結果
  • 完成中斷事務

3PC優缺點服務器

  • 優勢是下降了阻塞範圍,在等待超時後協調者或參與者會中斷事務。避免了協調者單點問題,階段3中協調者出現問題時,參與者會繼續提交事務。
  • 缺點是,仍是避免不了出現數據不一致的狀況

三、Paxos算法

拜占庭將軍問題,拜占庭帝國的不一樣軍隊處於不一樣的地理問題,他們之間只能經過通信員進行通信,可是通信員是不可靠的,可能篡改消息網絡

因爲加密算法和校驗算法的出現,全部實際的分佈式系統之間的通信,不存在數據被篡改的可能。

4、ZooKeeper和ZAB協議介紹

一、初識ZeeKeeper

ZooKeeper能夠作什麼

能夠基於它實現負載均衡、集羣管理、Master選舉、分佈式隊列、分佈式鎖、命名服務、數據發佈/訂閱等功能

Zookeeper能保證的分佈式一致性特性

  • 順序一致性。同一個客戶端發起的請求,會嚴格按照發起順序執行
  • 原子性。對於一個事務請求,集羣中的全部機器的執行狀況是一致的
  • 可靠性。一旦服務端成功的應用了一個事務,並完成了對客戶端的響應。服務端的狀態會一直保存下來
  • 實時性。保證在一段時間內的實時性
  • 單一視圖。不管客戶端鏈接的是哪個服務器,看到的服務端的數據模型都是一致的

Zookeeper的設計目標

  • 簡單的數據模型。Zookeeper將去數據存儲在內存中,採用樹形結構存儲,樹由ZNode節點構成
  • 能夠構建集羣。只有集羣中超過一半機器可以正常運做,整個集羣就能夠正常對外提供服務。
  • 順序訪問。每一個來自客戶端的請求,都會分配一個全局惟一的遞增編號
  • 高性能。全量數據存儲在內存中,3臺3.4.3的Zookeeper集羣,100%讀請求場景的壓測結果是12-13W的QPS

Zookeeper的基本概念

  • 集羣角色。存在Leader、Follower、Observer三種角色。Leader服務器提供讀和寫服務,Follower和Observer提供讀服務,可是Observer不參與選舉過程,也不參與寫操做的「過半寫」策略,所以,Observer能夠在不影響寫性能的狀況下提升讀性能
  • 客戶端會話。客戶端經過TCP長鏈接和服務端相連,第一次創建鏈接就表明客戶單會話開始了。客戶端可以經過心跳檢測與服務器保持有效的會話。Session的SessionTimeout值用來設置會話的超時時間,鏈接斷開後,只要在超時時間以內從新鏈接上了集羣中的任何一臺服務器,那麼以前建立的會話仍然有效
  • 節點。一方面只集羣中的每一臺機器,稱爲機器節點;另外一方面指數據模型中的數據單元,稱爲數據節點Znode。Znode又分爲持久節點和臨時節點,臨時節點的生命週期和會話綁定,一旦客戶端會話失效,那麼這個客戶端建立的全部臨時節點都會被移除。
  • 版本。每一個Znode,會維護一個叫作Stat的數據結構,記錄了Znode的三個版本:version(當期版本)、cversion(當前Znode子節點的版本)、aversion(當前Znode的ACL版本)。
  • Watcher。事件監聽器,容許用戶在一些節點上註冊一些watcher。特性事件觸發的時候,服務器會將事件通知到感興趣的客戶端上去。
  • ACL。權限控制策略(Access Control Lists)。定義了五種權限:Create(建立子節點)、Delete(刪除子節點)、read(讀取節點數據和子節點列表)、write(更新節點數據)、admin(設置節點ACL的權限)

二、ZAB協議(Zookeeper Atomic Broadcast,原子消息廣播協議)

全部事務請求都由Leader服務器來處理分發,若是集羣中的其餘服務器收到了來自客戶端的請求,這些非Leader服務器會首先將這個事務請求轉發給Leader服務器,Leader負責將請求封裝成Proposal(提議)分發給集羣中全部Follower,一旦收到超過半數的正確反饋,Leader就會再次向全部的Follower分發Commit消息,要求他們將前一個Prosocal提交

兩種基本模式:崩潰恢復模式和消息廣播模式

  • 消息廣播模式。相似於二階段提交,去掉了中斷邏輯,當Leader服務器收到了超過半數的Follower的ACK響應後,就會廣播一個Commit消息給全部的Follower進行事務提交。
  • 崩潰恢復。一旦Leader服務器出現崩潰,或者因爲網絡緣由失去了一半Follower服務器的聯繫,就會進入崩潰恢復模式。
  • 崩潰恢復須要確保已經被Leader提交的Proposal也能被全部Follower提交
  • 確保丟棄只在Leader服務器上提出的事務。(此處的提出指的是二階段第一階段)。從新選舉出來的Leader擁有集羣中全部服務器最高編號的事務Proposal
  • 正常狀況的數據同步:Leader服務器爲每個Follower服務器準備一個隊列,將那些沒有被Follower服務器同步的事務以Proposal消息的形式逐個發送給Follower,等待全部事務都同步到了Follower併成功應用到了Follower的本地數據庫中後,Leader服務器就將該Follower服務器加入到真正的可用列表中
  • 事務編號ZXID,是一個64位的數字。前32位存儲Leader屆數,後32位記錄本屆Leader處理的消息數。

三、深刻ZAB協議

運行分析,每個進程都有可能處於如下三種狀態之一

  • LOOKING:leader選舉階段
  • FOLLOWING:Follower服務器和Leader服務器保持同步狀態
  • LEADING:Leader服務器做爲主進程領導狀態

5、使用Zookeeper

一、服務端部署與運行

  • 初次使用,須要把/conf目錄下的zoo_sample.cfg文件重命名爲zoo.cfg。配置以下:
  • server.1=IP1:2888:3888,每一行這樣的配置表明一個集羣中的一個機器,server.1中的1表明ServerID,同時在每臺機器上須要在數據目錄(dataDir指定的目錄)下建立一個myid文件,文件內容就是ServerID,id範圍是1~255
  • 集羣中每一個機器的zoo.cfg文件都應該是相同的,最好使用git或者svn把配置管理起來
  • 啓動服務。/bin/zhServer.sh  start
  • 中止服務。/bin/zkServer.sh stop

二、客戶端腳本

  • 啓動。/bin/zkCli.sh  -server ip:port(不加server參數,默認鏈接本機)
  • 建立節點。create 【-s】【-e】path data acl。acl用來進行權限控制
  • 讀取節點下子節點。ls path。例如:ls /  查看根節點下的全部子節點
  • 讀取節點數據。get path
  • 更新節點數據。set path data 【version】
  • 刪除節點。delete path 【version】。沒法刪除一個包含子節點的節點

三、開源客戶端Curator的使用

直接看個人github代碼:https://github.com/leon66666/zookeeper-client

6、Zookeeper的典型應用場景

一、典型應用場景及實現

(1)數據發佈和訂閱

分爲推(push)模式和拉(pull)模式,push模式服務端主動把數據更新推送給全部訂閱的客戶端,而拉模式是由客戶端定時輪詢拉取的方式來獲取最新數據

應用場景:分佈式系通通一配置,例如機器列表信息、運行時的開關配置、數據庫配置信息等,這些全局配置交給Zookeeper統一管理

這些配置具備如下特色:

  • 數據量一般比較小
  • 數據內容在運行時動態變化
  • 集羣中各機器共享,配置一致

(2)負載均衡

DDNS,動態DNS解析。局域網內部通常採用host綁定的方式來進行ip和域名的映射。一旦機器規模變大,這種作法就會至關的不方便。

經過Zookeeper實現,每一個應用均可以建立一個屬於本身的數據節點做爲域名配置的根節點,在這個節點上,每一個應用均可以將本身的域名配置上去。經過註冊Watcher實現域名變動通知功能。

上圖爲總體的DDNS系統架構。

  • Register集羣負責域名的動態註冊。每一個服務者啓動的時候,都會把本身的域名信息註冊到Register集羣中去。
  • Dispatcher集羣負責域名的解析。服務消費者在使用域名的時候,會向Dispatcher集羣發出請求,獲取相應的IP:PORT信息。
  • Scanner集羣負責檢測及維護服務狀態(探測服務可用性、屏蔽異常服務節點)。(一種是心跳檢測,須要客戶端和服務端創建起tcp長鏈接。另外一種是服務端主動進行狀態彙報,一旦超過5秒沒有收到彙報,就認爲該IP地址不可用,進行域名清理)
  • SDK,提供各個語言的系統接入
  • Monitor負責收集集羣信息以及對DDNS自身的監控
  • Controller是一個後臺管理,負責受權管理、流量控制、服務配置和手動屏蔽服務等功能。

(3)命名服務

即分佈式環境下,生成全局惟一ID的方法。你們通常會聯想到UUID,是通用惟一識別碼的簡稱。主流ORM框架HIbernate就有對UUID的直接支持。

可是,UUID有以下缺點:

  • 長度過長,須要更多的存儲空間
  • 含義不明,根據字符串開發人員從字面上根本看不出他的含義

利用Zookeeper來實現這類全局惟一ID的生成。當客戶端建立一個順序子節點的時候,zookeeper會自動之後綴的形式在其子節點上添加一個序號,利用了zookeeper順序節點的特性

(4)分佈式協調/通知

Zookeeper實現分佈式協調通知,一般的作法是不一樣的客戶端都對Zookeeper上同一個數據節點進行Watcher註冊。監聽節點數據的變化。

(5)通用的分佈式系統機器間通訊方法

分佈西系統機器間通訊包括:心跳檢測、工做進度報告、系統調度

  • 心跳檢測。不一樣機器之間須要檢測到彼此是否正常運行。傳統方法經過機器之間可否互相ping通來判斷;更復雜的經過機器之間創建起Tcp長鏈接,經過tcp固有的心跳檢測機制來實現上層機器的心跳檢測;基於Zookeeper的臨時節點特性也能夠實現心跳檢測,不一樣的機器在指定節點下建立臨時節點,不一樣機器能夠經過判斷臨時節點是否存在來判斷客戶端機器是否存活。減小了系統耦合
  • 工做進度報告。每一個客戶端建立臨時子節點,各個任務機器會實時的將本身的執行進度存儲到對應的子節點上,也能夠判斷子節點是否存在判斷機器是否存活
  • 系統調度。一個分佈式系統由控制檯和客戶端組成。後臺管理人員在控制檯作一些操做(實際上就是修改Zookeeper上某些節點的數據),Zookeeper以事件通知的形式發送給對應的訂閱客戶端

(6)集羣管理

集羣管理需求點

  • 知道集羣中工做的機器數量
  • 對集羣中每臺機器的運行狀態進行收集
  • 對集羣中的機器進行上下線操做

傳統的基於agent的管理方式,集羣中每臺機器部署一個agent,負責本機器的監控和向中心繫統彙報

  • 大規模升級困難
  • 統一的agent沒法知足多樣的需求。沒法深刻應用內部,對一些業務狀態進行監控
  • 編程語言多樣性。不一樣機器須要提供不一樣語言的agent

利用zookeeper監控集羣

  • 客戶端能夠對zookeeper節點進行監聽,節點變動會受到通知
  • 在zookeeper上建立臨時節點,一旦會話失效,改臨時節點會被自動刪除
  • 監控系統在/clusterServers節點上註冊一個Watcher監聽,添加機器會在監聽節點下建立臨時子節點。

zookeeper監控應用:分佈式日誌收集系統

  • 註冊收集器機器。以/logs/controller做爲收集器的根節點,每一個收集器啓動的時候都會在收集器節點下建立本身的節點
  • 任務分發。收集系統把日誌源機器按照必定策略分配給註冊的收集器機器,將機器列表寫入到對應的收集器節點上
  • 狀態彙報。收集器節點下面建立狀態子節點,每一個註冊的收集器機器定時向該節點寫入本身的狀態信息和日誌收集進度信息(能夠看作是一種心跳檢測),根據更新時間來判斷是否存活
  • 動態分配。檢測到收集器的減小或者增長以後,須要進行從新分配。一般有兩種作法:全局分配(影響面大);局部動態分配(低負載優先分配)
  • 節點類型。收集器節點,需使用持久節點,須要保存該節點上的日誌源機器列表
  • 收集器節點監聽。放棄監聽設置,採用按期輪詢,節省網卡流量,可是具備一些延時,考慮到日誌收集需求,延時是能夠接受的

 (7)Master選舉

在集羣的全部機器中選舉出一臺機器做爲master

  • 能夠經過數據庫的主鍵惟一特性來實現。可是當選舉出的master掛了以後,數據庫沒法通知咱們這個事件
  • 利用zookeeper的強一致性,客戶端沒法建立一個已經存在的節點。其餘沒有成功建立這個節點的客戶端會在這個節點上註冊一個子節點變動的watcher,一旦發現當前的master掛了,其他客戶端會從新進行選舉

(8)分佈式鎖

最多見的是用數據庫實現。例如行鎖,表鎖,事務處理,樂觀鎖等等。可是每每分佈式系統的性能瓶頸都集中在數據庫的操做上。

  • 排它鎖。選擇一個節點做爲鎖節點,客戶端加鎖的時候會在鎖節點先建立臨時子節點,利用zookeeper特性,只有一個客戶端可以建立成功,其他客戶端註冊鎖節點的子節點變動的Watcher監聽,在持有鎖的客戶端主動刪除臨時節點或者因爲宕機致使會話超時致使臨時節點被移除,都表示鎖被釋放了。其餘監聽的客戶端會再次發起分佈式鎖獲取
  • 共享鎖。在鎖節點下建立臨時順序節點。讀節點爲R+序號,寫節點爲W+序號。建立完節點後,獲取全部子節點,對鎖節點註冊子節點變動的watcher監聽,肯定本身的序號在全部子節點中的位置。對於讀請求,沒有比本身序號小的寫節點,就表示得到了共享鎖,執行讀取邏輯。對於寫請求,若是本身不是序號最小的子節點,就須要進入等待。接收到watcher通知後,重複獲取鎖。
  • 共享鎖羊羣效應。大量的watcher通知和子節點列表獲取,兩個操做重複運行。集羣規模比較大的狀況下,會對zookeeper服務器形成巨大的性能影響和網絡衝擊
  • 改進後的共享鎖。讀請求,監聽比本身小的寫節點。寫請求,監聽比本身小的最後一個節點。
  • 具體選用哪一種實現的共享鎖,視集羣規模而定

(9)分佈式隊列

  •  常規的先入先出隊列。經過臨時順序節點實現。【2】經過getChildren()接口獲取隊列節點下的全部子節點,若是本身不是序號最小的子節點,進入等待,向比本身序號小的最後一個節點註冊watcher監聽。收集通知後,重複步驟【2】
  • Barrier模型。屏障節點的數據內容存儲n表明Barrier值。全部的客戶端都會在屏障節點下建立臨時節點,建立完畢獲取屏障節點內容,【2】獲取全部子節點,註冊對子節點列表變動的watcher監聽,統計子節點個數,不足barrier值,進入等待,收到watcher通知,重複步驟【2】

二、zookeeper在大型分佈式系統中的應用

(1)hadoop。大型分佈式計算框架

  • 核心包括HDFS和MapReduce,分別提供了對海量數據的存儲和計算能力。0.23.0版本開始,Hadoop又引入了全新一代MapReduce框架YARN。
  • YARN是爲了提升計算節點Master的擴展性,引入的全新一代分佈式調度框架。支持多個計算引擎,包括MapReduce、Spark、Storm等
  • YARN中最核心的ResourceManager,做爲全局的資源管理器,負責整個系統的資源管理和分配。存在單點問題,使用Active/Standby模式,解決單點問題。只有一臺處理Active狀態,其餘處於Standby狀態,當Active節點掛掉以後,其他Standby節點會經過競爭選舉產生新的Active節點
  • zookeeper實現Active/Standby模式。相似於master選舉,啓動的時候都會去建立一個臨時子節點,只要一個可以建立成功,成功的機器做爲Active,其餘的做爲Standby,並註冊子節點的watcher監聽。一旦Active掛點,會話斷開連接,臨時節點自動刪除,觸發watcher,再次進行master選舉出新的Active。
  • HDFS的NameNode和ResourceManager模塊都是使用該組件實現的HA
  • 腦裂問題。選舉出新的Active機器後,之前的Active恢復正常了,出現了腦裂現象。使用ACL權限控制來進行隔離,建立節點的同時增長修改這個節點的權限。當以前的Active機器恢復正常,嘗試去修改節點數據的時候,發現已經沒有了權限。

(2)HBase。是一個面向海量數據的高可靠性、高性能、面向列、可伸縮的分佈式存儲系統

  • 與大多數分佈式NoSQL數據庫不一樣的是,HBase針對數據寫入具備強一致性、甚至包括索引列也都實現了強一致性
  • HBase採用zookeeper服務來完成對整個系統的分佈式協調工做
  • 系統冗錯。每一個RegionServer服務器都會信息節點,Hmaster對這個節點註冊監聽,當RegionServer掛掉以後,會話斷開,節點被刪除,Hmaster接收到刪除通知,會將掛掉的RegionServer所處理的數據分片(Region)從新路由到其餘的節點上。隨着系統容量的不斷增長,Hmaster管理的負擔會愈來愈重,因此使用zookeeper來完成這部分工做,減輕Hmaster負擔。
  • RootRegion管理。數據存儲的位置信息記錄在元數據分片(RootRegion)上。客戶端每次發起請求,須要知道數據的位置,就會去查詢RootRegion。而RootRegion的位置存儲在zookeeper上,當RootRegion發生變化或者發生故障時,就可以經過zookeeper感知到這一變化作出一系列響應的容災措施。
  • Region狀態管理。Region是HBase中數據的物理切片,每一個Region中記錄了全局數據的一小部分,不一樣的Region之間數據不相互不重複的。對於一個分佈式系統來講,Region會常常變動,變動緣由來自於系統故障、負載均衡、配置修改、Region分裂和合並等。一旦Region發生移動,須要作上線和下線處理。狀態管理須要Zookeeper來實現。對於Hbase集羣來講,Region的數量會達到10萬級別。
  • 分佈式SplitLog任務管理。

 (3)Kafka。開源的分佈式消息系統,是一個吞吐量極高的分佈式消息系統。主要用於實現低延遲的發送和收集大量的事件和日誌數據。

  • 每一個broker服務器啓動的時候,都會向Zookeeper註冊。zookeeper做爲註冊中心
  • 使用zookeeper做爲他的分佈式協調框架,實現了生產者和消費者的負載均衡

(4)dubbo

7、Zookeeper技術內幕

一、系統模型

  • 數據模型。由數據節點Znode組成樹型結構。每個事務操做(節點的建立和刪除、數據節點內容變動、客戶端會話的建立和失效)zookeeper會分配一個全局惟一的事務ID,ZXID,64位數字。前32位表示leader選舉的屆數,後32位表示事務序號
  • 節點特性。持久節點,持久順序節點,臨時節點,臨時順序節點。節點除了存儲數據,子節點以外,還存儲了節點自己的一些狀態信息,用Stat類來表示。
  • 版本。版本信息也是存儲在stat中的。version(當前節點數據內容的版本號)、cversion(當前節點子節點的版本號)、aversion(當前節點ACL變動版本號)。經過版本號來實現樂觀鎖,會從客戶端請求中獲取到版本號,和節點狀態數據中存儲的版本號對比,若是不匹配,就拋出異常。
  • Watcher,數據變動的通知。客戶端註冊watcher的時候,會將watcher對象存儲在客戶端的watchManager中,當服務端觸發watcher事件後,會向客戶端發送通知,客戶端線程從watchManager中取出對應的watcher對象來執行回調邏輯。watcher機制具備以下特色:一次性(不管是客戶端仍是服務端,一旦一個watcher被觸發,zookeeper就會從相應的存儲中移除,因此須要反覆註冊);客戶端串行執行(客戶端watcher的回調處理,是一個串行同步的過程,保證了順序性,也須要注意watcher回調方法的處理,避免長時間執行而影響到其餘的watcher回調);輕量(只會告訴客戶端發生了事件,不會說明事件的具體內容,另外,客戶端註冊的時候,也不會把客戶端真實的watcher對象傳遞給服務器。如此輕量的設計,在網絡開銷和服務器內存開銷上都是很是廉價的)
  • ACL,權限控制。分爲權限模式(Scheme)、受權對象(ID)、權限(Permission),使用scheme:id:permission來識別一個有效的acl信息
  • Scheme說明。IP模式:「IP:192.168.1.24」,「IP:192.168.1.1/24」;Digest模式:username:password,會進行兩次編碼處理,分別是SHA-1算法和BASE64編碼
  • 受權對象(ID)。IP模式下是一個ip或一個ip段;Digest模式下,是username:password;World模型下,是「anyone」
  • 權限(Permission)。create(C)建立子節點;delete(D)刪除子節點;read(R)讀取節點數據和子節點列表;write(W)更新節點數據;admin(A)節點管理權限,acl操做

二、序列化和協議

  • jute介紹。是zookeeper的序列化組件,也是早期Hadoop中的默認序列化組件。後來因爲Apache Avro具備出衆的跨語言特性、豐富的數據結構和對MapReduce的天生支持,而且能很是方便的用於RPC調用,因此後來的Hadoop就拋棄了Jute。可是zookeeper因爲新老版本兼容、性能瓶頸並不在jute上、其餘需求優先級更高等緣由,一直使用着jute這個古老的序列化組件
  • 通信協議。基於tcp/ip協議,zookeeper實現了本身的通信協議來完成客戶端與服務端、服務端與服務端之間的網絡通訊。請求包括請求頭和請求體,響應包括響應頭和響應體

三、客戶端

 (1)一次會話的建立過程

  • 初始化zookeeper對象
  • 設置會話默認watcher
  • 構造zookeeper服務器地址列表管理器:HostProvider
  • 建立並初始化客戶端網絡鏈接器:ClientCncx。內部有兩個線程,SendThread(I/O線程,負責負責zookeeper客戶端和服務端之間的網絡I/O通訊),ExentThread(事件線程,負責對服務器事件進行處理)。兩個核心隊列,outgoingQueue(客戶端請求發送隊列)、pendingQueue(服務端響應的等待隊列),還會建立底層I/O處理器ClientCxcnSocket
  • 初始化和啓動SendThread,ExentThread
  • 獲取一個服務器地址,經過HostProvider獲取
  • 建立tcp長鏈接。ClientCxcnSocket負責建立一個tcp長鏈接
  • SendThread負責構造一個ConnectRequest請求,放入到outgoingQueue請求隊列中
  • ClientCxcnSocket負責從outgoingQueue隊列中取出一個待發送的對象,將其序列化成ByteBuffer後,發送給服務端
  • ClientCxcnSocket接受服務器的響應,處理response,進行反序列化,
  • 生成鏈接成功事件,交給ExentThread進行處理,從ClientWatcherManager查詢watcher,將其放入到EventThread的waitingEvents隊列中。
  • 處理事件watcher,EventThread不斷的從waitingEvents隊列中取出待處理的watcher,調用watcher的process方法,執行回調邏輯。

(2)服務器地址列表

  • 客戶端隔離命名空間
  • HostProvider,會把全部的地址列表打散成一個環形隊列,不斷的從這個隊列中獲取地址
  • 自定義HostProvider,實現動態變動的地址列表管理器和同機房優先策略

四、會話

(1)會話狀態。整個會話的運行期間,會在不一樣的狀態之間進行切換。這些狀態包括connecting,connected,reconnecting,reconnected,close。

  • 客戶端因爲網路緣由斷開鏈接,會重連服務器。這個過程當中狀態會在connecting和connected之間切換
  • 會話超時、權限檢查失敗、客戶端主動退出程序。這些狀況下,客戶端狀態直接變爲close

(2)session是zookeeper的會話實體。包含如下屬性

  • 會話ID。全局惟一的sessionid。sessionid計算算法:((System.currentTimeMillis()<<24)>>>8)|(id<<56)。當前系統時間左移24位再無符號右移8位,保證前8位都是0,用於來後邊的服務器惟一表示id<<56作位或運算。前8位表示服務器機器id,後56位表示時間毫秒。sessionid由服務器進行建立,基於順序執行的特定,因此全部客戶端的請求的時間毫秒都是不同的。這樣就保證了sessionid的全局惟一性。
  • timeout。會話超時時間
  • ticktime。下次會話超時時間點。用於分桶策略管理
  • isclosing。標記一個會話是否已經關閉

(3)會話管理。由SessionTracker負責管理

  • 分桶策略。按照ExpirationTime對會話進行分類,相似的會話放在同一區塊中進行管理統一處理。ExpirationTime=((currentTime+SessionTimeout)/ExpirationInterval+1)*ExpirationInterval。ExpirationInterval是leader服務器進行按期檢查會話超時的時間間隔,默認值是tickTime的值。ExpirationTime老是ExpirationInterval的整數倍。
  • 會話激活。當客戶端向服務端發起請求的時候,會進行會話激活。從新計算會話的ExpirationTime。根據新舊兩個下次超時時間點,進行會話遷移,完成會話激活。有兩種狀況會發生會話激活:1 是隻要客戶端發送了請求,就會觸發一次會話激活;2 是若是客戶端在sessionTimeout/3時間內未和服務器進行過任何通訊,就會主動向服務器發送ping請求(心跳檢測),觸發服務端的會話激活
  • 會話超時檢查,按照ExpirationTime時間線,對會話桶進行檢查,留下的全部會話都是還沒有被激活的,對他們進行批量清理
  • 會話清理。標記會話狀態爲關閉,向集羣中全部機器發起會話關閉請求,收集須要刪除的臨時節點,刪除臨時節點,移除會話,關閉鏈接

(4)會話重連

  • 鏈接斷開。connection_loss。客戶端會自動從服務器地址列表中從新逐個選取新的地址嘗試進行鏈接,直到最終成功鏈接上服務器。斷開鏈接和重連成功,客戶端都會受到服務端的事件通知
  • 會話失效。session_expired。斷開鏈接以後,重連期間耗時過長,超過了會話超時時間,服務器認爲這個會話已經結束,進行會話清理。客戶端不知道已經失效,若是以後客戶端從新鏈接上了服務器,會受到會話已經失效的通知(session_expired)。
  • 會話轉移。session_moved。斷開從新後,成功鏈接上了新的服務器,會話轉移到了新的服務器上。

五、集羣版服務器啓動流程

(1)預啓動

  • 統一由QuorumPeerMain做爲啓動類
  • 解析配置文件zoo.cfg
  • 判斷當前是集羣模式仍是單機模式啓動(集羣模式中,在zoo.cfg中配置了多個服務器地址)

(2)初始化

(3)leader選舉

(4)leader和follower啓動期交互過程

  • 建立leader服務器,建立follower服務器
  • follower服務器和leader創建鏈接,註冊follower
  • leader服務器和follower服務器同步數據
  • 過半follower服務器完成數據同步。
  • 啓動leader服務器和follower服務器

 六、leader選舉

(1)選舉概述。服務器啓動時期的Leader選舉

  • 每一個server發出一個投票。初始化階段都會投給本身。投票以(myid,ZXID)表示。
  • 接收來自各個服務器的投票。判斷投票的有效性、檢查是不是本輪投票、是否來自looking狀態的服務器
  • 處理投票。把本身的投票和其餘服務器的投票進行PK。PK規則:ZXID比較大的優先成爲leader;ZXID相同,myid比較大的優先。把pk結果從新發給其餘服務器
  • 統計投票。每次投票後,都會統計是否有超過半數機器接收到相同的投票,大於等於n/2+1。
  • 改變服務器狀態。leader變爲leading,follower變爲following

(2)選舉概述。服務器運行期間的leader選舉

  • 變動狀態,當leader掛了以後,餘下的非observer服務器都會講本身的狀態變爲looking,開始進入選舉過程。
  • 在進行選舉的過程當中,每臺zookeeper server服務器有如下四種狀態:LOOKING、FOLLOWING、LEADING、OBSERVING,其中出於OBSERVING狀態的server不參加投票過程,只有出於LOOKING狀態的機子才參加投票過程,一旦投票結束,server的狀態就會變成FOLLOWER或者LEADER

  • 選舉過程同上。

(3)leader選舉的算法分析。3.4.0版本開始,只保留了tcp版本的FastLeaderElection。廢棄了LeaderElection和udp版本的FastLeaderElection

七、服務端請求處理

(1)會話建立請求

  • 請求接收。I/O層接收請求,根據NIOServerCnxn是否初始化來判斷是不是會話建立請求,反序列化請求,檢查客戶端Zxid(客戶端Zxid需小於服務端Zxid),根據服務端的配置協商sessionTimeout
  • 會話建立。爲客戶端生成sessionID,向sessionTracker中註冊會話,會話激活,生成會話密碼(做爲會話在不一樣服務器中間轉移的憑證)
  • 預處理。採用責任鏈模式,建立請求事務頭、請求事務體、註冊與激活會話(爲了處理非Leader服務器轉發過來的會話建立請求)
  • 事務處理。Sync流程:Leader服務器和follower服務器記錄事務日誌的過程
  • 事務處理。Proposal流程:投票和統計投票過程。相似於二階段提交協議的preCommit。生成提議Proposal,廣播提議,收集投票
  • 事務處理。Commit流程:超過半數提議經過,廣播commit消息
  • 事務應用。將事務變動應用到內存數據庫中,對於會話建立須要特殊處理,會話的管理由sessionTracker負責,只須要再次向sessionTracker註冊便可
  • 會話響應。統計服務端處理所花費的時間,建立響應,序列化響應,I/O層發送響應給客戶端

(2)setData請求

  • 預處理。接收請求,反序列化,會話檢查、ACL權限檢查、數據版本檢查、生成事務
  • 事務處理。同上
  • 事務應用。將事務變動應用到內存數據庫中
  • 請求響應。同上

(3)事務請求轉發。全部非Leader服務器收到了客戶端發來的事務請求,都會將請求轉發到Leader服務器來處理

(4)getData等非事務請求的流程

  • 預處理。接收請求,判斷是否爲客戶端會話建立請求,交給PrepRequestProcessor處理器進行處理,會話檢查
  • 非事務處理。反序列化請求,獲取節點數據,ACL權限檢查,註冊Watcher
  • 請求響應。同上

八、數據與存儲

(1)內存數據

  •  DataTree。是內存數據存儲的核心,是一個樹的結構。底層是ConcurrentHashMap<String,DataNode> nodes。節點的路徑(path)做爲key,節點的數據內容DataNode做爲value
  • DataNode。是數據存儲的最小單元。包括節點的數據內容data[]、acl列表、節點狀態(stat)、還記錄了父節點的引用和子節點列表
  • ZKDatabase。是zookeeper的內存數據庫,負責管理zookeeper的全部會話、DataTree存儲、事務日誌。

(2)事務日誌

  • 文件存儲。配置中的dataDir目錄,是用來存儲日誌文件的。每一個日誌文件的大小都是64M,以事務ID(ZXID)做爲後綴,高32位表明Leader週期,低32位則是真正的操做序列號
  • 日誌內容存儲格式。事務日誌是二進制表示,沒法直接看出信息。需使用事務日誌格式化工具。org.apache.zookeeper.Server.LogFormatter。使用方法以下:Java LogFormatter 事務日誌文件。須要注意的是,這是一個記錄事務操做的日誌文件,所以裏面沒有任務讀操做的日誌記錄
  • 日誌寫入。1.當前日誌文件剩餘空間不足4k,會進行預分配。文件的不斷追加寫入會觸發底層磁盤I/O爲文件開闢新的磁盤塊(磁盤seek),爲了不磁盤seek的頻率,提升磁盤I/O效率;2.事務序列化;3.寫入事務日誌文件流;4.事務日誌刷入磁盤
  • 日誌截斷。非leader機器上記錄的zxid比leader服務器還要大,Leader會發送TRUNC命令,進行日誌截斷,刪除全部包含或大於peerLastZxid的事務日誌文件

(3)snapshot,數據快照。用來記錄Zookeeper服務器某一個時刻的全量內存數據內容,並將其寫入到指定的磁盤文件中

  • 文件存儲。 經過dataDir來配置,快照文件也是用事務ID(ZXID)的十六進制做爲文件後綴,該後綴標記了本次數據快照開始時刻的服務器最新ZXID。和事務日誌不一樣,快照日誌沒有采用預分配機制。
  • 存儲格式,和事務日誌存儲格式相同,須要使用格式化工具查看內容。會將數據節點逐個依次輸出,這裏輸出的僅僅是數據節點的元數據(stat),並無輸出每一個節點的數據內容
  • 數據快照過程:1 判斷是否須要進行數據快照(採用過半隨機策略,避免全部機器同時進行數據快照,影響性能。logcount>(snapcount/2+randroll) snapcount是配置文件配置的數值,randroll是一個隨機值);2 切換事務日誌文件,計數清零;3 建立數據快照異步線程; 4 獲取全量信息和會話信息 ;5 生成快照文件名 6 數據序列化,寫入磁盤

(4)初始化。服務器啓動期間,會進行數據初始化過程,將磁盤上的數據加載到內存中

  • 處理快照文件,獲取最新的100個快照文件
  • 對快照文件進行解析和校驗。若是最新的快照文件未經過解析和校驗,會逐個往下進行解析校驗。
  • 獲取最新的ZXID
  • 處理事務日誌,獲取全部大於上一步ZXID的事務日誌。把事務日誌應用到內存數據庫中
  • 再次獲取最新的ZXID
  • 校驗epoch(leader選舉屆數)

(5)數據同步

peerLastZxID:該follower服務器最後處理的Zxid

minComminttedLog :Leader服務器提議緩存隊列ComminttedLog中最小的Zxid

maxComminttedLog:Leader服務器提議緩存隊列ComminttedLog中最大的Zxid

  • 直接差別化同步(DIFF同步)。peerLastZxID介於minComminttedLog和maxComminttedLog中間
  • 先回滾在差別化同步(TRUNC+DIFF同步)。peerLastZxID介於minComminttedLog和maxComminttedLog中間,可是leader發現了某個follower包含了一條本身沒有的事務記錄。
  • 僅回滾同步(RTUNC)。peerLastZxID大於maxComminttedLog
  • 全量同步(SNAP)。peerLastZxID小於minComminttedLog;Leader沒有提議緩存隊列,peerLastZxID不等於Leader服務器最大的Zxid。在這兩種狀況下,Leader服務器都沒法直接使用提議緩存隊列和learner進行同步,所以只能使用全量同步(SNAP)

8、Zookeeper運維

一、配置詳解

(1)基本配置。必需配置

  •  clientPort:對外的服務端口,通常配置爲218一、集羣中的全部端口不須要保持一致
  • dataDir:服務器存儲快照文件的目錄。dataLogDir,事務日誌的存儲目錄
  • tickTime:默認值3000毫秒,用於配置Zookeeper中最小時間單位的長度。會話的最小超時時間默認是2*tickTime

(2)高級配置

  • dataLogDir:用於存儲事務日誌文件。應該將事務日誌單獨配置在一塊磁盤上,事務日誌寫入的性能直接影響到zookeeper的性能和吞吐量。數據快照操做會極大的影響事務日誌的寫性能,儘可能分開磁盤
  • initLimit:默認值爲10,即tickTime的十倍。Leader等待follower完成數據同步的時間。隨着集羣的數據量增大,同步時間變長,能夠適當調大這個參數
  • syncLimit:默認值5,leader服務器和follower進行心跳檢測的最大延時時間。若是網絡環境較差,能夠適當調大此參數
  • snapCount:默認值 100000。兩次快照之間間隔的事務操做次數
  • preAllocSize:默認值65536,即64M。事務日誌預分配的空間大小。隨着snapCount的變化而變化,同增同減
  • minSessionTimeout。maxSessionTimeout:最大和最小超時時間。分別是tickTime的2倍和20倍。用於對客戶端回話超時時間進行限制
  • maxClientCnxns:默認值60。若是設置爲0,則表示沒有限制。單個客戶端和服務端之間的最大併發鏈接數。
  • jute.maxbuffer:單個數據節點上存儲的最大數據量大小。zookeeper上不須要存儲太多的數據,每每還須要將該參數設置的更小
  • clientPortAddress:針對多網卡的機器,zookeeper容許爲每一個ip地址指定不一樣的監聽端口
  • server.id:host:port:port:配置組成集羣的機器列表。第一個port用於leader和follower進行通訊和數據同步的端口,第二個port用於leader選舉過程當中的投票通訊
  • autopurge.snapRetainCount:自動清理快照日誌和事務日誌時,須要保留的數量。最小值爲3,默認值也是3
  • autopurge.purgeInterval:自動清理的頻率。默認值是0,單位是小時。配置爲0或者負數,表示不開啓自動清理功能。默認不開啓此功能
  • fsync.warningthresholdms:配置事務日誌操做消耗時間的報警閾值,超過閾值,將在日誌中打印出報警日誌。
  • forceSync:配置事務日誌每次寫入操做強制寫入磁盤。默認值是yes。若是設置成no,在必定程度上能提升zookeeper的寫性能,但存在斷點的風險。
  • globalOutStandingLimit:默認值1000,服務器最大請求堆積數量,防止服務器資源被大量的客戶端請求耗盡。
  • leaderServers:是否容許leader服務器向客戶端提供服務。默認值yes。能夠設置成no,讓leader服務器專一的進行分佈式協調
  • SkipAcl:默認值 no。配置是否跳過acl權限檢查。
  • cnxTimeout:默認值5000毫秒。配置Leader選舉過程當中,個服務器間tcp鏈接建立的超時時間
  • eletionAlg:leader選舉策略。3.4.0版本以後,只留下了fastLeaderElection算法。

二、四字命令

  • conf。輸出服務器的配置信息
  • cons。輸出這臺服務器上全部客戶端鏈接的詳細信息
  • crst。重置全部客戶端的鏈接統計信息
  • dump。輸出當前集羣中的全部會話信息。只有leader服務器會進行會話超時檢測,leader服務器執行此命令,還會打印出會話的超時時間
  • envi。輸出當前服務器運行時的環境信息
  • ruok。輸出當前服務器是否正在運行。
  • stat。輸出當前服務器運行時的狀態信息,包括鏈接狀況
  • srvr。和stat命令功能相同,區別是srvr命令不會打印鏈接狀況
  • srst。重置全部服務器的統計信息
  • wchs。輸出當前服務器上的watcher概要信息
  • wchc。輸出當前服務器上管理的watcher詳細信息。以會話單元進行歸組
  • wchp。輸出當前服務器上管理的watcher詳細信息。以節點路徑爲單位進行歸組
  • mntr。輸出比stat更詳細的服務器統計信息。

三、JMX。是一個爲應用程序、設備、系統等植入管理功能的框架

(1)開啓遠程JMX

經過上述配置,就能夠容許遠程機器和zookeeper服務器進行jmx鏈接了

(2)經過JConsole鏈接zookeeper

JConsole是一個Java內置的基於JMX的圖形化管理工具,是最經常使用的JXM鏈接器。

四、監控

TaoKeeper監控系統,能夠在實時監控和數據統計兩方面保障Zookeeper的穩定性。github地址:https://github.com/alibaba/taokeeper

五、構建一個高可用的集羣

(1)集羣組成。最好的數量是奇數,不過偶數能夠的

(2)容災。三機房部署,2機房部署

(3)擴容與縮容。Zookeeper集羣擴容須要整個集羣機器的重啓。總體重啓和逐臺重啓

9、相關資料

Zookeeper的優缺點

zookeeper有什麼缺點?

相關文章
相關標籤/搜索