目錄
2 如何數據處理時間不可控, 因爲長時間不poll導致consumer退出的問題?
1 exactly once的實現
exactly once是指消息不多不少, 只消費了一次。 與exactly once相對應的, 還有: at least once 消息最少消費一次, 允許消費多次;at most once, 消息最多消費一次, 允許少消費。
這裏的exactly once的實現, 是在整個kafka系統沒有都崩潰了的前提下的。
可以對這個問題進行分解, 分解爲兩個子問題:
- producer不多不少, 只生產了一次消息;
- consumer不多不少, 只消費了一次消息;
前提: broker的數量爲3個以上, replication的數量爲3個以上;整個kafka系統沒有都崩潰; producer不崩潰的情況下。
三種異常情況: 一個partition至少有一個replication存活, producer, consumer崩潰.
1 producer只生產了一次消息
不會少生產消息: producer設置acks參數爲all, 這樣broker返回成功時, 這個消息就已經保存在了kafka中了。 不管時producer崩潰還是一些broker崩潰, 都沒有辦法影響到這個消息落地。
不會多生產消息: 這個由生產者的自己的業務代碼決定;
2 consumer 只消費了一次消息
不會少消費消息:消費成功後, 需要commit 當前已經消費的offset。 這種情況, 當consumer崩潰時, 會從最新的comiit offset開始消費消息, 這可能會出現一部分的重複, 拿到那些已經消費但是未來得及提交的數據; 如果broker沒有全都崩潰, 也無法影響消息的消費。 到這裏, 我們就已經實現了at least once。
不會多消費消息:要保證無法多消費消息, 則需要在不會少消費消息的基礎上, 保證從消費成功, 到提交kafka這個操作是一個事務性操作, 要麼都成功, 要麼都失敗。 一般來說消費成功的標識是入庫成功, 可以通過把offset存放到數據庫等存儲系統的方法來實現,下次啓動時從數據庫中的offset開始消費。 具體可以有兩種方式:
支持事務的存儲系統, 如關係數據庫, 把提交offset和提交入庫數據作爲一個事務提交;
如果不支持事務, 但是對於一個數據記錄的存儲也可以保證原子性, 可以把offset信息放在數據記錄中;(當然這種方法對於關係數據庫也是ok的)
綜上, 就已經實現了exactly once的語義。
2 如何數據處理時間不可控, 因爲長時間不poll導致consumer退出的問題?
使用後臺線程進行數據處理。 需要調整的kafka相關的東西:
- 關閉自動提交;(默認是開啓自動提交的, 當poll時, 就會自動提交上一條數據)
- 消息消費完成之後才commit;
- 獲取一批消息之後 pause 分區, 確保沒有消費完消息之前不會收到新的消息;