Kafka經典三大問:數據有序丟失重復


Kafka經典三大問:數據有序丟失重復

在kafka中有三個經典的問題:

  • 如何保證數據有序性
  • 如何解決數據丟失問題
  • 如何處理數據重復消費

這些不光是面試常客,更是日常使用過程中會遇到的幾個問題,下面分別記錄一下產生的原因以及如何解決。

1. 消息有序

kafka 的數據,在同一個partition下是默認有序的,但在多個partition中並不一定能夠保證其順序性。kafka因為其自身的性質,適合高吞吐的流式大數據,對數據有序性要求不嚴格的場景比較適用。

1.1. 為什么只保證單partition有序?

如果Kafka要保證多個partition有序,不僅broker保存的數據要保持順序,消費時也要按序消費。假設partition1堵了,為了有序,那partition2以及后續的分區也不能被消費,這種情況下,Kafka 就退化成了單一隊列,毫無並發性可言,極大降低系統性能。因此Kafka使用多partition的概念,並且只保證單partition有序。這樣不同partiiton之間不會干擾對方。

1.2. 解決方式

kafka自身沒有提供整個topic級別的消息順序性,但我們可以在業務層面來處理。

可以通過message key來保證你需要保持順序性的數據發送到同一個partition,即send方法,可以指定三個參數(topic, partition, key), partition和key是可選的,如果指定了同一個partition的話,那么數據就是有序的。

同時在消費端,只創建一個消費者來消費topic,但后續的話這個消費者可以寫入N個內存隊列,保證具有相同key的數據寫入同一個內存隊列即可。引入內存隊列是為了解決業務處理單線程處理太慢的問題,多個內存隊列可以起多個線程進行消費,同時具有相同key的數據在同一個內存隊列中,這樣就能保證順序性。

kafka_順序性

2. 數據丟失

丟失數據一般分為兩種情況:mq自己弄丟了,業務處理弄丟了。

2.1. kafka弄丟了數據

kafka的某個broker宕機,重新選舉partition的leader時,如果其他的follower還沒有完成數據同步,此時leader掛了,那么就有可能造成數據丟失的問題。

kafka提供了幾個參數來保證數據不丟失:

  • replication.factor:分區副本數,最低設置為2,即要求每個Partition至少擁有兩個副本;

  • min.insync.replicas:要求一個leader感知到有至少一個follower還跟自己保持聯系,沒掉隊,這樣才能確保leader掛了還有一個follower;

  • acks:在producer發送數據成功后,kafka會給生產者返回一個ack信息,這個稱為kafka的ack機制;

    ack有3個可選值,-1、0、1;

    • ack=1:producer只要收到一個分區副本寫入成功的通知就認為推送消息成功,這個分區副本特指leader副本;

    • ack=0:producer發送一次就不再發送了,不管是否發送成功;

    • ack=-1:producer只有收到分區內所有副本的成功寫入通知才算推送消息成功;

  • retries:重試次數,如果寫入失敗就會進行重試,直到超過retries設置的值;

2.2. 消費端弄丟了數據

例如消費者已經獲取到這個數據,並且提交了offset,但后續在對數據進行業務操作的時候掛掉了,導致數據沒有成功處理,這時候kafka認為你已經成功獲取了,但實際沒有,就造成了數據丟失的問題。

一般情況下用手動提交的方式來解決,當數據處理成功后再提交offset。

3. 重復消費

ack=1的情況下,是有可能存在消息丟失的情況的,因為producer收到leader寫入成功的通知就認為推送成功,但實際上leader副本在把消息同步到follower副本的時候失敗了,這時候消息就丟失了。

為了處理這種推送失敗的情況,kakfa引入了回調機制來處理,實際上就是一種重試的方式,這時候會出現因為重試機制導致消息亂序的情況。

3.1. 解決重試機制引起的消息亂序

生產者Producer

為了實現producer的冪等性,kafka引入了Producer IDSequence Number兩個參數,對於每個生產者,該Producer發送的消息都對應一個單調增的Sequence Number。同樣的Broker端也會為每個生產者的每條消息維護一個序號,並且每commit一條數據時就會將其序號遞增。

對於接收到的數據,如果其序號比Borker維護的序號大一(即表示是下一條數據),Broker會接收它,否則將其丟棄。

如果消息序號比Broker維護的序號差值比一大,說明中間有數據尚未寫入,即亂序,此時Broker拒絕該消息,Producer拋出InvalidSequenceNumber

如果消息序號小於等於Broker維護的序號,說明該消息已被保存,即為重復消息,Broker直接丟棄該消息,Producer拋出DuplicateSequenceNumber

Sender發送失敗后會重試,這樣可以保證每個消息都被發送到broker

消費者Consumer

同樣的也是利用冪等性的原理來解決,可以給每條數據加上一個唯一標識,進行數據處理的時候校驗這個標識是否存在,如果存在即為重復數據,丟棄。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM