Apache Kafka訊息傳遞精確正好一次的含義 | TechMyTalk

banq發表於2020-06-02

在分散式環境中,故障是很常見的情況,可以隨時發生。在Kafka環境中,訊息代理可能會崩潰,網路故障,處理故障,釋出訊息時失敗或無法使用訊息等。這些不同的情況導致了不同型別的資料丟失和重複。

失敗場景

  • A(確認失敗):  生產者成功釋出了訊息,但由於失敗而未收到確認回執。在這種情況下,生產者將重試相同的訊息,可能會引入重複訊息。
  • B(生產者程式在批處理訊息中失敗):  生產者傳送了一批失敗的訊息,但釋出成功的很少。在這種情況下,一旦生產者重新啟動,它將再次批次重新發布所有訊息,這將在Kafka中引入重複訊息。
  • C(  觸發並忘記失敗)生產者釋出的訊息,重試= 0(觸發並忘記)。如果失敗,釋出的訊息將不知道並繼續傳送下一條訊息,這將導致上一條訊息丟失。
  • D(批處理訊息中的消費者失敗)  消費者從Kafka接收到一批訊息,並手動提交其偏移量(enable.auto.commit = false)。如果消費者在提交給Kafka之前失敗,則下次消費者將再次使用相同的記錄,這些記錄將在消費者端複製副本。


精確一次語義
在這種情況下,即使生產者嘗試重新傳送訊息,它也導致訊息將被消費者釋出和消費一次。
為了在Kafka中實現Exactly-Once語義,它使用以下3個屬性:

  • enable.idempotence = true
  • MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5(生產者每次連線總是有一個飛行中請求)
  • isolated.level = read_committed

啟用冪等(enable.idempotence = true)
冪等傳遞使生產者可以在單個生產者的生命週期內,將訊息僅一次寫入Kafka到主題的特定分割槽,而不會造成資料丟失和每個分割槽的訂單。

“請注意,啟用冪等性要求MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION小於或等於5,RETRIES_CONFIG大於0且ACKS_CONFIG為'all'。如果使用者未明確設定這些值,則將選擇合適的值。如果設定了不相容的值,將丟擲ConfigException”

為了實現冪等性,Kafka在生成訊息時使用唯一的ID(稱為產品ID或PID和序列號)。生產者在釋出的每個訊息上保持遞增的序列號,這些訊息具有唯一的PID。代理總是將當前序列號與前一個序列號進行比較,如果新序列號不比上一個序列號大+1,則它會拒絕,這會避免重複;如果訊息中丟失了更多的序列號,則會拒絕同時顯示

在失敗的情況下,代理將序列號與先前的序列號進行比較,如果序列不增加,+ 1將拒絕該訊息。

事務(isolation.level)
事務使我們能夠自動更新多個主題分割槽中的資料。事務中包含的所有記錄都將被成功儲存,或者沒有儲存成功,它允許您將同一個事務中的消費者補償與已處理的資料一起提交,從而允許端到端的一次精確語義。
生產者不等待將訊息寫到kafka,生產者使用beginTransaction,commitTransaction和abortTransaction(如果發生故障),消費者使用isolate.level級別:要麼是read_committed要麼是read_uncommitted

  • read_committed:使用者將始終僅讀取提交的資料。
  • read_uncommitted:以偏移順序讀取所有訊息,而無需等待事務提交

如果具有Isolation.level = read_committed的使用者到達尚未完成的事務的控制訊息,它將不會再從該分割槽傳遞任何訊息,直到生產者提交或中止該事務或發生事務超時。事務超時由生產者使用配置transaction.timeout.ms(預設為1分鐘)確定。

生產者和消費者中的確切時間
在正常情況下,生產者和消費者是分開的。生產者必須具有冪等性並同時管理事務,以便消費者可以使用isolation.level讀取read_committed以使整個過程成為原子操作。這樣可以確保生產者將始終與源系統同步。即使生產者崩潰或事務中止,它也始終是一致的,並且一次將訊息或一批訊息釋出為一個單元。
同一使用者一次將收到訊息或一批訊息。

在Exactly-Once中,語義生產者與消費者一起將作為原子操作出現,它將作為一個單元進行操作。要麼釋出一次就被消耗掉,要麼中止。

在Kafka Stream中恰好一次
Kafka Stream消耗來自主題A的訊息,處理並將訊息釋出到主題B,並在釋出後使​​用commit(commit主要在後臺執行)將所有狀態儲存資料重新整理到磁碟。
在Kafka Stream中,一次完全是讀取過程寫入模式,可確保將這些操作視為原子操作。由於Kafka Stream可以滿足生產者,消費者和交易的需求,因此Kafka Stream附帶了特殊的引數processing.guarantee,它可以完全地_once或at_least_once使得不單獨處理所有引數變得容易。
Kafka Streams原子地更新使用者偏移量,本地狀態儲存,狀態儲存changelog主題和生產,以一起輸出所有主題。如果這些步驟中的任何一個失敗,則所有更改都將回滾。
processing.guarantee:確切地提供一次以下引數,您無需明確設定

  1. isolated.level = read_committed
  2. enable.idempotence = true
  3. MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5




 

相關文章