Zookeeper 的集群角色 集群中的 server 分為三種角色: , , 。 其中 是配置 明確定義的,角色 在一個zookeeper集群中有且只能有一個,是通過內部的選舉機制臨時產生的。 是集群中最重要的角色。負責響應集群的所有對Zookeeper數據狀態變更的請求。它會將每個狀態更新請求進 ...
Zookeeper 的集群角色
集群中的 server 分為三種角色:leader
, follower
, observer
。
- 其中
observer
是配置zoo.cfg
明確定義的,角色leader
在一個zookeeper集群中有且只能有一個,是通過內部的選舉機制臨時產生的。 leader
是集群中最重要的角色。負責響應集群的所有對Zookeeper數據狀態變更的請求。它會將每個狀態更新請求進行順序管理,以便保證整個集群內部消息處理的 FIFO,遵循了順序一致性(Sequential Consistency)。leader
內部維護 session ,來自客戶端的連接和斷開連接,都會被統一follower
或observer
轉發給leader
處理。leader
內部維護單調遞增的 Zxid(ZooKeeper Transaction Id
),針對客戶端連接,斷開連接,節點的寫操作都會分配一個全局唯一的Zxid,同時這些操作是原子性的,並且是嚴格順序性的,遵循ZAB
原子廣播一致性協議完成事務(transaction)操作。如果客戶端的所有寫操作,都會被follower
統一轉發給leader
處理。
follower
具有選舉權。負責提供給客戶端讀寫服務,需要響應leader
的提議observer
沒有選舉權。主要提供給客戶端讀服務,不提供寫服務,也不需要響應leader
的提議。也不需要日誌文件,因為沒有寫服務,沒有持久化的需要。
Server狀態
LOOKING
,競選狀態。FOLLOWING
,隨從狀態,同步leader
狀態,參與投票決策提案。OBSERVING
,觀察狀態,同步leader
狀態,不參與投票決策提案。LEADING
,領導者狀態,發起正常消息的提案。
Zookeeper 的存儲
zookeeper中的znode數據都是在記憶體中優先維護和提供讀服務,當事務被提交以及最終提交都會持久化到磁碟的日誌文件中。
Zookeeper 的內部網路拓撲
Zookeeper 在內部網路中如何實現兩兩連接的?
這裡暫且使用 10.0.2.30,10.0.2.31,10.0.2.32,10.0.2.33 替代 node1,node2,node3,node4,並依次啟動 zookeeper。
zoo.cfg
配置文件
server.1=10.0.2.30:2888:3888
server.2=10.0.2.31:2888:3888
server.3=10.0.2.32:2888:3888
server.4=10.0.2.33:2888:3888
依次使用 netstat
查看網路連接情況
- node1
可以看出來 node1作為服務節點,由 node2,node3,node4 通過 3888埠建立連接進來。
node1 作為客戶端連接 node3 (目前node3是leader
) 的2888埠。
- node2
可以看出來 node2作為服務節點,由 node3,node4 通過 3888埠建立連接進來。
但是 node2 作為客戶端連接node1的3888埠。
node2 作為客戶端連接 node3 (目前node3是leader
) 的2888埠。
- node3
可以看出來 node3作為服務節點,由 node4 通過 3888埠建立連接進來。
但是 node3 作為客戶端連接node1,node2 的3888埠。
node3 作為leader
節點,由 node1,node2 ,node4 通過 3888埠建立連接進來。
至於為什麼 node3能當選 leader 呢?可以在下麵的 選舉過程中 得到進一步詳細的闡述。
- node4
可以看出來 node4 作為客戶端連接node1,node2 ,node3 的3888埠。
node4 作為客戶端連接 node3 (目前node3是leader
) 的2888埠。
- 結論
Zookeeper 在內部網路中如圖所示,依據zoo.cfg
的配置後續的server都逐個連接前面的server的3888埠,這樣就形成了兩兩連接的拓撲,同時也不冗餘。
而當leader
當選時,會開放2888埠,其他follower
連接其2888埠。
ZAB(原子廣播,Zookeeper Atomic Broadcast
)
https://zookeeper.apache.org/doc/current/zookeeperInternals.html
ZAB(Zookeeper Atomic Broadcast
)原子廣播是 Paxos
分散式一致性協議演算法(http://zh.wikipedia.org/zh-cn/Paxos) 的一個簡化版本。
首先有以下概念,我們需要瞭解:
- 數據包(
Packet
):通過 FIFO Channel 發送的位元組數組。 - 提案(
Proposal
):協議的單位。通過與ZooKeeper中的法定server交換數據包來達成協議。大多數提案都包含消息,但是NEW_LEADER Proposal
提案是不包含消息。 - 消息(
Message
):要自動廣播到所有ZooKeeper伺服器的位元組數組。消息被包含在一個提案(Proposal
)中,並且只有在提案(Proposal
)被通過後消息才會最終交付delivered
(提交到事務日誌和更新記憶體的統一視圖)。 - 法定人員 (
Quorum
):有 Zookeeper集群中非observer
角色的所有伺服器節點組成,具有投票通過提案(Proposal
)的權力。
在 Zookeeper 中提供以下的保證數據的嚴格順序:
- 傳遞可靠性:如果一個消息被一個server最終交付
delivered
,那麼這個消息最終也被其他所有的server最終交付delivered
,這裡指最終一致性。 - 順序全局性:如果一個消息a先於b被一個server最終交付
delivered
,那麼消息a也是先於b被其他所有的server最終交付delivered
。 - 順序傳遞性:如果消息a先於b被髮送到server,消息b先於c被髮送到server,那麼消息a也是先於c被server接收的。
如上所述,ZooKeeper保證消息的總順序,也保證建議的總順序。
ZooKeeper使用ZooKeeper transaction id
(zxid) ,這是一個全局的唯一的ID。提出提案(Proposal
)時,所有提案都將附上zxid,進而保證全局的順序性。
-
leader
將提案(Proposal
)將發送到所有ZooKeeper伺服器。 -
在法定人員(
Quorum
)收到後,會確認(acknowledge
)回覆這個提案(Proposal
)給leader
。
其中確認acknowledge
提案(Proposal
)表示伺服器已將提案(Proposal
)持久化到日誌中。
稍微註意一下:法定人員(Quorum
)收到提案(Proposal
),只存在確認(acknowledge
),或者因為網路等原因超時響應,不存在反對(reject
)。
-
只要一但滿足半數以上(大於所有法定人員的一半)確認
acknowledge
後,leader
就會進入正式提交(Commit
)。 -
如果提案(
Proposal
)中包含一條消息,則在提交時將最終交付delivered
該消息。
ZooKeeper消息傳遞包括兩個階段:
- leader選舉(
Leader activation
):在此階段,leader
被選舉出來,集群開始變為對外可用狀態,並準備開始提出提案(Proposal
)。 - 活動消息傳遞(
Active messaging
):在此階段,leader
開始接受消息(Message
),併發起提案(Proposal
),協調和決策以提交(Commit
)提案(Proposal
)。
leader選舉
leader
產生的條件:
- 具有最新的 Zxid,如果 存在多個server都有最新的Zxid,在投票過程中選取建立網路連接中 myid最大的。
leader
和其連接的follower
的個數必須滿足半數以上(大於所有法定人員的一半)。
當集群中任意具有選舉權的server發現leader掛了:
- 該 server 會觸發
NEW_LEADER Proposal
提案,給自己投票,並通過 ZAB 廣播給所有連接的 server。 - 接受到
NEW_LEADER Proposal
提案的server,如果有被選舉權,則會觸發它的投票行為:- 先比較zxid,最新的勝出,如果zxid相同,再比較myid,最大的勝出。
- 最後將勝出的內容,通過 ZAB 廣播給所有連接的 server。
- 最終滿足
leader
條件的server,將被選出,同時follower
也被廣播獲得Proposal
的提交。
以上中的 網路拓撲 為什麼 node3能當選 leader 呢?
- node1 啟動時,給自己投票,因為其他server尚沒啟動,因為 node1 依然在
LOOKING
競選狀態。 - node2 啟動完,給自己投票,同時與 node1 交換了Zxid和myid,node2 勝出,但因為沒有達到半數以上法定人員,所以node1,node2 依然處於
LOOKING
競選狀態。 - node3 啟動完,給自己投票,同時與 node1 ,node2 交換了Zxid和myid,node3 勝出,也達到半數以上法定人員(3 > 4/2),因此 node3 被選舉為
leader
。 - node4 啟動完,給自己投票,同時與 node1 ,node2 ,node3交換了Zxid和myid,node3的Zxid最新,因此 node4 追隨 node3。
活動消息傳遞
消息的傳遞一般指寫請求。
- 當
follower
接收到 客戶端的 寫請求後,會轉發給leader
順序處理。 leader
收到寫請求,會檢查數據問題,如無問題,創建一個新的提案proposal
加入toBeApplied
FIFO 隊列,內容是寫請求的消息,並附上全局的ZXid。leader
每次toBeApplied
FIFO 隊列頭部取到一個提案proposal
,通過 ZAB 廣播給所有的follower
,處於 pending 等待回覆。follower
收到提案proposal
後,記錄提案proposal
持久化到磁碟的日誌文件中,然後確認(acknowledge
)回覆這個提案(Proposal
)給leader
。leader
處於 pending 等待回覆,一旦收到follower
加上自己的確認(acknowledge
)超過半數法定人員(Quorum
),就會觸發Commit
階段,發送commit
請求給所有的follower
,發送info
請求所有的observer
。
同時,leader
將提案proposal
放入 committedRequest 隊列,並從toBeApplied
FIFO 隊列移出該 提案proposal
。follower
收到Commit
後,會更新自己的記憶體數據,統一數據視圖。observer
收到info
後,會更新自己的記憶體數據,統一數據視圖。
針對客戶端的讀請求,則不需要轉發給leader
處理。
當然如果是客戶端的sync
命令,則會觸發客戶端連接的follower
或observer
向leader
請求同步數據狀態。
@SvenAugustus(https://www.flysium.xyz/)
更多請關註微信公眾號【編程不離宗】,專註於分享伺服器開發與編程相關的技術乾貨: