您好,登錄后才能下訂單哦!
Kafka常見面試問題有哪些,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
現如今,Kafka已不再是一個單純的消息隊列系統。Kafka是一個分布式的流處理平臺,被越來越多的公司使用,Kafka可以被用于高性能的數據管道,流處理分析,數據集成等場景。下面總結了幾個Kafka常見的面試問題。
該問題已經成為了Kafka面試的慣例,如同Java的HashMap,屬于高頻出現的面試問題。那么,我們該怎么理解這個問題呢?問題是Kafka如何保障數據不丟失,即Kafka的Broker提供了什么機制保證數據不丟失的。
其實對于Kafka的Broker而言,Kafka 的復制機制和分區的多副本架構是Kafka 可靠性保證的核心。把消息寫入多個副本可以使Kafka 在發生崩潰時仍能保證消息的持久性。
搞清楚了問題的核心,再來看一下該怎么回答這個問題:主要包括三個方面
1.Topic 副本因子個數:replication.factor >= 3
2.同步副本列表(ISR):min.insync.replicas = 2
3.禁用unclean選舉:unclean.leader.election.enable=false
下面將會逐步分析上面的三個配置:
Kafka的topic是可以分區的,并且可以為分區配置多個副本,該配置可以通過replication.factor
參數實現。Kafka中的分區副本包括兩種類型:領導者副本(Leader Replica)和追隨者副本(Follower Replica),每個分區在創建時都要選舉一個副本作為領導者副本,其余的副本自動變為追隨者副本。在 Kafka 中,追隨者副本是不對外提供服務的,也就是說,任何一個追隨者副本都不能響應消費者和生產者的讀寫請求。所有的請求都必須由領導者副本來處理。換句話說,所有的讀寫請求都必須發往領導者副本所在的 Broker,由該 Broker 負責處理。追隨者副本不處理客戶端請求,它唯一的任務就是從領導者副本異步拉取消息,并寫入到自己的提交日志中,從而實現與領導者副本的同步。
一般來說,副本設為3可以滿足大部分的使用場景,也有可能是5個副本(比如銀行)。如果副本因子為N,那么在N-1個broker 失效的情況下,仍然能夠從主題讀取數據或向主題寫入數據。所以,更高的副本因子會帶來更高的可用性、可靠性和更少的故障。另一方面,副本因子N需要至少N個broker ,而且會有N個數據副本,也就是說它們會占用N倍的磁盤空間。實際生產環境中一般會在可用性和存儲硬件之間作出權衡。
除此之外,副本的分布同樣也會影響可用性。默認情況下,Kafka會確保分區的每個副本分布在不同的Broker上,但是如果這些Broker在同一個機架上,一旦機架的交換機發生故障,分區就會不可用。所以建議把Broker分布在不同的機架上,可以使用broker.rack參數配置Broker所在機架的名稱。
In-sync replica(ISR)稱之為同步副本,ISR中的副本都是與Leader進行同步的副本,所以不在該列表的follower會被認為與Leader是不同步的。那么,ISR中存在是什么副本呢?首先可以明確的是:Leader副本總是存在于ISR中。而follower副本是否在ISR中,取決于該follower副本是否與Leader副本保持了“同步”。
Kafka的broker端有一個參數replica.lag.time.max.ms, 該參數表示follower副本滯后與Leader副本的最長時間間隔,默認是10秒。這就意味著,只要follower副本落后于leader副本的時間間隔不超過10秒,就可以認為該follower副本與leader副本是同步的,所以哪怕當前follower副本落后于Leader副本幾條消息,只要在10秒之內趕上Leader副本,就不會被踢出出局。
可以看出ISR是一個動態的,所以即便是為分區配置了3個副本,還是會出現同步副本列表中只有一個副本的情況(其他副本由于不能夠與leader及時保持同步,被移出ISR列表)。如果這個同步副本變為不可用,我們必須在可用性和一致性之間作出選擇(CAP理論)。
根據Kafka 對可靠性保證的定義,消息只有在被寫入到所有同步副本之后才被認為是已提交的。但如果這里的“所有副本”只包含一個同步副本,那么在這個副本變為不可用時,數據就會丟失。如果要確保已提交的數據被寫入不止一個副本,就需要把最小同步副本數量設置為大一點的值。對于一個包含3 個副本的主題分區,如果min.insync.replicas=2 ,那么至少要存在兩個同步副本才能向分區寫入數據。
如果進行了上面的配置,此時必須要保證ISR中至少存在兩個副本,如果ISR中的副本個數小于2,那么Broker就會停止接受生產者的請求。嘗試發送數據的生產者會收到NotEnoughReplicasException異常,消費者仍然可以繼續讀取已有的數據。
選擇一個同步副本列表中的分區作為leader 分區的過程稱為clean leader election。注意,這里要與在非同步副本中選一個分區作為leader分區的過程區分開,在非同步副本中選一個分區作為leader的過程稱之為unclean leader election。由于ISR是動態調整的,所以會存在ISR列表為空的情況,通常來說,非同步副本落后 Leader 太多,因此,如果選擇這些副本作為新 Leader,就可能出現數據的丟失。畢竟,這些副本中保存的消息遠遠落后于老 Leader 中的消息。在 Kafka 中,選舉這種副本的過程可以通過Broker 端參數 unclean.leader.election.enable控制是否允許 Unclean 領導者選舉。開啟 Unclean 領導者選舉可能會造成數據丟失,但好處是,它使得分區 Leader 副本一直存在,不至于停止對外提供服務,因此提升了高可用性。反之,禁止 Unclean Leader 選舉的好處在于維護了數據的一致性,避免了消息丟失,但犧牲了高可用性。分布式系統的CAP理論說的就是這種情況。
不幸的是,unclean leader election的選舉過程仍可能會造成數據的不一致,因為同步副本并不是完全同步的。由于復制是異步完成的,因此無法保證follower可以獲取最新消息。比如Leader分區的最后一條消息的offset是100,此時副本的offset可能不是100,這受到兩個參數的影響:
replica.lag.time.max.ms:同步副本滯后與leader副本的時間
zookeeper.session.timeout.ms:與zookeeper會話超時時間
簡而言之,如果我們允許不同步的副本成為leader,那么就要承擔丟失數據和出現數據不一致的風險。如果不允許它們成為leader,那么就要接受較低的可用性,因為我們必須等待原先的首領恢復到可用狀態。
關于unclean選舉,不同的場景有不同的配置方式。對數據質量和數據一致性要求較高的系統會禁用這種unclean的leader選舉(比如銀行)。如果在可用性要求較高的系統里,比如實時點擊流分析系統, 一般不會禁用unclean的leader選舉。
你可能會問:這個問題跟Q1有什么區別呢?其實一般在面試問題中可以理解成一個問題。之所以在這里做出區分,是因為兩者的解決方式不一樣。Q1問題是從Kafka的Broker側來看待數據丟失的問題,而Q2是從Kafka的生產者與消費者的角度來看待數據丟失的問題。
先來看一下如何回答這個問題:主要包括兩個方面:
Producer
retries=Long.MAX_VALUE
設置 retries 為一個較大的值。這里的 retries 同樣是 Producer 的參數,對應前面提到的 Producer 自動重試。當出現網絡的瞬時抖動時,消息發送可能會失敗,此時配置了 retries > 0 的 Producer 能夠自動重試消息發送,避免消息丟失。
acks=all
設置 acks = all。acks 是 Producer 的一個參數,代表了你對“已提交”消息的定義。如果設置成 all,則表明所有副本 Broker 都要接收到消息,該消息才算是“已提交”。這是最高等級的“已提交”定義。
max.in.flight.requests.per.connections=1
該參數指定了生產者在收到服務器晌應之前可以發送多少個消息。它的值越高,就會占用越多的內存,不過也會提升吞吐量。把它設為1 可以保證消息是按照發送的順序寫入服務器的,即使發生了重試。
Producer要使用帶有回調通知的API,也就是說不要使用 producer.send(msg),而要使用 producer.send(msg, callback)。
其他錯誤處理
使用生產者內置的重試機制,可以在不造成消息丟失的情況下輕松地處理大部分錯誤,不過 仍然需要處理其他類型的錯誤,例如消息大小錯誤、序列化錯誤等等。
Consumer
禁用自動提交:enable.auto.commit=false
消費者處理完消息之后再提交offset
配置auto.offset.reset
這個參數指定了在沒有偏移量可提交時(比如消費者第l次啟動時)或者請求的偏移量在broker上不存在時(比如數據被刪了),消費者會做些什么。
這個參數有兩種配置。一種是earliest:消費者會從分區的開始位置讀取數據,不管偏移量是否有效,這樣會導致消費者讀取大量的重復數據,但可以保證最少的數據丟失。一種是latest(默認),如果選擇了這種配置, 消費者會從分區的末尾開始讀取數據,這樣可以減少重復處理消息,但很有可能會錯過一些消息。
上面分析了一些保障數據不丟失的措施,在一定程度上可以避免數據的丟失。但是請注意:Kafka 只對“已提交”的消息(committed message)做有限度的持久化保證。所以說,Kafka不能夠完全保證數據不丟失,需要做出一些權衡。
首先,要理解什么是已提交的消息,當 Kafka 的若干個 Broker 成功地接收到一條消息并寫入到日志文件后,它們會告訴生產者程序這條消息已成功提交。此時,這條消息在 Kafka 看來就正式變為已提交消息了。所以說無論是ack=all,還是ack=1,不論哪種情況,Kafka 只對已提交的消息做持久化保證這件事情是不變的。
其次,要理解有限度的持久化保證,也就是說 Kafka 不可能保證在任何情況下都做到不丟失消息。必須保證Kafka的Broker是可用的,換句話說,假如消息保存在 N 個 Kafka Broker 上,那么這個前提條件就是這 N 個 Broker 中至少有 1 個存活。只要這個條件成立,Kafka 就能保證你的這條消息永遠不會丟失。
總結一下,Kafka 是能做到不丟失消息的,只不過這些消息必須是已提交的消息,而且還要滿足一定的條件。
首先需要明確的是:Kafka的主題是分區有序的,如果一個主題有多個分區,那么Kafka會按照key將其發送到對應的分區中,所以,對于給定的key,與其對應的record在分區內是有序的。
Kafka可以保證同一個分區里的消息是有序的,即生產者按照一定的順序發送消息,Broker就會按照這個順序將他們寫入對應的分區中,同理,消費者也會按照這個順序來消費他們。
在一些場景下,消息的順序是非常重要的。比如,先存錢再取錢與先取錢再存錢是截然不同的兩種結果。
上面的問題中提到一個參數max.in.flight.requests.per.connections=1,該參數的作用是在重試次數大于等于1時,保證數據寫入的順序。如果該參數不為1,那么當第一個批次寫入失敗時,第二個批次寫入成功,Broker會重試寫入第一個批次,如果此時第一個批次重試寫入成功,那么這兩個批次消息的順序就反過來了。
一般來說,如果對消息的順序有要求,那么在為了保障數據不丟失,需要先設置發送重試次數retries>0,同時需要把max.in.flight.requests.per.connections參數設為1,這樣在生產者嘗試發送第一批消息時,就不會有其他的消息發送給broker,雖然會影響吞吐量,但是可以保證消息的順序。
除此之外,還可以使用單分區的Topic,但是會嚴重影響吞吐量。
選擇合適的分區數量可以達到高度并行讀寫和負載均衡的目的,在分區上達到均衡負載是實現吞吐量的關鍵。需要根據每個分區的生產者和消費者的期望吞吐量進行估計。
舉個栗子:假設期望讀取數據的速率(吞吐量)為1GB/Sec,而一個消費者的讀取速率為50MB/Sec,此時至少需要20個分區以及20個消費者(一個消費者組)。同理,如果期望生產數據的速率為1GB/Sec,而每個生產者的生產速率為100MB/Sec,此時就需要有10個分區。在這種情況下,如果設置20個分區,既可以保障1GB/Sec的生產速率,也可以保障消費者的吞吐量。通常需要將分區的數量調整為消費者或者生產者的數量,只有這樣才可以同時實現生產者和消費者的吞吐量。
一個簡單的計算公式為:分區數 = max(生產者數量,消費者數量)
需要注意的是:當我們增加主題的分區數量時,會違背同一個key進行同一個分區的事實。我們可以創建一個新的主題,使得該主題有更多的分區數,然后暫停生產者,將舊的主題中的數據復制到新的主題中,然后將消費者和生產者切換到新的主題,操作起來會非常棘手。
在下面情況發生時,需要重平衡集群:
使用kafka-reassign-partitions.sh命令進行重平衡
我們可以使用kafka-consumer-groups.sh命令進行查看,比如:
$ bin/kafka-consumer-groups.sh --bootstrap-server cdh02:9092 --describe --group my-group
## 會顯示下面的一些指標信息
TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
主題 分區 當前offset LEO 滯后消息數 消費者id 主機 客戶端id
一般情況下,如果運行良好,CURRENT-OFFSET的值會與LOG-END-OFFSET的值非常接近。通過這個命令可以查看哪個分區的消費出現了滯后。
看完上述內容,你們掌握Kafka常見面試問題有哪些的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。