文章很長,建議收藏起來,慢慢讀! 瘋狂創客圈為小伙伴奉上以下珍貴的學習資源:
- 瘋狂創客圈 經典圖書 : 《Netty Zookeeper Redis 高並發實戰》 面試必備 + 大廠必備 + 漲薪必備
- 瘋狂創客圈 經典圖書 : 《SpringCloud、Nginx高並發核心編程》 面試必備 + 大廠必備 + 漲薪必備
- 資源寶庫: Java程序員必備 網盤資源大集合 價值>1000元 隨便取 GO->【博客園總入口 】
- 獨孤九劍:Netty靈魂實驗 : 本地 100W連接 高並發實驗,瞬間提升Java內力
- 技術、面試交流:和大廠 小伙伴、技術高手、架構師 進行 純粹的的技術問題交流、探討求助、問題圍觀學習
推薦: 瘋狂創客圈 高質量 博文
高並發 必讀 的精彩博文 | |
---|---|
nacos 實戰(史上最全) | sentinel (史上最全+入門教程) |
Zookeeper 分布式鎖 (圖解+秒懂+史上最全) | Webflux(史上最全) |
SpringCloud gateway (史上最全) | TCP/IP(圖解+秒懂+史上最全) |
10分鍾看懂, Java NIO 底層原理 | Feign原理 (圖解) |
更多精彩博文 ..... | 請參見【 瘋狂創客圈 高並發 總目錄 】 |
史上最全 Java 面試題 28 專題 總目錄
zookeeper的使用場景
zookeeper是Apache開源的頂級項目,用於提供一個高性能、高可用,且具有嚴格的順序訪問控制能力(主要是寫操作的嚴格順序性)的分布式協調服務。可用於在分布式環境中保證數據的一致性,擁有非常廣泛地使用場景。
主要的使用場景如下:
- 實現數據的發布和訂閱 :可以把一些可能變化的配置數據放入zookeeper服務器,客戶端可以訂閱並監聽這個配置,一旦配置更新,就可以重新獲取配置。
- 命名服務 :有時分布式系統需要一些命名,比如提供RPC服務地址的名稱、全局唯一不能重復的主鍵等,利用zookeeper節點不重名的特點可以進行命名服務。
- master選舉:有時分布式系統中存在多台服務器,必須選出一台master來執行特定的計算任務,master掛掉后,自動重新選出一台服務器擔任master執行任務。這種情況可以使用zookeeper來實現,多個客戶端創建同一個臨時節點,只有一個可以成功,成功的節點就是master,其他客戶端監聽該節點,一旦被刪除,說明master宕機,重新開始新的選舉。
- 負載均衡:在消息隊列的集群中,消息生產者需要比較均衡地將消息投遞到不同的消息代理上,這里就涉及到負載均衡的使用。
- 分布式鎖: 后台接口分布式部署了以后,為了避免出現不同服務器的線程同時修改同一個數據引起並發問題,需要進行跨主機跨進程的線程同步,這是就用到分布式鎖,主要基於zookeeper的臨時有序節點來實現。
- 分布式隊列 :客戶端提交的任務信息可以保存到zookeeper中,利用zookeeper有序節點的特性,實現一個先進先出的隊列,zookeeper可以記錄任務提交的拓撲信息並保持任務的有序調度。
- 分布式協調和通知 :可以實現不同機器之間心跳監測(臨時有序節點是否存在)、數據通信(向節點寫入數據並監聽變化)等場景。
- 集群元數據管理 :每個集群的機器可以向zookeeper添加一個臨時有序節點,只要節點存在表示機器存活。利用這個特點可以完成集群服務器的監控。還可以將主機的狀態信息寫入zookeeper的節點,監控中心訂閱這些節點的數據來獲得主機的實時信息。
- 其他的需要分布式協調場景
Zookeeper的角色
» 領導者(leader),負責進行投票的發起和決議,更新系統狀態
» 學習者(learner),包括跟隨者(follower)和觀察者(observer),follower用於接受客戶端請求並想客戶端返回結果,在選主過程中參與投票
» Observer可以接受客戶端連接,將寫請求轉發給leader,但observer不參加投票過程,只同步leader的狀態,observer的目的是為了擴展系統,提高讀取速度
» 客戶端(client),請求發起方
每個Server在工作過程中有三種狀態:
LOOKING:當前Server不知道leader是誰,正在搜尋
LEADING:當前Server即為選舉出來的leader
FOLLOWING:leader已經選舉出來,當前Server與之同步
什么是Observer?
zk3.3開始引入的角色,觀察最新狀態,並變更。與Follower不同只是不參與投票、選舉,只提供非事務服務。
• Zookeeper需保證高可用和強一致性;
• 為了支持更多的客戶端,需要增加更多Server;
• Server增多,投票階段延遲增大,影響性能;
• 權衡伸縮性和高吞吐率,引入Observer
• Observer不參與投票;
• Observers接受客戶端的連接,並將寫請求轉發給leader節點;
• 加入更多Observer節點,提高伸縮性,同時不影響吞吐率
Zab協議
Zookeeper 客戶端會隨機的連接到 zookeeper 集群中的一個節點。
注意,ZK集群會有很多節點, 客戶端在建立連接時,會隨機挑選一個節點。
ZK集群對客戶端的請求,按照類型(讀、寫兩類)分開處理:
-
讀請求
客戶端直接從當前節點(其建立連接的節點)中讀取數據;
-
寫請求
這里涉及到了分布式事務。 客戶端就會向 Leader 提交事務,Leader 接收到事務提交,會廣播該事務,只要超過半數節點寫入成功,該事務就會被提交。
Zookeeper的核心是原子廣播,這個機制保證了各個Server之間的同步。實現這個機制的協議叫做Zab協議。Zab協議 的全稱是 Zookeeper Atomic Broadcast (Zookeeper原子廣播)。Zookeeper 是通過 Zab 協議來保證分布式事務的最終一致性。
ZAB與Paxos聯系&區別
兩者設計目標不一樣,ZAB主要用於構建高可用分布式系統,Paxos 算法用於構建一致性狀態機器。所有會有細微差別。但是ZAB就是在Paxos保證一致性基礎上設計出高可用的協議。
ZAB 的基本概念
epoch周期值(比喻:年號)
acceptedEpoch(比喻:接受的年號):follower已經接受leader更改年號的(newepoch)提議。
currentEpoch(比喻:當前的年號):當前的年號
history:當前節點接受到事務提議的log
lastZxid:history中最近接收到的提議zxid(最大的值)
年號如何遞增:
當產生新Leader的時候,就從這個Leader服務器上取出本地log中最大事務Zxid,從里面讀出epoch+1,作為一個新epoch,並將低32位置0(保證id絕對自增)
ZXID : 事務的Proposal(提議) 的id,可以簡單理解為事務id
ZXID 是一個 64 位的數字,其中低 32 位可看作是計數器,Leader 服務器每產生一個新的事務 Proposal 的時候,都會該計數器進行加 1 操作。
ZXID 的高 32 位表示 Leader 周期 epoch 的編號,每當選舉一個新的 Leader 服務器,就會從該服務器本地的事務日志中最大 Proposal 的 ZXID 中解析出對應的 epoch 值,然后對其加 1 操作,這個值就作為新的 epoch 值,並將低 32 位初始化為 0 來開始生成新的 ZXID。
Zookeeper 集群的模式
Zookeeper 集群的模式包括兩種基本的模式:崩潰恢復 和 消息廣播
崩潰恢復模式
當整個集群啟動過程中,或者當 Leader 服務器出現網絡中弄斷、崩潰退出或重啟等異常時,Zab協議就會 進入崩潰恢復模式,選舉產生新的Leader。
一但出現崩潰,會導致數據不一致,ZAB的崩潰恢復開始起作用。有如下兩個確保:
- ZAB協議需要確保已經在Leader提交的事務最終被所有服務器提交。
- ZAB協議需要確保丟棄只在Leader服務器上被提出的事務。
針對上兩個要求,如果Leader選舉算法保證新選舉出來的Leader服務器擁有集群中所有機器最高編號(ZXID最大)的事務Proposal,那么就能保證新的Leader 一定具有已提交的所有提案,更重要是,如果這么做,可以省去Leader服務器檢查Proposal的提交和丟棄工作的這一步。
一旦Leader服務器出現崩潰,或者說網絡原因導致Leader服務器失去了與過半的Follower的聯系,那么就會進入崩潰恢復模式。為了保證程序的正常運行,整個恢復過程后需要選舉一個新的Leader服務器。因此,ZAB協議需要一個高效可靠的Leader選舉算法,從而確保能夠快速的選舉出新的Leader。同時,新的Leader選舉算法不僅僅需要讓Leader自己知道其自身已經被選舉為Leader,同時還需要讓集群中所有的其他機器也能夠快速的感知選舉產生的新的Leader服務器。
ZAB協議規定了如果一個事務Proposal在一台機器上被處理成功,那么應該在所有的機器上都被處理成功,哪怕機器出現崩潰。
消息廣播模式
當新的Leader出來了,同時,已有過半機器完成同步之后,ZAB協議將退出恢復模式。進入消息廣播模式。這時,如果有一台遵守Zab協議的服務器加入集群,因為此時集群中已經存在一個Leader服務器在廣播消息,那么該新加入的服務器自動進入恢復模式:找到Leader服務器,並且完成數據同步。同步完成后,作為新的Follower一起參與到消息廣播流程中。
如果集群中其他機器收到客戶端事務請求后,那么會先轉發Leader服務器,由Leader統一處理。
- 在zookeeper集群中,數據副本的傳遞策略就是采用消息廣播模式。zookeeper中數據副本的同步方式與二段提交相似,但是卻又不同。二段提交要求協調者必須等到所有的參與者全部反饋ACK確認消息后,再發送commit消息。要求所有的參與者要么全部成功,要么全部失敗。二段提交會產生嚴重的阻塞問題。
- Zab協議中 Leader 等待 Follower 的ACK反饋消息是指“只要半數以上的Follower成功反饋即可,不需要收到全部Follower反饋”
- 整個過程中,Leader為每個事務請求生產對應的Proposal,在廣播前,為這個事務分配一個全局唯一ID,為ZXID(事務ID),必須按照遞增的事務順序進行處理。
- 具體流程如下圖。
ZAB協議中涉及的二階段提交和2pc有所不同。在ZAB協議的二階段提交過程中,移除了中斷邏輯,所有Follower服務器要么正常反饋Leader提出的事務Proposal,要么就拋棄Leader服務器。ZAB協議中,只要集群中過半的服務器已經反饋ACK,就開始提交事務了,不需要等待集群中所有的服務器都反饋響應。這種模型是無法處理Leader服務器崩潰退出而帶來的數據不一致問題的,因此在ZAB協議中添加了另一個模式,即采用崩潰恢復模式來解決這個問題。此外,整個消息廣播協議是基於具有FIFO特性的TCP協議來進行網絡通信的,因此能夠很容易保證消息廣播過程中消息接受與發送的順序性。
在整個消息廣播過程中,Leader服務器會為每個事務請求生成對應的Proposal來進行廣播,並且在廣播事務Proposal之前,Leader服務器會首先為這個事務分配一個全局單調遞增的唯一ID,我們稱之為事務ID(即ZXID)。由於ZAB協議需要保證每一個消息嚴格的因果關系,因此必須將每一個事務Proposal按照其ZXID的先后順序來進行排序與處理。
在消息廣播過程中,Leader服務器會為每一個Follower服務器各自分配一個單獨的隊列,然后將需要廣播的事務Proposal依次放入這些隊列中,並且根據FIFO策略進行消息發送。每一個Follower服務器在接受到這個事務Proposal之后,都會首先將其以事務日志的形式寫入到本地磁盤中去,並且在成功寫入后反饋給Leader服務器一個ACK響應。當Leader服務器接收到超過半數Follower的ACK響應后,就會廣播一個Commit消息給所有Follower服務器以通知其將事務進行提交,同時Leader自身也會完成事務的提交,而每一個Follower服務器收到Commit消息之后,也會完成對事務的提交。
ZAB的兩種基本模式?
崩潰恢復:在正常情況下運行非常良好,一旦Leader出現崩潰或者由於網絡原因導致Leader服務器失去了與過半Follower的聯系,那么就會進入崩潰恢復模式。為了程序的正確運行,整個恢復過程后需要選舉出一個新的Leader,因此需要一個高效可靠的選舉方法快速選舉出一個Leader。
消息廣播:類似一個兩階段提交過程,針對客戶端的事務請求, Leader服務器會為其生成對應的事務Proposal,並將其發送給集群中的其余所有機器,再分別收集各自的選票,最后進行事務提交。
哪些情況會導致ZAB進入恢復模式並選取新的Leader?
啟動過程或Leader出現網絡中斷、崩潰退出與重啟等異常情況時。
當選舉出新的Leader后,同時集群中已有過半的機器與該Leader服務器完成了狀態同步之后,ZAB就會退出恢復模式。
ZAB協議的選主:
ZAB協議中存在着三種狀態,每個節點都屬於以下三種中的一種:
-
Looking /election:系統剛啟動時或者Leader崩潰后正處於選舉狀態
-
Following :Follower節點所處的狀態,Follower與Leader處於數據同步階段;
-
Leading :Leader所處狀態,當前集群中有一個Leader為主進程;
在ZooKeeper的整個生命周期中,每個節點都會在Looking、Following、Leading狀態間不斷轉換.
啟動之初,ZooKeeper所有節點初始狀態為Looking,這時集群會嘗試選舉出一個Leader節點,選舉出的Leader節點切換為Leading狀態;當節點發現集群中已經選舉出Leader則該節點會切換到Following狀態,然后和Leader節點保持同步;當Follower節點與Leader失去聯系時Follower節點則會切換到Looking狀態,開始新一輪選舉;
Zookeeper leader 選舉圖解
• 半數通過
– 3台機器 掛一台 2>3/2
– 4台機器 掛2台 2!>4/2
• A提案說,我要選自己,B你同意嗎?C你同意嗎?B說,我同意選A;C說,我同意選A。(注意,這里超過半數了,其實在現實世界選舉已經成功了。
但是計算機世界是很嚴格,另外要理解算法,要繼續模擬下去。)
• 接着B提案說,我要選自己,A你同意嗎;A說,我已經超半數同意當選,你的提案無效;C說,A已經超半數同意當選,B提案無效。
• 接着C提案說,我要選自己,A你同意嗎;A說,我已經超半數同意當選,你的提案無效;B說,A已經超半數同意當選,C的提案無效。
• 選舉已經產生了Leader,后面的都是follower,只能服從Leader的命令。而且這里還有個小細節,就是其實誰先啟動誰當頭。
選主的細分場景
分析以上兩種細分場景:
- 啟動時期選舉:
- 每個Server發出一個投票
- 接受來自各個服務器的投票
- 處理投票(優先檢查ZXID,相同就比較myid)
- 統計投票( 判斷是否已經有過半的機器接收到相同的投票信息,所謂“過半”就是指大於集群機器數量的一半,即大於或等於 (n/2+1)。對於這里由3台機器構成的集群,大於等於2台即為達到“過半”要求。)
- 改變服務器狀態:Leader->LEADING, Follower->FOLLOWING
- 服務運行期間的Leader選舉:
- 變更狀態:Leader掛后,剩下的Follower都變成LOOKING,進入Leader選舉
- 每個Server發出投票,第一輪都投自己,然后將自己投票發給所有機器
- 接收投票,與啟動選舉相同
- 處理投票,與啟動選舉相同
- 統計投票,與啟動選舉相同
- 改變服務器狀態,與啟動選舉相同
為什么zookeeper集群的數目,一般為奇數個?
•Leader選舉算法采用了Paxos協議;
•Paxos核心思想:當多數Server寫成功,則任務數據寫成功如果有3個Server,則兩個寫成功即可;如果有4或5個Server,則三個寫成功即可。
•Server數目一般為奇數(3、5、7)如果有3個Server,則最多允許1個Server掛掉;如果有4個Server,則同樣最多允許1個Server掛掉由此,
我們看出3台服務器和4台服務器的的容災能力是一樣的,所以為了節省服務器資源,一般我們采用奇數個數,作為服務器部署個數。
FastLeaderElection選主算法(選主算法可在zoo.cfg中配置)
ZAB 默認采用 TCP 版本的 FastLeaderElection 選舉算法。在選舉投票消息中包含了兩個最基本的信息:所推舉的服務器 SID 和 ZXID,分別表示被推舉服務器的唯一標識(每台機器不一樣)和事務 ID。假如投票信息為 (SID, ZXID)的形式。在第一次投票的時候,由於還無法檢測集群其他機器的狀態信息,因此每台機器都將自己作為被推舉的對象來進行投票。每次對收到的投票,都是一個對投票信息(SID, ZXID)對比的過程,規則如下:
1 邏輯時鍾clock表示第幾輪選舉,重啟時為0,選舉時加1
2 啟動時處於looking狀態
3 選舉細節
- 先選自己,選票為“clock(1)、 looking、zxid、myid”
- 廣播選票,收到其他節點選票
- 如果其他節點選票的clock大,更新自己的clock;
- 如果接收到的投票 ZXID 大於自己的 ZXID,就認可當前收到的投票,則更新自己選票的相應值為該節點值,表示選舉該節點。
- 如果接收到的投票 ZXID 小於自己的 ZXID,那么就堅持的投票,不做任何變更。
- 如果接收到的投票 ZXID 等於自己的 ZXID,再對比 myid,比自己大,就認可當前收到的投票,表示選舉該節點;如果比自己小,那就堅持自己的投票,不做變更。
4 重新發出選票
經過第二次投票后,集群中每台機器都會再次收到其他機器的投票,然后開始統計,如果一台機器收到超過了半數的相同投票,那么這個投票對應的 myid機器即為 Leader。
簡單來說,通常哪台服務器上的數據越新,那么越有可能成為 Leader。原因很簡答,數據越新,也就越能夠保證數據的恢復。當然,如果集群中有幾個服務器具有相同的 ZXID,那么 myid較大的那台服務器成為 Leader。
結束選主之后的進入消息廣播模式
選舉出Leader節點后ZAB進入原子廣播階段,Leader與Follower使用心跳檢測來感知對方的存在:
1 當Leader節點在超時時間內能正常收到來自Follower的心跳, 那Follower節點會一直與該節點保持連接;
2 若超時時間內Leader沒有接收到來自過半Follower節點的心跳檢測或TCP連接斷開,那Leader會結束當前周期的領導,切換到Looking狀態,所有Follower節點也會放棄該Leader節點切換到Looking狀態,然后開始新一輪選舉;
選主的過程
Phase 0: Leader election(選舉階段)
節點在一開始都處於選舉階段,只要有一個節點得到超半數節點的票數,它就可以當選准 leader。只有到達 Phase 3 准 leader 才會成為真正的 leader。這一階段的目的是就是為了選出一個准 leader,然后進入下一個階段。
協議並沒有規定詳細的選舉算法,后面我們會提到實現中使用的 Fast Leader Election。
Phase 1: Discovery(發現階段)
在這個階段,followers 跟准 leader 進行通信,同步 followers 最近接收的事務提議。這個一階段的主要目的是發現當前大多數節點接收的最新提議,並且准 leader 生成新的 epoch,讓 followers 接受,更新它們的 accepted Epoch
一個 follower 只會連接一個 leader,如果有一個節點 f 認為另一個 follower p 是 leader,f 在嘗試連接 p 時會被拒絕,f 被拒絕之后,就會進入 Phase 0。
Phase 2: Synchronization(同步階段)
同步階段主要是利用 leader 前一階段獲得的最新提議歷史,同步集群中所有的副本。只有當 quorum 都同步完成,准 leader 才會成為真正的 leader。follower 只會接收 zxid 比自己的 lastZxid 大的提議。
Phase 3: Broadcast(廣播階段)
到了這個階段,Zookeeper 集群才能正式對外提供事務服務,並且 leader 可以進行消息廣播。同時如果有新的節點加入,還需要對新節點進行同步。
值得注意的是,ZAB 提交事務並不像 2PC 一樣需要全部 follower 都 ACK,只需要得到 quorum (超過半數的節點)的 ACK 就可以了。
Zookeeper節點的數據同步
完成Leader選舉之后,在正式開始工作(即接收客戶端的事務請求,然后提出新的提案)之前,Leader服務器會首先確認事務日志中的所有Proposal都已經被集群中過半的機器提交了,即是否完成數據同步。
集群中所有的正常運行的服務器,要么成為Leader,要么成為Follower並和Leader保持同步。Leader服務器需要確保所有的Follwer服務器能夠接收到每一條事務Proposal,並且能夠正確地將所有已經提交了的事務Proposal應用到內存數據庫中。Leader服務器會為每一個Followe服務器都准備一個隊列,並將沒有被各Follower服務器同步的事務以Proposal消息形式逐個發送到Follower服務器,並在每一個Proposal消息后緊跟着再發送一個Commit消息,以表示這個事務已經被提交。等到Follower服務器將所有尚未同步的事務Proposal都從Leader服務器上同步過來並成功應用到本地數據庫中后,Leader服務器就會將改Follower服務器加入到真正可用的Follower列表中,並開始之后的其他流程。
ZAB協議如何處理那些需要被丟棄的事務Proposal的?
在ZAB協議的事務編號ZXID設計中,ZXID是一個64位數字,其中低32位可以看做一個簡單的單調遞增的計數器,針對客戶端的每一個事務請求,Leader服務器在產生一個新的事務Proposal的時候,都會對改計數器進行加一操作;而高32位則代表了leader周期epoch的編號,每當選舉產生一個新的Leader服務器,就會從這個Leader服務器取出本地日志中最大事務Proposal的ZXID,並從ZXID中解析出對應的epoch值,然后再對其進行加1操作,之后的編號就會作為新的epoch,並將低32位 置0來開始生成新的ZXID。ZAB協議中的這一通過epoch編號來區分Leader周期變化的策略,能夠有效避免不同的Leader服務器錯誤的使用相同的ZXID編號提出不一樣的事務的情況。
基於這樣的策略,當一個包含了上一個Leader周期中尚未提交過的事務服務器啟動時,肯定無法成為leader。因為當前集群中肯定包含一個Quorum集合,該集合中機器一定包含了更高的epoch的事務Proposal。
Zab協議的事務
分布式事務就是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位於不同的分布式系統的不同節點之上。簡單的說,就是一次大的操作由不同的小操作組成,這些小的操作分布在不同的服務器上,且屬於不同的應用,分布式事務需要保證這些小操作要么全部成功,要么全部失敗。本質上來說,分布式事務就是為了保證不同數據庫的數據一致性。
為了保證事務的順序一致性,zookeeper采用了遞增的事務id號(zxid)來標識事務。所有的提議(proposal)都在被提出的時候加上了zxid。實現中zxid是一個64位的數字,它高32位是epoch(有點類似年代、年號)用來標識 leader關系是否改變,每次一個leader被選出來,它都會有一個新的epoch,標識當前屬於那個leader的統治時期。低32位用於遞增計數。
那么什么是zxid呢?
ZooKeeper狀態的每一次改變, 都對應着一個遞增的Transaction id, 該id稱為zxid. 由於zxid的遞增性質, 如果zxid1小於zxid2, 那么zxid1肯定先於zxid2發生.
創建任意節點, 或者更新任意節點的數據, 或者刪除任意節點, 都會導致Zookeeper狀態發生改變, 從而導致zxid的值增加.
Zab協議的核心:
Zab協議的核心:定義了事務請求的處理方式
1)所有的事務請求必須由一個全局唯一的服務器來協調處理,這樣的服務器被叫做 Leader服務器。其他剩余的服務器則是 Follower服務器。
2)Leader服務器 負責將一個客戶端事務請求,轉換成一個 事務Proposal,並將該 Proposal 分發給集群中所有的 Follower 服務器,也就是向所有 Follower 節點發送數據廣播請求(或數據復制)
3)分發之后, Leader服務器需要等待所有Follower服務器的反饋(Ack請求),在Zab協議中,只要超過半數的Follower服務器進行了正確的反饋后, 那么 Leader 就會再次向所有的 Follower服務器發送 Commit 消息,要求其將上一個 事務proposal 進行提交。 (注意:有點像2PC)
廣播模式下只有主節點可以發送廣播消息,如果某個從節點需要發送廣播信息,也需要通過主節點進行。
Zab協議的事務特點:
消息廣播階段的數據寫入策略,通過事務完成,有以下特點:
1)在zookeeper集群中,數據副本的傳遞策略就是采用消息廣播模式。zookeeper中農數據副本的同步方式與二段提交相似,但是卻又不同。二段提交要求協調者必須等到所有的參與者全部反饋ACK確認消息后,再發送commit消息。要求所有的參與者要么全部成功,要么全部失敗。二段提交會產生嚴重的阻塞問題。
2)Zab協議中 Leader 等待 Follower 的ACK反饋消息是指“只要半數以上的Follower成功反饋即可,不需要收到全部Follower反饋”
Zab協議的事務過程:
消息廣播具體步驟如下:
1)客戶端發起一個寫操作請求。
2)Leader 服務器將客戶端的請求轉化為事務 Proposal 提案,同時為每個 Proposal 分配一個全局的ID,即zxid。
3)Leader 服務器為每個 Follower 服務器分配一個單獨的隊列,然后將需要廣播的 Proposal 依次放到隊列中取,並且根據 FIFO 策略進行消息發送。
4)Follower 接收到 Proposal 后,會首先將其以事務日志的方式寫入本地磁盤中,寫入成功后向 Leader 反饋一個 Ack 響應消息。
5)Leader 接收到超過半數以上 Follower 的 Ack 響應消息后,即認為消息發送成功,可以發送 commit 消息。
6)Leader 向所有 Follower 廣播 commit 消息,同時自身也會完成事務提交。Follower 接收到 commit 消息后,會將上一條事務提交。
zookeeper 采用 Zab 協議的核心,就是只要有一台服務器提交了 Proposal,就要確保所有的服務器最終都能正確提交 Proposal。這也是 CAP/BASE 實現最終一致性的一個體現。
Leader 服務器與每一個 Follower 服務器之間都維護了一個單獨的 FIFO 消息隊列進行收發消息,使用隊列消息可以做到異步解耦。 Leader 和 Follower 之間只需要往隊列中發消息即可。如果使用同步的方式會引起阻塞,性能要下降很多。
Zab協議的事務過程圖解:
1、主節點廣播發送事務提交提議
包括以下步驟:
a.針對客戶端的事務請求,leader服務器會先將該事務寫到本地的log文件中
b.然后,leader服務器會為這次請求生成對應的事務Proposal並且為這個事務Proposal分配一個全局遞增的唯一的事務ID,即Zxid
c.leader服務器會為每一個follower服務器都各自分配一個單獨的隊列,將需要廣播的事務Proposal依次放入隊列中,發送給每一個follower
2、從節點接收到提議后,回復確認信息通知主節點
包括以下步驟:
d. 每一個follower在收到隊列之后,會從隊列中依次取出事務Proposal,寫入本地的事務日志中。如果寫成功了,則給leader返回一個ACK消息
3、主節點接收到超過法定數量從節點確認信息后,廣播發送事務提交命令到從節點
e. 當leader服務器接收到半數的follower的ACK相應之后,就會廣播一個Commit消息給所有的follower以通知其進行事務提交,同時leader自身也進行事務提交
當然,在這種簡化了的二階段提交模型下,是無法處理Leader服務器崩潰退出而帶來的數據不一致問題的,因此在ZAB協議中添加了另一個模式,即采用崩潰恢復模式來解決這個問題
整個消息廣播協議是基於具有FIFO特性的TCP協議來進行網絡通信的,因此能夠很容易地保證消息廣播過程中消息接收與發送的順序性
zookeeper 服務實現中很重要的一點:順序性。順序請求,順序響應;主節點事務順序提交,從節點按順序響應事務等等。
ZK性能問題
客戶端對ZK的更新操作都是永久的,不可回退的,也就是說,一旦客戶端收到一個來自server操作成功的響應,那么這個變更就永久生效了。為做到這點,ZK會將每次更新操作以事務日志的形式寫入磁盤,寫入成功后才會給予客戶端響應。明白這點之后,你就會明白磁盤的吞吐性能對於ZK的影響了,磁盤寫入速度制約着ZK每個更新操作的響應。
事務日志的寫性能確實對ZK性能,尤其是更新操作的性能影響很大,為了盡量減少ZK在讀寫磁盤上的性能損失,可以考慮使用單獨的磁盤作為事務日志的輸出(使用單獨的掛載點用於事務日志的輸出)
ZK的事務日志輸出是一個順序寫文件的過程,本身性能是很高的,所以盡量保證不要和其它隨機寫的應用程序共享一塊磁盤,盡量避免對磁盤的競爭。
參考文獻: