復制
Kafka可以通過可配置的服務器數量復制每個主題分區的日志(可以為每個主題設置復制因子)。這允許在集群中的服務器發生故障時自動故障轉移到其他副本,因此在存在故障的情況下,消息仍然可用。
其他消息傳遞系統提供了一些復制相關的功能,這似乎是一個固定的事情,沒有被大量使用,並且有很大的缺點:從站是非活動的,吞吐量受到很大的影響,虛擬手動配置等。默認情況下,Kafka旨在與復制配合使用 - 事實上,我們將復制因子為1的未復制的主題實現為復制主題。
復制單位是主題分區。在非故障條件下,Kafka的每個分區都有一個leader和零個或多個follower。包括領導者的副本總數構成復制因子。所有的讀寫操作都在leader分區進行。通常,leader的數量多於broker數量,leader在broker之間平均分配。follower上的日志與leader上的日志相同 - 所有這些日志都以相同的順序具有相同的偏移量和消息(盡管當然,在任何給定的時間,leader可能在其日志結尾處有一些尚未復制的消息)。
Follower像Consumer那樣從kafka leader消費消息,並應用到自己的日志中。讓Kafka的follower從leader中拉取數據可以很好的進行批處理。
與大多數分布式系統自動處理故障一樣,需要對節點“活着”的意義進行精確定義。對於kafka節點活躍有兩個條件:
- 節點必須能夠與ZooKeeper保持會話(通過ZooKeeper的心跳機制)
- 如果它是一個follower,它必須復制發生在leader上寫操作,而不是落后於“太遠”
我們將滿足這兩個條件的節點稱為“同步”,以避免“活着”或“失敗”的模糊。leader跟蹤一組“同步”節點。如果follower死亡,卡住或落后,領導者將從同步副本列表中刪除它。滯后副本的確定由replica.lag.time.max.ms配置控制。
在分布式系統術語中,我們只嘗試處理一個“失敗/恢復”模式的失敗,其中節點突然停止工作,然后再恢復)。Kafka不處理所謂的“拜占庭”故障,其中節點產生任意或惡意的響應。
當該分區的所有同步副本已將其應用於其日志時,消息被視為“已提交”。只有“提交”的消息才會被給予消費者。這意味着消費者無需擔心如果leader失敗,可能會看到可能丟失的消息。另一方面,生產者可以選擇等待消息被提交,這取決於他們偏好延遲和耐久性之間的權衡。此偏好由生產者使用的acks設置控制。
Kafka提供的保證是,只要至少有一個同步復制存活的情下消息不會丟失.
Kafka在並節點故障短時間故障轉移期后仍然可用,但在網絡分區存在的情況下可能無法保持可用。
Unclean leader election: What if they all die?
Kafka對數據丟失的保證是基於至少一個副同保持同步。如果復制分區的所有節點都宕機,則此保證不再成立。當所有副本死亡時,有兩種行為可以執行:
- 等待ISR中的一個副本重新存活,並選擇這個副本作為Leader(希望它仍然擁有所有的數據)。
- 選擇第一個副本(不一定在ISR中)作為領導者恢復生活的。
這是在可用性和一致性之間的折衷。如果我們等待ISR中的副本,那么只要這些副本已經關閉,我們將保持不可用。如果這樣的副本被毀壞或數據丟失,那么我們永久性地失效。另一方面,如果不同步的副本恢復生活,並且允許它成為領導者,那么它的日志也成為真理的根源,即使它不保證每一個已經提交的消息,默認情況下,Kafka選擇第二種策略,並且在ISR中的所有副本都死亡時選擇潛在的不一致副本。可以使用配置屬性unclean.leader.election.enable禁用此行為,以支持停機時間優於不一致的用例。
這個困境不是kafka特有的。它存在於任何基於quorum-based scheme。例如在多數投票計划中,如果大多數服務器遭受永久性故障,那么您必須選擇丟失100%的數據或違反一致性,將現有服務器上剩下的內容作為新的真實來源。
可用性和耐久性保證
在生產者寫入消息到Kafka時,生產者可以選擇是否等待消息被0,1或全部(-1)副本確認。請注意,“所有副本的確認”不能保證全部已分配的副本已收到該消息。默認情況下,當acks = all時,一旦所有當前在ISR中的副本收到消息,就會發生確認。例如,如果主題僅配置了兩個副本,並且一個主題失敗(即中只有一個副本在ISR),則指定acks = all的寫入將成功。但是,如果剩余副本也失敗,這些寫入可能會丟失。盡管這確保了分區的最大可用性,但是對於那些喜歡持久性超過可用性的用戶而言,這種行為可能是不希望的。因此,Kafka提供兩個主題級別的配置,可用於優先於消息持久性超過可用性:
- 禁止unclean leader election:如果所有副本都不可用,則分區將保持不可用,直到最近的領導者再次可用(最近指的是副本中保存的數據可leader最近)。這樣做有效地避免了消息丟失的風險。
- 指定最小ISR大小 :如果ISR的大小大於某個最小值,則分區才接受數據寫入,以防止寫入單個副本的消息在副本不可用時丟失。此設置僅在生產者使用acks = all並且確保該消息至少會被許多ISR中副本確認的情況下生效。此設置提供了一致性和可用性之間的權衡。更大的最小ISR設置保證更好的一致性,因為消息被保證被寫入更多的副本,這降低了丟失的可能性。但是,如果同步副本的數量下降到最小閾值以下,則分區對於寫入將不可用,因此可以降低可用性。
復制管理
在Kafka集群將管理數百或數千個Topic分區。kafka以round-robin方式來平衡群集中的分區,以避免將大量topic的所有分區都聚集在少量的節點上。同樣,kafka嘗試平衡broker上的leader數量,以便每個節點都是其分區的比例份額的leader。
優化領導選舉過程同樣重要,因為這是不可用的關鍵窗口。一個幼稚的傻的實現是當節點故障,leader將在運行中的所有分區中選舉一個節點來托管。相反的,我們選出一個broker作為“控制器”。這個控制器檢查broker級別故障和負責改變所有故障的broker中的受影響的leader的分區,這樣的好處是,我們能夠批量處理多個需要leader變更的分區,這使得選舉更廉價、更快。如果控制器發生故障,在幸存的broker之中,將選舉一個成為新的控制器。