1. 程式人生 > >kafka使用high api如何確保不丟失訊息,不重複傳送,訊息只讀取一次?

kafka使用high api如何確保不丟失訊息,不重複傳送,訊息只讀取一次?

首先說明,Kafka 的設計就是 at-least-once 的


那麼,如何確保非極端環境下,Kafka 不丟資料,以及 Kafka 叢集儘可能穩定呢?
  1. Producer 端設定 ack 為 all(或者說盡可能越多越好,但實際生產裡叢集例項過多,這樣設定會影響效能,因此根據具體情況來定),即 確保所有 replication 都拿到資料的時候,send 方法才得以返回,以此來判斷資料是否傳送成功,那麼理論上來說,此時傳送成功的資料都不會丟失;
  2. unclean.leader.election.enable 設定為 false(預設引數為 true),意思是,當存有你最新一條記錄的 replication 宕機的時候,Kafka 自己會選舉出一個主節點,如果預設允許還未同步你最新資料的 replication 所在的節點被選舉為主節點的話,你的資料將會丟失,因此這裡應該按需將引數調控為 false;
  3. auto.offset.reset 引數設定為 earliest 避免出現 offset 丟失的時候,跳過需要消費的資料的情況,準確來說這裡並非丟失,即使因為引數配置的問題出現跳過的情況,也可以通過前置 offset 找回歷史訊息;
  4. 資料持久化的時間需要設定業務足夠接受的程度,我自己業務上使用就是能保證我的資料持久化時間為8個小時,超過8個小時的資料將被清空。

即使這樣配置了,Kafka 在極端環境下也並非確保絕對不丟資料!!!


既然是極端環境的探討,也就意味著能碰到的機率是非常低的,機率有多少我沒統計過,其中第二種情況在業務中時常遇到。
  1. 根據 Kafka 官方文件說明,Producer 傳送訊息持久化到 Kafka 得到 ack 的回饋這段過程中,基於效能的考慮,Kafka 並沒有及時把資料落盤的,而是將資料放到記憶體(FS cache)中,並週期性的落盤(從磁碟監控也可以看的出來),如果資料未及時落盤,如遇到伺服器斷電宕機,則資料丟失;
  2. 實際業務中,對資料可靠性較高的場景我建議手動提交 offset,自動提交 offset 會出現一個比較尷尬的情況,在業務應用被 kill 之前, A 訊息的offset 可能被提交了,然而 A 訊息在應用系統中尚未執行完畢,且狀態都儲存在了記憶體中,無法保留,此時重啟應用將不會繼續消費 A 訊息,而是神不知鬼不覺的跳過。當然這種情況也並非算得上丟失資料,重置 offset 一樣可以找的回來,但是手動提交 offset 可以避免這種詭異的情況發生。

Kafka HA 如何保障?
官方的意思是儘可能多節點叢集部署,節點數儘可能大於等於3,並且 replication 數量也是大於等於3,那麼當 replication 數量為 N 時,ack 設定為 all,這種情況下,就能確保 N-1臺機子宕機的時候,資料仍能保持不丟。

另外補充,既然是at-least-once,肯定會出現重複消費的情況,這個不難解決,Consumer 保持無狀態和冪等性就可以了。