消息投遞語義
Message Delivery Semantics
- At most once —— Messages may be lost but are never redelivered(消息可能丢失但不會重複投遞)
- At least once —— Messages are never lost but may be redelivered(消息不會丢失但可能重複投遞)
- Exactly once —— this is what people actually want, each message is delivered once and only once(消息隻投遞一次)
許多系統都聲稱提供"exactly once"投遞,但是仔細閱讀很重要,大部分這種宣稱都是誤導(他們沒有考慮生産者和消費者可能失敗的情況,以及多個消費者程序同時處理的情況,還有寫到磁盤上的資料可能丢失的情況)。
Kafka的消息投遞語義是直接的。釋出消息的時候我們有一個概念叫消息被送出到日志。一旦被釋出的消息被送出到日志,隻要有一個這個消息所在分區的broker活着消息就不會丢失。從0.11.0.0版本以後,Kafka生産者支援幂等投遞選項,以保證即使消息被重新發送,日志中也不會有重複的條目。為了實作這一點,broker給沒用個生成者指定一個ID并且每條消息指定一個序列号。
并不是所有的情況都需要這樣強的保證。
現在,讓我們站在消費者的角度來看這個語義。消費者用日志控制它的位置。如果消費者沒有崩潰它僅僅隻是在記憶體中存儲這個位置,但如果消費者失敗了,我們想要另一個程序來接管這個分區,那麼這個新的程序需要選擇一個合适的位置開始處理。讓我們來看一下消費者讀取消息後處理消息和更新位置的幾種選項。
- It can read the messages, then save its position in the log, and finally process the messages.(讀取消息,然後在日志中儲存位置,最後處理消息)。這種情況有一種可能就是消費者在儲存位置之後就崩潰了。這情況下接管的程序會從儲存的那個位置開始處理,即使在這個位置之前有一些消息沒有被處理也不管了。這與"at-most-once"的語義是一緻的,在這種情況下,消費者處理失敗的那些消息就不會被處理了。
- It can read the messages, process the messages, and finally save its position.(讀取消息,然後處理消息,最後儲存位置)。這種情況下有一種可能是消費者在處理消息之後儲存位置之前就崩潰了。這種情況下,新的程序接管以後會接收到一些之前已經被處理過的消息。這與"at-least-once"的語義是一緻的。在許多情況下,消息有一個主鍵,以至于更新是幂等的(接收相同的消息兩次,重寫日志記錄)。
The consumer's position is stored as a message in a topic, so we can write the offset to Kafka in the same transaction as the output topics receiving the processed data. If the transaction is aborted, the consumer's position will revert to its old value and the produced data on the output topics will not be visible to other consumers, depending on their "isolation level." In the default "read_uncommitted" isolation level, all messages are visible to consumers even if they were part of an aborted transaction, but in "read_committed," the consumer will only return messages from transactions which were committed (and any messages which were not part of a transaction).
當從主題消費并生産到另一個主題的時候,我們可以用事務生産者。消費者的位置作為消息被存儲在topic中,以至于我們可以在接收處理資料的那個事務中将offset寫到kafka。如果事務被中止,消費者的位置會恢複成舊值并且生産的資料對其它消費者不可見,這取決于隔離級别。預設的隔離級别是"read_uncommitted"表示消息對所有消費者可見,即使有些消息來自被中止的事務。
總結
1、消息投遞語義
最多一次:可能丢失消息但不會重複投遞
最少一次:不會丢失消息但可能重複投遞
精确一次:隻會投遞一次
2、kafka給每個生産者指定一個ID,每個釋出的消息一個序列号,這樣的話即使生産者重複發送消息,在送出日志中也不會有重複記錄
3、站在消費者的角度,先儲存位置後處理消息就是“最多一次”;先處理消息後儲存位置就是“最少一次”;至于“精确一次”,可以使用事務生産者來實作,即在同一個事務中接收并處理消息,将位置(offset)儲存到另一個topic中。隻要事務成功了,皆大歡喜,若事務失敗,則位置恢複。
參考 http://kafka.apache.org/documentation/#design