1. 程式人生 > >Kafka訊息delivery可靠性保證(Message Delivery Semantics)

Kafka訊息delivery可靠性保證(Message Delivery Semantics)

原文見:http://kafka.apache.org/documentation.html#semantics

kafka在生產者和消費者之間的傳輸是如何保證的,我們可以知道有這麼幾種可能提供的delivery guarantee:

  • At most once 訊息可能會丟,但絕不會重複傳輸
  • At least one 訊息絕不會丟,但可能會重複傳輸
  • Exactly once 每條訊息肯定會被傳輸一次且僅傳輸一次,很多時候這是使用者所想要的。

  值得注意的是,當Producer向broker傳送訊息時,一旦這條訊息被commit,因數replication的存在,它就不會丟。但是如果Producer傳送資料給broker後,遇到網路問題而造成通訊中斷,那Producer就無法判斷該條訊息是否已經commit。雖然Kafka無法確定網路故障期間發生了什麼,但是Producer可以生成一種類似於主鍵的東西,發生故障時冪等性的重試多次,這樣就做到了Exactly once。目前這一Feature還並未實現,有希望在Kafka未來的版本中實現。(所以目前預設情況下一條訊息從Producer到broker是確保了At least once,可通過設定Producer非同步傳送實現At most once)。

  接下來討論的是訊息從broker到Consumer的delivery guarantee語義。(僅針對Kafka consumer high level API)。Consumer在從broker讀取訊息後,可以選擇commit,該操作會在Zookeeper中儲存該Consumer在該Partition中讀取的訊息的offset。該Consumer下一次再讀該Partition時會從下一條開始讀取。如未commit,下一次讀取的開始位置會跟上一次commit之後的開始位置相同。當然可以將Consumer設定為autocommit,即Consumer一旦讀到資料立即自動commit。如果只討論這一讀取訊息的過程,那Kafka是確保了Exactly once。但實際使用中應用程式並非在Consumer讀取完資料就結束了,而是要進行進一步處理,而資料處理與commit的順序在很大程度上決定了訊息從broker和consumer的訊息投遞語義保證。

  • 讀完訊息先commit消費狀態(儲存offset)再處理訊息。這種模式下,如果Consumer在commit後還沒來得及處理訊息就crash了,下次重新開始工作後就無法讀到剛剛已提交而未處理的訊息,這對應at-most-once
  • 讀完訊息先處理再commit消費狀態(儲存offset)。這種模式下,如果在處理完訊息之後commit之前Consumer crash了,下次重新開始工作時還會處理剛剛未commit的訊息,實際上該訊息已經被處理過了。這對應at-least-once
  • 如果一定要做到exactly once,就需要協調offset和實際操作的輸出。經典的做法是引入兩階段提交,如果能讓offset和操作輸入存到同一個地方,會更簡潔和通用。這種方式可能更好,因為許多輸出系統可能不支援兩階段提交。比如,Consumer拿到資料後可能把資料放到HDFS,如果把最新的offset和資料本身一起寫到HDFS,那就可以保證資料的輸出和offset的更新要麼都完成,要麼都不完成,間接實現Exactly once。目前就high level api而言,offset是存於Zookeeper中的,無法存於HDFS,而low level API的offset是由自己去維護的,可以將之存於HDFS中.

Kafka預設保證At least once,並且允許通過設定Producer非同步提交來實現At most once。而Exactly once要求與外部儲存系統協作,幸運的是Kafka提供的offset可以非常直接非常容易得使用這種方式。

參考:

http://kafka.apache.org/documentation.html#semantics