一文徹底搞清 Kafka 的副本複製機制

也可以到過往記憶大數據博客閱讀(點擊下面閱讀原文即可) https://www.iteblog.com/archives/2556.html

讓分佈式系統的操作變得簡單,在某種程度上是一種藝術,通常這種實現都是從大量的實踐中總結得到的。Apache Kafka 的受歡迎程度在很大程度上歸功於其設計和操作簡單性。隨着社區添加更多功能,開發者們會回過頭來重新思考簡化複雜行爲的方法

Apache Kafka 中一個更細微的功能是它的複製協議(replication protocol)。對於單個集羣上不同大小的工作負載,調整 Kafka replication 以讓它適用不同情況在今天來看是有點棘手的。使這點特別困難的挑戰之一是如何防止副本從同步副本列表(也稱爲ISR)加入和退出。從用戶的角度來看,這意味着如果生產者(producer )發送一批“足夠大”的消息,那麼這可能會導致 Kafka brokers 發出多個警報。這些警報表明某些主題“未被複制”(under replicated),這意味着數據未被複制到足夠多的 brokers 上,從而增加數據丟失的可能性。因此,Kafka cluster 密切監控“未複製的”分區總數非常重要。在這篇文章中,我將討論導致這種行爲的根本原因以及我們如何解決這個問題。

一分鐘瞭解 Kafka 複製機制

Kafka 主題中的每個分區都有一個預寫日誌(write-ahead log),我們寫入 Kafka 的消息就存儲在這裏面。這裏面的每條消息都有一個唯一的偏移量,用於標識它在當前分區日誌中的位置。如下圖所示:

如果想及時瞭解Spark、Hadoop或者HBase相關的文章,歡迎關注微信公衆號:iteblog_hadoop

Kafka 中的每個主題分區都被複制了 n 次,其中的 n 是主題的複製因子(replication factor)。這允許 Kafka 在集羣服務器發生故障時自動切換到這些副本,以便在出現故障時消息仍然可用。Kafka 的複製是以分區爲粒度的,分區的預寫日誌被複制到 n 個服務器。在 n 個副本中,一個副本作爲 leader,其他副本成爲 followers。顧名思義,producer 只能往 leader 分區上寫數據(讀也只能從 leader 分區上進行),followers 只按順序從 leader 上覆制日誌。

如果想及時瞭解Spark、Hadoop或者Hbase相關的文章,歡迎關注微信公衆號:iteblog_hadoop

日誌複製算法(log replication algorithm)必須提供的基本保證是,如果它告訴客戶端消息已被提交,而當前 leader 出現故障,新選出的 leader 也必須具有該消息。在出現故障時,Kafka 會從掛掉 leader 的 ISR 裏面選擇一個 follower 作爲這個分區新的 leader ;換句話說,是因爲這個 follower 是跟上 leader 寫進度的。

每個分區的 leader 會維護一個 in-sync replica(同步副本列表,又稱 ISR)。當 producer 往 broker 發送消息,消息先寫入到對應 leader 分區上,然後複製到這個分區的所有副本中。只有將消息成功複製到所有同步副本(ISR)後,這條消息纔算被提交。由於消息複製延遲受到最慢同步副本的限制,因此快速檢測慢副本並將其從 ISR 中刪除非常重要。Kafka 複製協議的細節會有些細微差別,本博客並不打算對該主題進行詳盡的討論。感興趣的同學可以到這裏詳細瞭解 Kafka 複製的工作原理。

副本在什麼情況下才算跟上 leader

一個副本如果它沒有跟上 leader 的日誌進度,那麼它可能會被標記爲不同步的副本。我通過一個例子來解釋跟上(caught up)的含義。假設我們有一個名爲 foo 的主題,並且只有一個分區,同時複製因子爲 3。假設此分區的副本分別在 brokers 1,2和3上,並且我們已經在主題 foo 上提交了3條消息。brokers 1上的副本是 leader,副本2和3是 followers,所有副本都是 ISR 的一部分。假設 replica.lag.max.messages 設置爲4,這意味着只要 follower 落後 leader 的消息不超過3條,它就不會從 ISR 中刪除。我們把 replica.lag.time.max.ms 設置爲500毫秒,這意味着只要 follower 每隔500毫秒或更早地向 leader 發送一個 fetch 請求,它們就不會被標記爲死亡並且不會從 ISR 中刪除。

如果想及時瞭解Spark、Hadoop或者Hbase相關的文章,歡迎關注微信公衆號:iteblog_hadoop

現在假設 producer 往 leader 上發送下一條消息,與此同時,broker 3 上發生了 GC 停頓,現在每個 broker 上的分區情況如下所示:


如果想及時瞭解Spark、Hadoop或者Hbase相關的文章,歡迎關注微信公衆號:iteblog_hadoop

由於 broker 3 在 ISR中,因此在將 broker 3從 ISR 中移除或 broker 3 上的分區跟上 leader 的日誌結束偏移之前,最新消息都是不認爲被提交的。注意,由於 border 3 落後 leader 的消息比 replica.lag.max.messages = 4 要小,因此不符合從 ISR 中刪除的條件。這意味着 broker 3 上的分區需要從 leader 上同步 offset 爲 3 的消息,如果它做到了,那麼這個副本就是跟上 leader 的。假設 broker 3 在 100ms 內 GC 完成了,並且跟上了 leader 的日誌結束偏移,那麼最新的情況如下圖:

如果想及時瞭解Spark、Hadoop或者Hbase相關的文章,歡迎關注微信公衆號:iteblog_hadoop

什麼情況下會導致一個副本與 leader 失去同步

一個副本與 leader 失去同步的原因有很多,主要包括:

  • 慢副本(Slow replica):follower replica 在一段時間內一直無法趕上 leader 的寫進度。造成這種情況的最常見原因之一是 follower replica 上的 I/O瓶頸,導致它持久化日誌的時間比它從 leader 消費消息的時間要長;

  • 卡住副本(Stuck replica):follower replica 在很長一段時間內停止從 leader 獲取消息。這可能是以爲 GC 停頓,或者副本出現故障;

  • 剛啓動副本(Bootstrapping replica):當用戶給某個主題增加副本因子時,新的 follower replicas 是不同步的,直到它跟上 leader 的日誌。

當副本落後於 leader 分區時,這個副本被認爲是不同步或滯後的。在 Kafka 0.8.2 中,副本的滯後於 leader 是根據 replica.lag.max.messages 或 replica.lag.time.max.ms 來衡量的;前者用於檢測慢副本(Slow replica),而後者用於檢測卡住副本(Stuck replica)。

如何確認某個副本處於滯後狀態

通過 replica.lag.time.max.ms 來檢測卡住副本(Stuck replica)在所有情況下都能很好地工作。它跟蹤 follower 副本沒有向 leader 發送獲取請求的時間,通過這個可以推斷 follower 是否正常。另一方面,使用消息數量檢測不同步慢副本(Slow replica)的模型只有在爲單個主題或具有同類流量模式的多個主題設置這些參數時才能很好地工作,但我們發現它不能擴展到生產集羣中所有主題。在我之前的示例的基礎上,如果主題 foo 以 2 msg/sec 的速率寫入數

據,其中 leader 收到的單個批次通常永遠不會超過3條消息,那麼我們知道這個主題的 replica.lag.max.messages 參數可以設置爲 4。爲什麼?因爲我們以最大速度往 leader 寫數據並且在 follower 副本複製這些消息之前,follower 的日誌落後於 leader 不超過3條消息。同時,如果主題 foo 的 follower 副本始終落後於 leader 超過3條消息,則我們希望 leader 刪除慢速 follower 副本以防止消息寫入延遲增加。

這本質上是 replica.lag.max.messages 的目標 - 能夠檢測始終與 leader 不同步的副本。假設現在這個主題的流量由於峯值而增加,生產者最終往 foo 發送了一批包含4條消息,等於 replica.lag.max.messages = 4 的配置值。此時,兩個 follower 副本將被視爲與 leader 不同步,並被移除 ISR。

如果想及時瞭解Spark、Hadoop或者Hbase相關的文章,歡迎關注微信公衆號:iteblog_hadoop

但是,由於兩個 follower 副本都處於活動狀態,因此它們將在下一個 fetch 請求中趕上 leader 的日誌結束偏移量並被添加回 ISR。如果生產者繼續向 leader 發送大量的消息,則將重複上述相同的過程。這證明了 follower 副本進出 ISR 時觸發不必要的錯誤警報的情況。

如果想及時瞭解Spark、Hadoop或者Hbase相關的文章,歡迎關注微信公衆號:iteblog_hadoop

replica.lag.max.messages 參數的核心問題是,用戶必須猜測如何配置這個值,因爲我們不知道 Kafka 的傳入流量到底會到多少,特別是在網絡峯值的情況下。

一個參數搞定一切

我們意識到,檢測卡住或慢速副本真正重要的事情,是副本與 leader 不同步的時間。我們刪除了通過猜測來設置的 replica.lag.max.messages 參數。現在,我們只需要在服務器上配置 replica.lag.time.max.ms 參數即可;這個參數的含義爲副本與 leader 不同步的時間。

檢測卡住副本(Stuck replica)的方式與以前相同 - 如果副本未能在 replica.lag.time.max.ms 時間內發送 fetch 請求,則會將其視爲已死的副本並從 ISR 中刪除;

檢測慢副本的機制已經改變 - 如果副本落後於 leader 的時間超過 replica.lag.time.max.ms,則認爲它太慢並且從 ISR 中刪除。

因此,即使在峯值流量下,生產者往 leader 發送大量的消息,除非副本始終和 leader 保持 replica.lag.time.max.ms 時間的落後,否則它不會隨機進出 ISR。

本文翻譯自 Hands-free Kafka Replication: A lesson in operational simplicity: https://de.confluent.io/blog/hands-free-kafka-replication-a-lesson-in-operational-simplicity/

猜你喜歡

1、即將發佈的 Flink 1.11 新特性:流批一體的 Hive 數倉

2、大數據平臺架構設計沒思路?來看這篇就知道了!

3、基於 Apache Druid 的實時分析平臺在愛奇藝的實踐

4、Spark 3.0 自適應查詢優化介紹,在運行時加速 Spark SQL 的執行性能

過往記憶大數據微信羣,請添加微信:fangzhen0219,備註【進羣】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章