Kakfa複製機制
- 微信公眾號:阿俊的學習記錄空間
- 小紅書:ArnoZhang
- wordpress:arnozhang1994
- 部落格園:arnozhang
- CSDN:ArnoZhang1994
Kafka 將每個主題的分割槽日誌複製到可配置數量的伺服器上(可以為每個主題設定不同的複製因子)。這樣在叢集中某個伺服器發生故障時,Kafka可以自動切換到這些副本上,以確保訊息在出現故障時依然可用。
其他訊息系統也提供與複製相關的功能,但我們認為,這些功能往往是後期新增的,使用較少且存在明顯的缺點:副本處於非活躍狀態,吞吐量大幅下降,且需要複雜的手動配置等。而 Kafka 預設就設計為支援複製的系統——實際上,我們將非複製的主題視為只有一個副本的複製主題。
Kafka 的複製單位是主題分割槽。在沒有故障的情況下,每個分割槽都有一個主節點(leader)和零個或多個副節點(follower)。包括主節點在內的所有副本的總數就是複製因子。所有寫操作都傳送到主節點,讀操作則可以從主節點或副節點讀取。通常,分割槽的數量比代理伺服器(broker)多,且主節點會均勻分佈在代理伺服器之間。副節點的日誌與主節點的日誌相同,具有相同的偏移量和訊息順序(雖然主節點可能會有少量未複製的訊息)。
副節點像普通消費者一樣從主節點消費訊息,並將其應用到自己的日誌中。透過讓副節點從主節點拉取訊息,可以自然地批次處理日誌條目。
在分散式系統中,自動處理故障需要明確定義節點何時算作“存活”。在 Kafka 中,有一個特殊的節點稱為“控制器”(controller),負責管理叢集中代理的註冊。代理的存活有兩個條件:
- 代理必須與控制器保持活躍會話,以接收定期的後設資料更新。
- 作為副節點的代理必須從主節點複製寫入操作,並且不能落後太多。
“活躍會話”的定義取決於叢集配置。對於 KRaft 叢集,活躍會話是透過向控制器傳送定期心跳來維護的。如果控制器在配置的 broker.session.timeout.ms
時間內沒有收到心跳,節點將被視為離線。
對於使用 Zookeeper 的叢集,存活性透過 Zookeeper 上的臨時節點間接確定。代理在初始化 Zookeeper 會話時建立一個臨時節點,如果代理在 zookeeper.session.timeout.ms
過期前未傳送心跳導致會話丟失,該節點將被刪除,控制器透過 Zookeeper 的監視機制注意到節點刪除並將代理標記為離線。
我們稱滿足這些條件的節點為“同步”(in sync),以避免“存活”或“失敗”的模糊性。主節點會跟蹤同步副本集合(ISR)。如果某個代理不滿足這些條件,它將從 ISR 中移除。例如,如果一個副節點當機,控制器會注意到會話的丟失並將其移除。如果副節點落後於主節點太多但仍保持活躍會話,主節點也會將其從 ISR 中移除。滯後副本的判斷透過 replica.lag.time.max.ms
配置控制。如果副節點在最大時間內無法追趕上主節點日誌的末尾,將被移除出 ISR。
在分散式系統術語中,Kafka 僅處理“故障/恢復”模型的故障,即節點突然停止工作,隨後恢復(可能不知自己曾當機)。Kafka 不處理所謂的“拜占庭故障”,即節點產生任意或惡意響應。
我們可以更精確地定義訊息的提交。當分割槽中所有 ISR 副本都將訊息應用到日誌時,訊息才算提交。只有提交的訊息才會提供給消費者。這意味著消費者無需擔心在主節點故障時會看到可能丟失的訊息。生產者可以選擇等待訊息提交或立即返回,這取決於他們對延遲和永續性的權衡偏好,該偏好透過生產者的 acks
設定控制。注意,主題還有一個設定用於指定同步副本的最小數量,生產者在請求訊息寫入所有同步副本時會檢查這個數量。如果生產者請求的確認較少,訊息可以在同步副本數量低於最小值時提交併被消費(例如,僅主節點也可以提交)。
Kafka 保證已提交的訊息不會丟失,只要始終有一個同步副本線上。
Kafka 在節點故障後的短暫切換期間仍然可用,但在網路分割槽的情況下可能不可用。
複製日誌:多數決機制、ISR 和狀態機
Kafka 的每個分割槽本質上是一個複製日誌。複製日誌是分散式資料系統中最基礎的原語之一,有多種實現方法。複製日誌可以用作其他分散式系統的原語來實現狀態機風格的系統。
複製日誌的核心是對一系列值的順序達成共識(通常按 0、1、2... 編號)。最簡單、最快速的實現方式是透過主節點選擇值的順序,只要主節點存活,副節點只需複製主節點的值及其順序。
當然,如果主節點不會故障,我們就不需要副節點了!當主節點故障時,我們需要從副節點中選出新的主節點。然而,副節點可能落後或當機,因此我們必須確保選擇最新的副節點。日誌複製演算法的核心保證是:如果我們告訴客戶端訊息已提交,即使主節點當機,新選出的主節點也必須有這條訊息。這意味著如果主節點等待更多的副節點確認訊息提交,可能會有更多可選的主節點。
如果你選擇了合適的確認數量,並確保在選舉主節點時比較日誌時存在交集,那麼這被稱為“多數決機制”。
一種常見的做法是使用多數票來決定提交和選舉主節點。儘管 Kafka 沒有采用這種方式,但為了理解其權衡,我們還是先探討一下。假設有 2f+1 個副本,如果在提交訊息前需要 f+1 個副本接收到訊息,而在選舉主節點時從至少 f+1 個副本中選出日誌最完整的副本作為新的主節點,那麼在最多 f 個副本故障的情況下,新的主節點將保證擁有所有已提交的訊息。多數決機制的一個優勢是,延遲只取決於最快的伺服器。例如,若複製因子為 3,延遲取決於較快的副節點,而非較慢的副節點。
Kafka 採用的是另一種方式,透過動態維護同步副本集合(ISR)。只有這些副本才有資格選舉為主節點。Kafka 在分割槽寫入訊息時,只有當所有同步副本都收到訊息,寫入才被視為提交。ISR 集合在每次變更時儲存在叢集後設資料中,因此只要副本在 ISR 中,就有資格成為新的主節點。
Kafka 允許客戶端選擇是否在訊息提交時阻塞,且由於所需的複製因子較低,Kafka 的吞吐量和磁碟空間利用率也相對較高。
另一個重要的設計區別是 Kafka 並不要求崩潰的節點在恢復後保留其所有資料。許多複製演算法依賴於“穩定儲存”,即保證在任何故障恢復場景中不會丟失資料。Kafka 的協議允許副本重新加入 ISR 時,確保即便該副本在崩潰時丟失了未刷寫的資料,依然可以透過重新同步完全恢復。