Kafka 副本間如何實現(xiàn)數(shù)據(jù)同步?
Kafka介紹
Kafka是一個高吞吐的分布式消息系統(tǒng),不但像傳統(tǒng)消息隊列(RaabitMQ、RocketMQ等)那樣能夠【異步處理、流量消峰、服務(wù)解耦】
還能夠把消息持久化到磁盤上,用于批量消費。除此之外由于 Kafka被設(shè)計成分布式系統(tǒng),吞吐量和可用性大大提高
Kafka角色
Kafka客戶端
生產(chǎn)者(producer):也叫發(fā)布者,負責(zé)創(chuàng)建消息
消費者(consumer):也叫訂閱者,負責(zé)消費(讀?。┫?/p>
Kafka服務(wù)端(broker)
leader:對外提供讀寫服務(wù)
follower:不提供服務(wù),負責(zé)向 leader 同步數(shù)據(jù)
Topic(主題)和 partition(分區(qū))
topic 就是消息發(fā)布的地方,消費者通過訂閱 topic 來消費到對應(yīng)的消息
為了提高吞吐量,實現(xiàn) topic 的負載均衡,Kafka在 topic 下又引用了分區(qū)(partition)的概念,每個 topic 可以被劃分成多個分區(qū)
分區(qū)允許消息在 Topic 下水平分割和存儲,每個分區(qū)都是一個有序且不可變的消息隊列,消費者可以以并行的方式消費同一個 topic 中的消息
PS:topic 是邏輯上的概念,消息真正是存儲到 partition 中去的
例如某個 topic 下被劃分成 n 個分區(qū),那么這個 topic 的并發(fā)度就提高 n,同時可以支持 n 個 consumer 并行消費該 topic 中的消息
log(日志)
對于每一個 topic ,Kafka都會維護一個分區(qū)日志
每個分區(qū)都是一個有序的、不可變的消息隊列,且可以持續(xù)地添加消息。消息在分區(qū)中分配了唯一的序列號,被稱為偏移量(Offset)
offset 用來唯一的標識分區(qū)中每一條記錄
Kafka會保留所有分區(qū)中的消息,不會自動刪除消息。消息的保留策略由 Kafka配置參數(shù)控制,消息可以在一定時間或達到一定大小后過期,過期的消息會被刪除
消費者在 Kafka中只保留自己的 Offset,用于標識它在分區(qū)中的位置。通常情況下,當 消費者消費消息時,它的 Offset 會線性增加,表示它已經(jīng)消費了這些消息
消費者可以選擇將 Offset 重置為更舊的值,從而重新開始讀取消息
每個消費者實例唯一負責(zé)一個分區(qū),Kafka只保證分區(qū)內(nèi)的記錄是有序的,而不保證主題中不同分區(qū)的順序
Kafka集群
Kafka是分布式架構(gòu),有集群(cluster)的概念
Kafka中的一個實例被稱為 broker,它接收生產(chǎn)者的消息并存入磁盤,消費者連接 broker 消費消息
多個 broker 組成一個 Kafkacluster,集群內(nèi)某個 broker 會成為集群控制器(cluster controller),負責(zé)管理整個 Kafka集群,包括分配分區(qū)給 broker,監(jiān)控 broker 等
分區(qū)被復(fù)制成了多個副本(replica)然后均分在不同的 broker 上 ,其中一個副本 Leader,其他的是 Follower
創(chuàng)建副本的單位是 topic 的 分區(qū)
正常情況下,每個分區(qū)都有一個 leader 和零或多個 followers 。這樣即使某個 broker 發(fā)生故障,其他 broker上的副本仍然可以繼續(xù)提供服務(wù)
那如何將所有的副本均勻分布在不同 broker 上呢?
分配副本的算法如下:
將所有 broker(假設(shè)共n個 broker)和待分配的分區(qū)排序
將第i個分區(qū)分配到第(i mod n)個 broker上
將第i個分區(qū)的第j個副本分配到第((i + j) mode n)個 broker 上
Kafka如何實現(xiàn)數(shù)據(jù)同步
我們先來看下 Kafka中的 ISR(In-Sync Replicas) 機制
既然每個 leader 下面都有至少一個 follower,于是便有了 ISR,ISR 就是 Kafka動態(tài)維護的一組同步副本集合
ISR 中所有的 follower 都與 leader 保持同步狀態(tài),而且 leader 也在 ISR 列表中,只有在自己 ISR 列表中的副本才能參與 leader 競選
當生產(chǎn)者寫入數(shù)據(jù)時,leader 更新數(shù)據(jù),follower 是怎么知道 leader 更新然后去同步數(shù)據(jù)的呢?
follower 會通過定期向 leader 發(fā)送 fetch 請求來實現(xiàn)數(shù)據(jù)同步,這個是由 fetcher 線程來負責(zé)的
當一個副本被選舉成為 follower 后,會啟動副本的 fetcher 線程,隨后 Follower 會定期向 Leader 發(fā)送心跳請求,以保持連接,并發(fā)送 fetch 請求來獲取最新的數(shù)據(jù)。
如果 follower 發(fā)現(xiàn)自己的 LEO(Log End Offset,日志結(jié)束偏移量)與 Leader 的 LEO 有差距時,會觸發(fā)同步數(shù)據(jù)請求,以便將自身日志同步至 Leader 的對應(yīng)位置,確保與 Leader 的數(shù)據(jù)保持一致
如果一個 follower 在指定時間內(nèi)(配置字段為 replica.lag.time.max.ms)沒有發(fā)送 fecth 請求或者沒有追上 leader 的 LEO,就會從 ISR 中移除
最后總結(jié)一下:
Kafka中的 topic 是邏輯概念,每個 topic 可以被劃分為多個分區(qū),而分區(qū)才是存儲消息的實體
每一個分區(qū)會被復(fù)制成多個副本,然后選取其中一個副本當作 leader,剩下的則是 follower
follower 會定期去向 leader 發(fā)送 fetch 請求來保證數(shù)據(jù)的同步
leader 不會關(guān)心 follower 的數(shù)據(jù)是不是同步好了的,只要你在指定時間內(nèi)沒有找我來fetch ,我就把你從ISR中剔除出去(事實證明主動點也并非壞事)