Kafka高可用架構(gòu)設(shè)計(jì)

1.高可用概述

高可?性(High Availability),指系統(tǒng)無間斷地執(zhí)?其功能的能力,代表系統(tǒng)的可?性程度。Kafka從0.8版本開始提供了高可?機(jī)制, 可保障?個或多個Broker宕機(jī)后,其他Broker及所有Partition都能繼續(xù)提供服務(wù),且存儲的消息不丟失。
對分布式系來說,當(dāng)集群規(guī)模上升到一定程度后,一臺或者多臺機(jī)?宕機(jī)的可能性?大增加;Kafka采?多機(jī)備份和消息應(yīng)答確認(rèn)方式解決了數(shù)據(jù)丟失問題,并通過一套失敗恢復(fù)機(jī)制解決服務(wù)不可?問題。

2.消息備份機(jī)制

2.1 消息備份

Kafka允許同?個Partition存在多個消息副本(Replica),每個Partition的副本通常由1個Leader及0個以上的Follower組成,?產(chǎn)者將 消息直接發(fā)往對應(yīng)Partition的Leader,F(xiàn)ollower會周期地向Leader發(fā)送同步請求,Kafka的Leader機(jī)制在保障數(shù)據(jù)?致性地同時降低了了 消息備份的復(fù)雜度。
同?Partition的Replica不應(yīng)存儲在同一個Broker上,因?yàn)橐坏┰揃roker宕機(jī),對應(yīng)Partition的所有Replica都無法?作,這就達(dá)不到 高可用的效果。為了做好負(fù)載均衡并提?容錯能力,Kafka會盡量將所有的Partition以及各Partition的副本均勻地分配到整個集群上。 舉個例?,當(dāng)集群中部署了3臺Broker,TopicA共有4個Partition,每個Partition均有3個Replica時下圖就是?種合理理的分布方式。


file

2.2 ISR

ISR(In-Sync Replicas)指的是?個Partition中與Leader“保持同步”的Replica列表(實(shí)際存儲的是副本所在Broker的BrokerId),這里的 保持同步不是指與Leader數(shù)據(jù)保持完全?一致,只需在replica.lag.time.max.ms時間內(nèi)與Leader保持有效連接,官?方解釋如下
If a follower hasn't sent any fetch requests or hasn't consumed up to the leaders log end offset for at least this time, the leader will remove the follower from isr,( default value =10000 )
Follower周期性地向Leader發(fā)送FetchRequest請求(數(shù)據(jù)結(jié)構(gòu)?見下),發(fā)送時間間隔配置在replica.fetch.wait.max.ms中,默認(rèn)值為 500。

public class FetchRequest {
    private final short versionId;
    private final int correlationId;
    private final String clientId;
    private final int replicaId;
    private final int maxWait; // Follower容忍的最?大等待時間: 到點(diǎn)Leader?立即返回結(jié)果,默認(rèn)值500
    private final int minBytes; // Follower容忍的最?小返回?cái)?shù)據(jù)?大?小:當(dāng)Leader有?足夠數(shù)據(jù)時?立即返回,兜底等待ma private final Map<TopicAndPartition, PartitionFetchInfo> requestInfo; // Follower中各Partititon
}

各Partition的Leader負(fù)責(zé)維護(hù)ISR列表并將ISR的變更同步至ZooKeeper,被移出ISR的Follower會繼續(xù)向Leader發(fā)FetchRequest請 求,試圖再次跟上Leader重新進(jìn)?入ISR。
ISR中所有副本都跟上了Leader,通常只有ISR里的成員才可能被選為Leader。當(dāng)Kafka中unclean.leader.election.enable配置為 true(默認(rèn)值為false)且ISR中所有副本均宕機(jī)的情況下,才允許ISR外的副本被選為Leader,此時會丟失部分已應(yīng)答的數(shù)據(jù)。

2.3 Acks

為了了講清楚ISR的作?用,下?面介紹?下?產(chǎn)者可以選擇的消息應(yīng)答?式,?產(chǎn)者發(fā)送消息中包含acks字段,該字段代表Leader應(yīng)答?產(chǎn)者前Leader收到的應(yīng)答數(shù)

  • acks = 0

?產(chǎn)者?需等待服務(wù)端的任何確認(rèn),消息被添加到生產(chǎn)者套接字緩沖區(qū)后就視為已發(fā)送,因此acks=0不不能保證服務(wù)端已收到消息, 使?用場景較少,本?文不不做任何討論

  • acks = 1

Leader將消息寫?入本地?日志后?無需等待Follower的消息確認(rèn)就做出應(yīng)答。如果Leader在應(yīng)答消息后?立即宕機(jī)且其他Follower均未完 成消息的復(fù)制,則該條消息將丟失

file

上圖左側(cè)的穩(wěn)態(tài)場景下,Partition1的數(shù)據(jù)冗余備份在Broker0和Broker2上;Broker0中的副本與Leader副本因?網(wǎng)絡(luò)開銷等因素存在1 秒鐘同步時間差,Broker0中的副本落后124條消息;Broker2中的副本存在8秒鐘同步時間差,Broker2中的副本落后7224條消息。若 圖中的Broker1突然宕機(jī)且Broker0被選為Partition1的Leader,則在Leader宕機(jī)前寫入的124條消息未同步?至Broker0中的副本,這次宕 機(jī)會造成少量量消息丟失。

  • acks = all

Leader將等待ISR中的所有副本確認(rèn)后再做出應(yīng)答,因此只要ISR中任何?一個副本還存活著,這條應(yīng)答過的消息就不會丟失。 acks=all是可?用性最?的選擇,但等待Follower應(yīng)答引入了額外的響應(yīng)時間。Leader需要等待ISR中所有副本做出應(yīng)答,此時響應(yīng)時間 取決于ISR中最慢的那臺機(jī)器,下圖中因復(fù)制產(chǎn)生的額外延遲為3秒。


file

Broker的配置項(xiàng)min.insync.replicas(默認(rèn)值為1)代表了正常寫??產(chǎn)者數(shù)據(jù)所需要的最少ISR個數(shù),當(dāng)ISR中的副本數(shù)量?于 min.insync.replicas時,Leader停?止寫??產(chǎn)者?產(chǎn)的消息,并向?產(chǎn)者拋出NotEnoughReplicas異常,阻塞等待更更多的Follower趕上 并重新進(jìn)?ISR。被Leader應(yīng)答的消息都至少有min.insync.replicas個副本,因此能夠容忍min.insync.replicas-1個副本同時宕機(jī)。 小結(jié):發(fā)送的acks=1消息會出現(xiàn)丟失情況,為不丟失消息可配置?產(chǎn)者acks=all & min.insync.replicas >= 2

2.4 LEO & HW

每個Kafka副本對象都有下面兩個重要屬性:

  • LEO(log end offset) ,即?志末端偏移,指向了副本日志中下?條消息的位移值(即下一條消息的寫?位置)
  • HW(high watermark),即已同步消息標(biāo)識,因其類似于?桶效應(yīng)中短板決定?位高度,故取名高?位線
    所有??位線以下消息都是已備份過的,消費(fèi)者僅可消費(fèi)各分區(qū)Leader?水位線以下的消息,對于任何?個副本對象而?其HW值不會大于LEO值
    Leader的HW值由ISR中的所有備份的LEO最小值決定(Follower在發(fā)送FetchRequest時會在PartitionFetchInfo中會攜帶Follower的LEO)
file

Kafka原本使?用HW來記錄副本的備份進(jìn)度,HW值的更新通常需要額外一輪FetchRequest才能完成,存在一些邊緣案例導(dǎo)致備份數(shù)據(jù)丟失或?qū)е露鄠€備份間的數(shù)據(jù)不一致。本?主要介紹可用性,數(shù)據(jù)?一致性及截?cái)嘁?guī)則不詳述。Kafka新引入了Leader epoch解決HW 截?cái)喈a(chǎn)?的問題,有興趣的同學(xué)可參考 Apache : Fix log divergence after fast leader fail over

3.故障恢復(fù)

3.1 Broker故障恢復(fù)

Kafka從0.8版本開始引?了一套Leader選舉及失敗恢復(fù)機(jī)制:?先需要在集群所有Broker中選出?個Controller,負(fù)責(zé)各Partition的 Leader選舉以及Replica的重新分配。當(dāng)出現(xiàn)Leader故障后,Controller會將Leader/Follower的變動通知到需為此作出響應(yīng)的Broker。
Kafka使?ZooKeeper存儲Broker、Topic等狀態(tài)數(shù)據(jù),Kafka集群中的Controller和Broker會在ZooKeeper指定節(jié)點(diǎn)上注冊 Watcher(事件監(jiān)聽器?),以便在特定事件觸發(fā)時,由ZooKeeper將事件通知到對應(yīng)Broker。

3.1.1 Broker故障場景分析

  • 場景1 Broker與其他Broker斷開連接
file

上圖中Broker0和其余Broker都斷開了連接,由于ZooKeeper還能接收到Broker0的?跳,因此ZooKeeper認(rèn)為Broker0依然存活,則對于

Partition0

Broker0中的副本為Partition0的Leader,當(dāng)Broker0超過replica.lag.time.max.ms沒接收到Broker1、Broker2的FetchRequest請求后, Broker0選擇將Partition0的ISR收縮到僅剩Broker0本身,并將ISR的變更同步到ZooKeeper;Broker0需要根據(jù)min.insync.replicas的配置決定是否繼續(xù)接受生產(chǎn)者數(shù)據(jù)
Partition1
超過replica.lag.time.max.ms后,Broker1會將Broker0中的副本從Partition1的ISR中移除。若后續(xù)Broker0恢復(fù)連接并趕上了Broker1, 則Broker1還會再將Broker0重新加?入Partition1的ISR

  • 場景2 Broker與ZooKeeper斷開連接
file

Broker0與ZooKeeper斷開連接后,ZooKeeper會?自動刪除該Broker對應(yīng)節(jié)點(diǎn),并且認(rèn)為Broker0已經(jīng)宕機(jī),則對于

Partition0

ZooKeeper刪除節(jié)點(diǎn)后,該節(jié)點(diǎn)上注冊的Watcher會通知Controller,Controller會發(fā)現(xiàn)Broker0為Partition0的Leader,于是從當(dāng)前 存活的ISR中選擇了了Broker2作為Partition0的新Leader。Controller通過LeaderAndIsrRequest將Leader變更更通知到Broker1、Broker2, 于是Broker1改向Broker2發(fā)送Partition0數(shù)據(jù)的FetchRequest請求。
?生產(chǎn)者每隔60秒會從bootstrap.servers中的Broker獲取最新的metadata,當(dāng)發(fā)現(xiàn)Partition0的Leader發(fā)?生變更更后,會改向新 Leader-Broker2發(fā)送Partition0數(shù)據(jù)。另?一邊,Broker0收不到ZooKeeper通知,依然認(rèn)為?自?己是Partition0的Leader;由于Broker1、 Broker2不不再向Broker0發(fā)送FetchRequest請求,缺失了了ISR應(yīng)答的Broker0停?止寫?入acks=all的消息,但可以繼續(xù)寫?入acks=1的消息。 在replica.lag.time.max.ms時間后,Broker0嘗試向ZooKeeper發(fā)送ISR變更請求但失敗了了,于是不再接收?產(chǎn)者的消息。
當(dāng)Broker0與ZooKeeper恢復(fù)連接后,發(fā)現(xiàn)?己不再是Partition0的Leader,于是將本地日志截?cái)?為了保證和Leader數(shù)據(jù)一致性), 并開始向Broker2發(fā)送FetchRequest請求。在Broker0與ZooKeeper失聯(lián)期間寫入Broker0的所有消息由于未在新Leader中備份,這些消息都丟失了了。

Partition1

Broker0中的副本只是作為Partition1的Follower節(jié)點(diǎn),?Broker0與Broker1依然保持連接,因此Broker0依然會向Broker1發(fā)送 FetchRequest。只要Broker0能繼續(xù)保持同步,Broker1也不會向ZooKeeper變更更ISR。

3.1.2 Broker故障恢復(fù)過程

Broker發(fā)?生故障后,由Controller負(fù)責(zé)選舉受影響Partition的新Leader并通知到相關(guān)Broker,具體過程可參考下圖。


file

當(dāng)Broker出現(xiàn)故障與ZooKeeper斷開連接后,該Broker在ZooKeeper對應(yīng)的znode會?動被刪除,ZooKeeper會觸發(fā)Controller注冊 在該節(jié)點(diǎn)的Watcher;Controller從ZooKeeper的/brokers/ids節(jié)點(diǎn)上獲取宕機(jī)Broker上的所有Partition(簡稱set_p);Controller再從 ZooKeeper的/brokers/topics獲取set_p中所有Partition當(dāng)前的ISR;對于宕機(jī)Broker是Leader的Partition,Controller從ISR中選擇幸存 的Broker作為新Leader;最后Controller通過LeaderAndIsrRequest請求向set_p中的Broker發(fā)送LeaderAndISRRequest請求。
受到影響的Broker會收到Controller發(fā)送的LeaderAndIsrRequest請求后,Broker通過ReplicaManager的becomeLeaderOrFollower ?法響應(yīng)LeaderAndIsrRequest:新Leader會將HW更新為它的LEO值,而Follower則通過?系列策略截?cái)鄉(xiāng)og以保證數(shù)據(jù)一致性。

3.2 Controller故障恢復(fù)

3.2.1 Controller 故障場景分析

  • 場景1 Controller與ZooKeeper斷開連接
file

此時ZooKeeper會將Controller臨時節(jié)點(diǎn)刪除,并按照下節(jié)的故障恢復(fù)過程重新競選出新Controller。?而原本的Controller由于?無法連 上ZooKeeper,它什什么也執(zhí)?行行不不了了;當(dāng)它與ZooKeeper恢復(fù)連接后發(fā)現(xiàn)?自?己不不再是Controller,會在Kafka集群中充當(dāng)?一個普通的 Broker。

  • 場景2 Controller與某個Broker斷開連接

因?yàn)镃ontroller?無法通知到Broker0,所以Broker0不曉得Partition0的Leader已經(jīng)更換了,所以也會出現(xiàn)3.1.1節(jié)場景2描述的出現(xiàn)短暫 服務(wù)不可?并可能發(fā)生數(shù)據(jù)丟失。

3.2.2 Controller 故障恢復(fù)過程

最后,集群中的Controller也會出現(xiàn)故障,因此Kafka讓所有Broker都在ZooKeeper的Controller節(jié)點(diǎn)上注冊一個Watcher。Controller
發(fā)?故障時對應(yīng)的Controller臨時節(jié)點(diǎn)會自動刪除,此時注冊在其上的Watcher會被觸發(fā),所有活著的Broker都會去競選成為新的 Controller(即創(chuàng)建新的Controller節(jié)點(diǎn),由ZooKeeper保證只會有一個創(chuàng)建成功)。競選成功者即為新的Controller,會在ZooKeeper的 下述節(jié)點(diǎn)上注冊Watcher,以監(jiān)控各Broker運(yùn)?行行狀態(tài)、負(fù)責(zé)Leader宕機(jī)的失敗恢復(fù),并對管理腳本做出響應(yīng)。

  • 在/admin節(jié)點(diǎn)上注冊Watcher,以應(yīng)對管理員腳本對Topic及Partition的影響;
  • 在/brokers/ids節(jié)點(diǎn)上注冊Watcher,以獲取各Brokers的狀態(tài)變化;
  • 在/brokers/topics節(jié)點(diǎn)上注冊Watcher,以監(jiān)控每個Partition的ISR副本狀態(tài);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容