1. 程式人生 > >Kafka如何保證at-least-once

Kafka如何保證at-least-once

kafka最初是被LinkedIn設計用來處理log的分散式訊息系統,因此它的著眼點不在資料的安全性(log偶爾丟幾條無所謂),換句話說kafka並不能完全保證資料不丟失。

儘管kafka官網聲稱能夠保證at-least-once,但如果consumer程序數小於partition_num,這個結論不一定成立。

考慮這樣一個case,partiton_num=2,啟動一個consumer程序訂閱這個topic,對應的,stream_num設為2,也就是說啟兩個執行緒並行處理message。

如果auto.commit.enable=true,當consumer fetch了一些資料但還沒有完全處理掉的時候,剛好到commit interval出發了提交offset操作,接著consumer crash掉了。這時已經fetch的資料還沒有處理完成但已經被commit掉,因此沒有機會再次被處理,資料丟失。

如果auto.commit.enable=false,假設consumer的兩個fetcher各自拿了一條資料,並且由兩個執行緒同時處理,這時執行緒t1處理完partition1的資料,手動提交offset,這裡需要著重說明的是,當手動執行commit的時候,實際上是對這個consumer程序所佔有的所有partition進行commit,kafka暫時還沒有提供更細粒度的commit方式,也就是說,即使t2沒有處理完partition2的資料,offset也被t1提交掉了。如果這時consumer crash掉,t2正在處理的這條資料就丟失了。

如果希望能夠嚴格的不丟資料,解決辦法有兩個:

1.手動commit offset,並針對partition_num啟同樣數目的consumer程序,這樣就能保證一個consumer程序佔有一個partition,commit offset的時候不會影響別的partition的offset。但這個方法比較侷限,因為partition和consumer程序的數目必須嚴格對應。
2.另一個方法同樣需要手動commit offset,另外在consumer端再將所有fetch到的資料快取到queue裡,當把queue裡所有的資料處理完之後,再批量提交offset,這樣就能保證只有處理完的資料才被commit。當然這只是基本思路,實際上操作起來不是這麼簡單,具體做法以後我再另開一篇。