面试|图解kafka的高可用机制
對于一個復(fù)雜的分布式系統(tǒng),如果沒有豐富的經(jīng)驗和牛逼的架構(gòu)能力,很難把系統(tǒng)做得簡單易維護(hù),我們都知道,一個軟件的生命周期中,后期維護(hù)占了70%,所以系統(tǒng)的可維護(hù)性是極其重要的, kafka 能成為大數(shù)據(jù)領(lǐng)域的事實標(biāo)準(zhǔn),很大原因是因為運維起來很方便簡單,今天我們來看下 kafka 是怎么來簡化運維操作的。
kafka 使用多副本來保證消息不丟失,多副本就涉及到kafka的復(fù)制機制,在一個超大規(guī)模的集群中,時不時地這個點磁盤壞了,那個點cpu負(fù)載高了,出現(xiàn)各種各樣的問題,多個副本之間的復(fù)制,如果想完全自動化容錯,就要做一些考量和取舍了。我們舉個例子說明下運維中面對的復(fù)雜性,我們都知道 kafka 有個 ISR集合,我先說明下這個概念:
kafka不是完全同步,也不是完全異步,是一種ISR機制:?
1. leader會維護(hù)一個與其基本保持同步的Replica列表,該列表稱為ISR(in-sync Replica),每個Partition都會有一個ISR,而且是由leader動態(tài)維護(hù)?
2. 如果一個follower比一個leader落后太多,或者超過一定時間未發(fā)起數(shù)據(jù)復(fù)制請求,則leader將其重ISR中移除?
3. 當(dāng)ISR中所有Replica都向Leader發(fā)送ACK時,leader才commit,這時候producer才能認(rèn)為一個請求中的消息都commit了。
在這種機制下,如果一個? producer 一個請求發(fā)送的消息條數(shù)太多,導(dǎo)致flower瞬間落后leader太多怎么辦?如果 follower不停的移入移出 ISR 會不會影響性能?如果對這種情況加了報警,就有可能造成告警轟炸,如果我們不加報警,如果是broker 掛掉或者 broker 因為IO性能或者GC問題夯住的情況導(dǎo)致落后leader太多,這種真正需要報警情況怎么辦呢?今天我們來看下 kafka 是怎么在設(shè)計上讓我們完全避免這種運維中頭疼的問題的。
kafka的復(fù)制機制
kafka 每個分區(qū)都是由順序追加的不可變的消息序列組成,每條消息都一個唯一的offset 來標(biāo)記位置。
kafka中的副本機制是以分區(qū)粒度進(jìn)行復(fù)制的,我們在kafka中創(chuàng)建 topic的時候,都可以設(shè)置一個復(fù)制因子,這個復(fù)制因子決定著分區(qū)副本的個數(shù),如果leader 掛掉了,kafka 會把分區(qū)主節(jié)點failover到其他副本節(jié)點,這樣就能保證這個分區(qū)的消息是可用的。leader節(jié)點負(fù)責(zé)接收producer 打過來的消息,其他副本節(jié)點(follower)從主節(jié)點上拷貝消息。
kakfa 日志復(fù)制算法提供的保證是當(dāng)一條消息在 producer 端認(rèn)為已經(jīng) committed的之后,如果leader 節(jié)點掛掉了,其他節(jié)點被選舉成為了 leader 節(jié)點后,這條消息同樣是可以被消費到的。
這樣的話,leader 選舉的時候,只能從 ISR集合中選舉,集合中的每個點都必須是和leader消息同步的,也就是沒有延遲,分區(qū)的leader 維護(hù)ISR 集合列表,如果某個點落后太多,就從 ISR集合中踢出去。?producer 發(fā)送一條消息到leader節(jié)點后, 只有當(dāng)ISR中所有Replica都向Leader發(fā)送ACK確認(rèn)這條消息時,leader才commit,這時候producer才能認(rèn)為這條消息commit了,正是因為如此,kafka客戶端的寫性能取決于ISR集合中的最慢的一個broker的接收消息的性能,如果一個點性能太差,就必須盡快的識別出來,然后從ISR集合中踢出去,以免造成性能問題。kafka 復(fù)制機制詳情參考??https://kafka.apache.org/documentation.html#replication
一個副本怎么才算是跟得上leader的副本
一個副本不能 “caught up” leader 節(jié)點,就有可能被從 ISR集合中踢出去,我們舉個例子來說明,什么才是真正的?“caught up” —— 跟leader節(jié)點消息同步。
kafka 中的一個單分區(qū)的 topic — foo,復(fù)制因子為 3 ,分區(qū)分布和 leader 和 follower 如下圖,現(xiàn)在broker 2和3 是 follower 而且都在 ISR 集合中。我們設(shè)置?replica.lag.max.messages?為4,只要 follower 只要不落后leader 大于3條消息,就然后是跟得上leader的節(jié)點,就不會被踢出去, 設(shè)置??replica.lag.time.max.ms?為 500ms, 意味著只要 follower 在每 500ms內(nèi)發(fā)送fetch請求,就不會被認(rèn)為已經(jīng)dead ,不會從ISR集合中踢出去。
現(xiàn)在 producer 發(fā)送一條消息,offset 為3, 這時候 broker 3 發(fā)生了 GC, 入下圖:
因為 broker 3 現(xiàn)在在 ISR 集合中, 所以要么 broker 3? 拉取同步上這條 offset 為3 的消息,要么 3 被從 ISR集合中踢出去,不然這條消息就不會 committed, 因為?replica.lag.max.messages=4?為4, broker 3 只落后一條消息,不會從ISR集合中踢出去, broker 3 如果這時候 GC? 100ms, GC 結(jié)束,然后拉取到 offset 為3的消息,就再次跟 leader 保持完全同步,整個過程一直在 ISR集合中,如下圖:
什么時候一個副本才會從ISR集合中踢出去
一個副本被踢出 ISR集合的幾種原因:
-
一個副本在一段時間內(nèi)都沒有跟得上 leader 節(jié)點,也就是跟leader節(jié)點的差距大于?replica.lag.max.messages,?通常情況是 IO性能跟不上,或者CPU 負(fù)載太高,導(dǎo)致 broker 在磁盤上追加消息的速度低于接收leader 消息的速度。
-
一個 broker 在很長時間內(nèi)(大于?replica.lag.time.max.ms?)都沒有向 leader 發(fā)送fetch 請求,? 可能是因為 broker 發(fā)生了 full GC, 或者因為別的原因掛掉了。
-
一個新 的 broker 節(jié)點,比如同一個 broker id, 磁盤壞掉,新?lián)Q了一臺機器,或者一個分區(qū) reassign 到一個新的broker 節(jié)點上,都會從分區(qū)leader 上現(xiàn)存的最老的消息開始同步。
所以說 kafka 0.8 版本后設(shè)置了兩個參數(shù)? ,?replica.lag.max.messages?用來識別性能一直很慢的節(jié)點,?replica.lag.time.max.ms?用來識別卡住的節(jié)點。
一個節(jié)點在什么情況下真正處于落后狀態(tài)
從上面的情況來看,兩個參數(shù)看似已經(jīng)足夠了,如果一個副本超過?replica.lag.time.max.ms還沒有發(fā)送fetch同步請求, 可以認(rèn)為這個副本節(jié)點卡住了,然后踢出去,但是還有一種比較特殊的情況沒有考慮到,我們上文中設(shè)置?replica.lag.max.messages?為4,之所以設(shè)置為 4, 是我們已經(jīng)知道 producer 每次請求打過來的消息數(shù)都在 4 以下,如果我們的參數(shù)是作用于多個 topic 的情況,那么這個 producer 最大打過來的消息數(shù)目就不好估計了,或者說在經(jīng)常出現(xiàn)流量抖動的情況下,就會出現(xiàn)一個什么情況呢,我們還是使用例子說明:
如果我們的 topic — foo? 的 producer 因為流量抖動打過來一個 包含 4條消息的請求,我們設(shè)置的?replica.lag.max.messages?還是為4, 這個時候,所有的 follower 都會因為超出落后條數(shù)被踢出 ISR集合:
然后,因為 follower 是正常的,所以下一次 fetch 請求就會又追上 leader, 這時候就會再次加入 ISR 集合,如果經(jīng)常性的抖動,就會不斷的移入移出ISR集合,會造成令人頭疼的 告警轟炸。
這里的核心問題是,在海量的 topic 情況下,或者經(jīng)常性的流量抖動情況下,我們不能對 topic 的producer 每次打過來的消息數(shù)目做任何假設(shè),所以就不太好定出來一個 合適的?eplica.lag.max.messages?值
一個配置全部搞定
其實只有兩種情況是異常的,一種就是卡住,另外一種是follower 性能慢,如果我們只根據(jù) follower 落后 leader 多少來判斷是否應(yīng)該把 follower 提出ISR集合,就必須要對流量進(jìn)行預(yù)測估計,怎么才能避免這種不靠譜的估計呢,kafka 給出的方案是這樣的,對?replica.lag.time.max.ms?這個配置的含義做了增強,和之前一樣,如果?follower 卡住超過這個時間不發(fā)送fetch請求, 會被踢出ISR集合,新的增強邏輯是,在 follower 落后 leader 超過?eplica.lag.max.messages?條消息的時候,不會立馬踢出ISR 集合,而是持續(xù)落后超過??replica.lag.time.max.ms?時間,才會被踢出,這樣就能避免流量抖動造成的運維問題,因為follower 在下一次fetch的時候就會跟上leader, 這樣就也不用對 topic 的寫入速度做任何的估計嘍。
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的面试|图解kafka的高可用机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 干货|kafka最佳实践
- 下一篇: 分享一波Kafka面试题答案