面試官:今天我想問下,你覺得Kafka會丟資料嗎?
候選者:嗯,使用Kafka時,有可能會有以下場景會丟訊息
候選者:比如說,我們用Producer發訊息至Broker的時候,就有可能會丟訊息
候選者:如果你不想丟訊息,那在發送訊息的時候,需要選擇帶有 callBack的api進行發送
候選者:其實就意味著,如果你發送成功了,會回呼告訴你已經發送成功了,如果失敗了,那收到回呼之后自己在業務上做重試就好了,
候選者:等到把訊息發送到Broker以后,也有可能丟訊息
候選者:一般我們的線上環境都是集群環境下嘛,但可能你發送的訊息后broker就掛了,這時掛掉的broker還沒來得及把資料同步給別的broker,資料就自然就丟了
候選者:發送到Broker之后,也不能保證資料就一定不丟了,畢竟Broker會把資料存盤到磁盤之前,走的是作業系統快取
候選者:也就是異步刷盤這個程序還有可能導致資料會丟

候選者:嗯,到這里其實我已經說了三個場景了,分別是:producer -> broker ,broker->broker之間同步,以及broker->磁盤
候選者:要解決上面所講的問題也比較簡單,這塊也沒什么好說的…
候選者:不想丟資料,那就使用帶有callback的api,設定 acks、retries、factor等等些引數來保證Producer發送的訊息不會丟就好啦,
面試官:嗯…
候選者:一般來說,還是client 消費 broker 丟訊息的場景比較多
面試官:那你們在消費資料的時候是怎么保證資料的可靠性的呢?
候選者:首先,要想client端消費資料不能丟,肯定是不能使用autoCommit的,所以必須是手動提交的,

候選者:我們這邊是這樣實作的:
候選者:一、從Kafka拉取訊息(一次批量拉取500條,這里主要看配置)時
候選者:二、為每條拉取的訊息分配一個msgId(遞增)
候選者:三、將msgId存入記憶體佇列(sortSet)中
候選者:四、使用Map存盤msgId與msg(有offset相關的資訊)的映射關系
候選者:五、當業務處理完訊息后,ack時,獲取當前處理的訊息msgId,然后從sortSet洗掉該msgId(此時代表已經處理過了)
候選者:六、接著與sortSet佇列的首部第一個Id比較(其實就是最小的msgId),如果當前msgId<=sort Set第一個ID,則提交當前offset
候選者:七、系統即便掛了,在下次重啟時就會從sortSet隊首的訊息開始拉取,實作至少處理一次語意
候選者:八、會有少量的訊息重復,但只要下游做好冪等就OK了,

面試官:嗯,你也提到了冪等,你們這業務怎么實作冪等性的呢?
候選者:嗯,還是以處理訂單訊息為例好了,
候選者:冪等Key我們由訂單編號+訂單狀態所組成(一筆訂單的狀態只會處理一次)
候選者:在處理之前,我們首先會去查Redis是否存在該Key,如果存在,則說明我們已經處理過了,直接丟掉
候選者:如果Redis沒處理過,則繼續往下處理,最終的邏輯是將處理過的資料插入到業務DB上,再到最后把冪等Key插入到Redis上
候選者:顯然,單純通過Redis是無法保證冪等的(:
候選者:所以,Redis其實只是一個「前置」處理,最終的冪等性是依賴資料庫的唯一Key來保證的(唯一Key實際上也是訂單編號+狀態)
候選者:總的來說,就是通過Redis做前置處理,DB唯一索引做最終保證來實作冪等性的

面試官:你們那邊遇到過順序消費的問題嗎?
候選者:嗯,也是有的,我舉個例子
候選者:訂單的狀態比如有 支付、確認識訓、完成等等,而訂單下還有計費、退款的訊息報
候選者:理論上來說,支付的訊息報肯定要比退款訊息報先到嘛,但程式處理的程序中可不一定的嘛
候選者:所以在這邊也是有消費順序的問題
候選者:但在廣告場景下不是「強順序」的,只要保證最終一致性就好了,
候選者:所以我們這邊處理「亂序」訊息的實作是這樣的:
候選者:一、寬表:將每一個訂單狀態,單獨分出一個或多個獨立的欄位,訊息來時只更新對應的欄位就好,訊息只會存在短暫的狀態不一致問題,但是狀態最終是一致的
候選者:二、訊息補償機制:另一個進行消費相同topic的資料,訊息落盤,延遲處理,將訊息與DB進行對比,如果發現資料不一致,再重新發送訊息至主行程處理
候選者:還有部分場景,可能我們只需要把相同userId/orderId發送到相同的partition(因為一個partition由一個Consumer消費),又能解決大部分消費順序的問題了呢,

面試官:嗯…懂了

【對線面試官-移動端】系列 一周兩篇持續更新中!
【對線面試官-電腦端】系列 一周兩篇持續更新中!
原創不易!!求三連!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/339079.html
標籤:其他
上一篇:Spring與Kafka整合
下一篇:RabbitMQ實作延時佇列
