Kafka 叢集如何實現資料同步?

鹹魚Linux運維發表於2023-11-16

哈嘍大家好,我是鹹魚

最近這段時間比較忙,將近一週沒更新文章,再不更新我那為數不多的粉絲量就要庫庫往下掉了 T﹏T

剛好最近在學 Kafka,於是決定寫篇跟 Kafka 相關的文章(文中有不對的地方歡迎大家指出)

考慮到有些小夥伴可能是第一次接觸 Kafka ,所以先簡單介紹一下什麼是 Kafka 吧!

Kafka 介紹

Kafka 是一個高吞吐的分散式訊息系統,不但像傳統訊息佇列(RaabitMQ、RocketMQ等)那樣能夠【非同步處理、流量消峰、服務解耦】

還能夠把訊息持久化到磁碟上,用於批次消費。除此之外由於 Kafka 被設計成分散式系統,吞吐量和可用性大大提高

Kafka 角色

  • kafka 客戶端
    • 生產者(producer):也叫釋出者,負責建立訊息
    • 消費者(consumer):也叫訂閱者,負責消費(讀取)訊息
  • Kafka 服務端(broker)
    • leader:對外提供讀寫服務
    • follower:不提供服務,負責向 leader 同步資料

Topic(主題)和 partition(分割槽)

topic 就是訊息釋出的地方,消費者透過訂閱 topic 來消費到對應的訊息

為了提高吞吐量,實現 topic 的負載均衡,Kafka 在 topic 下又引用了分割槽(partition)的概念,每個 topic 可以被劃分成多個分割槽

分割槽允許訊息在 Topic 下水平分割和儲存,每個分割槽都是一個有序且不可變的訊息佇列,消費者可以以並行的方式消費同一個 topic 中的訊息

PS:topic 是邏輯上的概念,訊息真正是儲存到 partition 中去的

例如某個 topic 下被劃分成 n 個分割槽,那麼這個 topic 的併發度就提高 n,同時可以支援 n 個 consumer 並行消費該 topic 中的訊息

log(日誌)

對於每一個 topic ,Kafka 都會維護一個分割槽日誌

每個分割槽都是一個有序的、不可變的訊息佇列,且可以持續地新增訊息。訊息在分割槽中分配了唯一的序列號,被稱為偏移量(Offset)

offset 用來唯一的標識分割槽中每一條記錄

Kafka 會保留所有分割槽中的訊息,不會自動刪除訊息。訊息的保留策略由 Kafka 配置引數控制,訊息可以在一定時間或達到一定大小後過期,過期的訊息會被刪除

消費者在 Kafka 中只保留自己的 Offset,用於標識它在分割槽中的位置。通常情況下,當 消費者消費訊息時,它的 Offset 會線性增加,表示它已經消費了這些訊息

消費者可以選擇將 Offset 重置為更舊的值,從而重新開始讀取訊息

每個消費者例項唯一負責一個分割槽,Kafka 只保證分割槽內的記錄是有序的,而不保證主題中不同分割槽的順序

Kafka 叢集

Kafka 是分散式架構,有叢集(cluster)的概念

Kafka 中的一個例項被稱為 broker,它接收生產者的訊息並存入磁碟,消費者連線 broker 消費訊息

多個 broker 組成一個 Kafka cluster,叢集內某個 broker 會成為叢集控制器(cluster controller),負責管理整個 Kafka 叢集,包括分配分割槽給 broker,監控 broker 等

分割槽被複製成了多個副本(replica)然後均分在不同的 broker 上 ,其中一個副本 Leader,其他的是 Follower

建立副本的單位是 topic 的 分割槽

正常情況下,每個分割槽都有一個 leader 和零或多個 followers 。這樣即使某個 broker 發生故障,其他 broker上的副本仍然可以繼續提供服務

那如何將所有的副本均勻分佈在不同 broker 上呢?

分配副本的演算法如下:

  • 將所有 broker(假設共 n 個 broker)和待分配的分割槽排序
  • 將第 i 個分割槽分配到第(i mod n)個 broker上
  • 將第 i 個分割槽的第 j 個副本分配到第((i + j) mode n)個 broker 上

如何實現資料同步?

我們先來看下 Kafka 中的 ISR(In-Sync Replicas) 機制

既然每個 leader 下面都有至少一個 follower,於是便有了 ISR,ISR 就是 Kafka 動態維護的一組同步副本集合

ISR 中所有的 follower 都與 leader 保持同步狀態,而且 leader 也在 ISR 列表中,只有在自己 ISR 列表中的副本才能參與 leader 競選

當生產者寫入資料時,leader 更新資料,follower 是怎麼知道 leader 更新然後去同步資料的呢?

follower 會透過定期向 leader 傳送 fetch 請求來實現資料同步,這個是由 fetcher 執行緒來負責的

當一個副本被選舉成為 follower 後,會啟動副本的 fetcher 執行緒,隨後 Follower 會定期向 Leader 傳送心跳請求,以保持連線,併傳送 fetch 請求來獲取最新的資料

如果 follower 發現自己的 LEO(Log End Offset,日誌結束偏移量)與 Leader 的 LEO 有差距時,會觸發同步資料請求,以便將自身日誌同步至 Leader 的對應位置,確保與 Leader 的資料保持一致

如果一個 follower 在指定時間內(配置欄位為 replica.lag.time.max.ms)沒有傳送 fecth 請求或者沒有追上 leader 的 LEO,就會從 ISR 中移除

最後總結一下:

  • Kafka 中的 topic 是邏輯概念,每個 topic 可以被劃分為多個分割槽,而分割槽才是儲存訊息的實體
  • 每一個分割槽會被複製成多個副本,然後選取其中一個副本當作 leader,剩下的則是 follower
  • follower 會定期去向 leader 傳送 fetch 請求來保證資料的同步
  • leader 不會關心 follower 的資料是不是同步好了的,只要你在指定時間內沒有找我來 fetch ,我就把你從 ISR 中剔除出來

相關文章