分區機制
Kafka 的分區機制是其實現高吞吐和可擴展性的重要特性之一。
Kafka 中的數據具有三層結構,即主題(topic)-> 分區(partition)-> 消息(message)。一個 Kafka 主題可以包含多個分區,而每個分區又可以包含多條消息。
Topic和Partition是kafka中比較重要的概念。
- 主題:Topic是Kafka中承載消息的邏輯容器。可以理解為一個消息隊列。生產者將消息發送到特定的Topic,消費者從Topic中讀取消息。Topic可以被認為是邏輯上的消息流。在實際使用中多用來區分具體的業務。
- 分區:Partition。是Topic的物理分區。一個Topic可以被分成多個Partition,每個Partition是一個有序且持久化存儲的日志文件。每個Partition都存儲了一部分消息,并且有一個唯一的標識符(稱為Partition ID)。
好處:
- 提升吞吐量:通過將一個Topic分成多個Partition,可以實現消息息的并行處理。每個Partition可以由不同的消費者組進行獨立消費,這樣就可以提高整個系統的吞吐量。
- 負載均衡:Partition的數量通常比消費者組的數量多,這樣可以使每個消費者組中的消費者均勻地消費消息。當有新的消費者加入或離開消費者組時,可以通過重新分配Partition的方式進行負載均衡。
- 擴展性:通過增加Partition的數量,可以實現Kafka集群的廣展性。更多的Partition可以提供更高的并發處理能力和更大的存儲容量。
重平衡機制
Kafka的重平衡機制是指在消費者組中新增或刪除消費者時,Kafka集群會重新分配主題分區給各個消費者,以保證每個消費者消費的分區數量盡可能均衡。
重平衡機制的目的是實現消費者的負載均衡和高可用性,以確保每個消費者都能夠按照預期的方式消費到消息。
重平衡的3個觸發條件:
- 消費者組成員數量發生變化。
- 消費者組成員訂閱主題數量發生變化。
- 訂閱主題的分區數發生變化。
平衡機制步驟:
- 暫停消費:在重平衡開始之前,Kafka會暫停所有消費者的拉取操作,以確保不會出現重平衡期間的消息丟失或重復消費。
- 計算分區分配方案:kafka集群會根據當前消費者組的消費者數量和主題分區數量,計算出每個消費者應該分配的分區列表,以實現分區的負載均衡。
- 通知消費者:一旦分區分配方案確定,Kafka集群會將分配方案發送給每個消費者,告訴它們需要消費的分區列表,并請求它們重新加入消費者組。
- 重新分配分區:在消費者重新加入消費者組后,Kafka集群會將分區分配方案應用到實際的分區分配中,重新分配主題分區給各個消費者。
- 恢復消費:最后,Kafka會恢復所有消費者的拉取操作,允許它們消費分配給自己的分區。
Kafka的重平衡機制能夠有效地實現消費者的負載均衡和高可用性,提高消息的處理能力和可靠性。但是,由于重平衡會帶來一定的性能開銷和不確定性,例如:消息亂序、重復消費等問題,因此在設計應用時需要考慮到重平衡的影響,并采取一些措施來降低重平衡的頻率和影響。
在重平衡過程中,所有Consumer實例都會停止消費。等待重平衡完成。但是目前并沒有什么好的辦法來解決重平衡帶來的STW,只能盡量避免它的發生。
Consumer實例五種狀態
- Empty:組內沒有任何成員,但是消費者可能存在已提交的位移數據,而且這些位移尚未過期。
- Dead:同樣是組內沒有任何成員,但是組的元數據信息已經被協調者端移除,協調者保存著當前向他注冊過的所有組信息。
- Preparing Rebalance:費者組準備開啟重平衡,此時所有成員都需要重新加入消肖費者組
- Completing Rebalance:消費者組下所有成員已經加入,各個成員中等待分配方案
- Stable:消費者組的穩定狀態,該狀態表明重平衡已經完成,組內成員能夠正常消費數據
Leader選舉機制
Partition Leader 選舉
Kafka中的每個Partition都有一個Leader,負責處理該Parttition的讀寫請求。在正常情況下。Leader和ISR集合中的所有副本保持同步,Leader接收到的消息也會被ISF集合中的副本所接收。當leader副本宕機或者無法正常工作時,需要選舉新的leader副本來接管分區的工作。
Leader選舉的過程如下:
- 每個參與選舉的副本會嘗試向ZooKeeper上寫入一個臨時節點,表示它們正在參與Leader選舉
- 所有寫入成功的副本會在ZooKeeper上創建一個序列號節點,并將自己的節點序列號寫入該節點
- 節點序列號最小的副本會被選為新的Leader,并將自己的節點名稱寫入ZooKeeper上的/broker/…/leader節點中。
Controller選舉
Kafka集群中只能有一個Controller節點,用于管理分區的副本分配、leader選舉等任務。當一個Broker變成Controller后,會在Zookeeper的/controller節點中記錄下來。然后其他的Broker會實時監聽這個節點,主要就是避免當這個controller宕機的話,就需要進行重新選舉。
Controller選舉的過程如下:
- 所有可用的Broker向ZooKeeper注冊自己的ID。并監聽Zookeeper中/controller節點的變化。
- 當Controller節點出現故障時,ZooKeeper會刪除/controller節點,這時所有的Broker都會監聽到該事件,并開始爭奪Controller的位置。為了避免出現多個Broker同時競選Controller的情況,Kafka設計了一種基于ZooKeeper的Master-Slave機制,其中一個Broker成為Master,其它Broker成為為Slave。Master負責選舉Controller,并將選舉結果寫入ZooKeeper中,而Slave則監聽/controller節點的變化,一旦發現Master發生故障,則開始爭奪Master的位置。
- 當一個Broker發現Controller失效時,它會向ZooKeeper寫入自自己的ID,并嘗試競選Controller的位置。如果他創建臨時節點成功,則該Broker成為新的Controller,并將選舉結果寫入ZooKeeper中。
- 其它的Broker會監聽到ZooKeeper中/controller節點的變化,一旦發現選舉結果發生變化,則更新自己的元數據信息,然后與新的Controller建立連接,進行后續的操作。
高水位HW機制
高水位(HW,HighWatermark)是Kafka中的一個重要的概念,主要是用于管理消費者的進度和保證數據的可靠性的。
高水位標識了一個特定的消息偏移量(offset),即一個分區中已提交(這里的已提交指的是ISR中的所有副本都記錄了這條消息)消息的最高偏移量(offset),消費者只能拉取到這個offset之前的消息。消費者可以通過跟蹤高水位來確定自己消費的位置。
在Kafka中,HW主要有兩個作用:
- 消費進度管理:消費者可以通過記錄上一次消費的偏移量,然后將其與分區的高水位進行比較,來確定自己的消費進度。消費者可以在和高水位對比之后繼續消費新的消息,確保不會錯過任何已提交的消息。這樣,消費者可以按照自己的節奏進行消費,不受其他消費者的響。
- 數據的可靠性:高水位還用于確保數據的可靠性。在Kafka中,只有消息被寫入主副本(Leader Replica)并被所有的同步副本(In-Sync Replicas,ISR)確認后,才被認為是是已提交的消息。高水位表示已經被提交的消息的邊界。只有高水位之前的消息才能被認為是已經被確認的,其他的消息可能會因為副本故障或其他原因而丟失。當消費者消費消息,可以使用高水位作為參考點,只消費高水位之前的消息,以確保消費的是已經被確認的消息,從而保證數據的可靠性。
還有一個概念,叫做LEO,即LogEnd Offset,,他是日志最后消息的偏移量。它標識當前日志文件中下一條待寫入消息的offset。
它有以下特點和作用:
- 用于表示副本寫入下一條消息的位置。
- 每個副本(包括 leader 副本和 follower 副本)都有自己的 LEO。
- LEO 的值會隨著消息的寫入而增加,每當有新消息寫入底層日志成功時,相應副本的 LEO 就會加 1。
- LEO 主要用于跟蹤副本的同步進度。
需要注意的是,在 0.11.0.0 版本之前,HW 的更新可能存在一些問題,例如在特定情況下可能導致消息丟失。0.11.0.0 及之后的版本使用 leader epoch,與 HW 值結合,從而更好地保證了數據的一致性和順序性。
- 每個分區都有一個初始的LeaderEpoch,通常為0。
- 當Leader副本發生故障或需要進行切換時,Kafka會觸發副本切換過程。
- 副本切換過程中,Kafka會從ISR(In-Sync Replicas,同步副本)中選擇一個新的Follower副本作為新的Leader副本。
- 新的Leader副本會增加自己的Leader Epoch,使其大于之前的Leader Epoch。這表示進入了一個新的任期。
- 新的Leader副本會驗證舊Leader副本的狀態以確保數據的一致性。它會檢查舊Leader副本的Leader Epoch和高水位。
- 如果舊Leader副本的Leader Epoch小于等于新Leader副本的Leadder Epoch,并且舊Leader副本的高水位小于等于新Leader副本的高水位,則驗證通過。
- 一旦驗證通過,新的Leader副本會開始從ISR中的一部分副本中尋找最大的LEO副本進行復制數據,以確保新Leader上的數據與舊Leader-致。
- 一旦新的Leader副本復制了舊Leader副本的所有數據,并達到了與舊Leader副本相同的高水位,副本切換過程就完成了。
通過使用Leader Epoch、高水位、LEO的驗證,Kafka可以避免新的Leader副本接受舊Leader副本之后的消息,從而避免數據回滾和丟失。Leader Epoch 為 Kafka 提供了一種更可靠和一致的副本管理機制,確保了在 Leader 副本切換等情況下數據的完整性和正確性。