Apache Kafka訊息傳遞策略

Arno_z發表於2024-10-14

kafka訊息傳遞策略

  • 微信公眾號:阿俊的學習記錄空間
  • 小紅書:ArnoZhang
  • wordpress:arnozhang1994
  • 部落格園:arnozhang
  • CSDN:ArnoZhang1994

現在我們瞭解了一些關於生產者和消費者的工作原理,接下來討論Kafka在生產者和消費者之間提供的策略保證。顯然,訊息傳遞可以提供多種保證:

  • 最多一次——訊息可能會丟失,但從不會被重新傳送。
  • 至少一次——訊息不會丟失,但可能會被重複傳送。
  • 精確一次——這是理想狀態,每條訊息僅傳遞一次且不會重複。

需要注意的是,這可以分解為兩個問題:釋出訊息的永續性保證和消費訊息時的保證。

很多系統聲稱提供“精確一次”的傳遞策略,但仔細閱讀細則後會發現,這些宣告大多是誤導性的(例如,在生產者或消費者失敗的情況下、存在多個消費者程序時、或磁碟上的資料可能丟失時,這些保證不再成立)。

Kafka 的策略相對簡單。當釋出訊息時,我們有一個“提交”訊息到日誌的概念。一旦訊息被提交,只要其中一個複製該訊息的分割槽的broker仍然“存活”,訊息就不會丟失。目前我們假設一個理想、無損的broker,來理解生產者和消費者的保證。當生產者嘗試釋出訊息並遇到網路錯誤時,它無法確定錯誤發生在訊息提交之前還是之後。這類似於向資料庫插入帶有自生成鍵的記錄。

在0.11.0.0版本之前,如果生產者未能收到訊息已提交的響應,它幾乎只能重新傳送訊息。這提供了至少一次的傳遞策略,因為在重發時,原始請求可能已經成功,訊息可能會再次寫入日誌。從0.11.0.0版本開始,Kafka 生產者還支援冪等傳遞選項,保證重新傳送不會導致日誌中出現重複條目。為實現這一點,broker會為每個生產者分配一個ID,並透過生產者在每條訊息中附帶的序列號去重。從0.11.0.0版本開始,生產者還支援使用類似事務的策略將訊息傳送到多個topic分割槽:要麼所有訊息都成功寫入,要麼都不會寫入。其主要用例是Kafka topic間的精確一次處理(將在下文描述)。

並非所有用例都需要如此強的保證。對於對延遲敏感的用例,我們允許生產者指定所需的永續性級別。如果生產者指定希望等待訊息被提交,這可能需要約10毫秒。然而,生產者也可以指定完全非同步傳送,或者僅等待主副本(而不一定是所有副本)接收訊息。

現在從消費者的角度描述策略。所有副本都有完全相同的日誌,且有相同的偏移量。消費者控制它在日誌中的位置。如果消費者從未崩潰,它可以將位置儲存在記憶體中,但如果消費者失敗,且我們希望另一個程序接管該topic分割槽,那麼新程序需要選擇一個合適的位置開始處理。假設消費者讀取了一些訊息,它有幾種處理訊息和更新其位置的選項:

  1. 它可以讀取訊息,然後儲存其在日誌中的位置,最後處理訊息。在這種情況下,消費者程序可能在儲存其位置後但在處理訊息結果之前崩潰。接管的程序會從已儲存的位置開始處理,即使某些訊息尚未被處理。這對應於“最多一次”策略,因為在消費者故障的情況下,訊息可能不會被處理。
  2. 它可以先讀取訊息,處理訊息,最後儲存其位置。在這種情況下,消費者程序可能在處理完訊息後但在儲存位置之前崩潰。接管的新程序會接收到已經處理過的前幾條訊息。這對應於“至少一次”策略。在許多情況下,訊息有一個主鍵,因此更新是冪等的(即接收同一條訊息兩次只會覆蓋之前的記錄)。

那麼關於精確一次策略呢(即我們真正需要的)?當從Kafka topic消費並向另一個topic生產訊息時(如在Kafka Streams應用中),我們可以利用0.11.0.0中提到的新事務性生產者功能。消費者的位置被儲存為一個topic中的訊息,因此我們可以將偏移量寫入Kafka,並與接收已處理資料的輸出topic一起使用同一事務。如果事務被中止,消費者的位置將回滾到舊值,輸出topic中的資料將對其他消費者不可見,這取決於它們的“隔離級別”。在預設的“未提交讀取”隔離級別下,消費者可以看到所有訊息,即使這些訊息是中止事務的一部分;而在“已提交讀取”中,消費者只會返回已提交事務中的訊息(以及未參與事務的訊息)。

當寫入外部系統時,限制在於需要協調消費者的位置與實際儲存的輸出。經典的實現方法是將消費者位置的儲存與消費者輸出的儲存之間引入兩階段提交。但這可以透過讓消費者將偏移量儲存在與輸出相同的地方來更簡單且通用地解決。這種方法更好,因為消費者可能寫入的許多輸出系統不支援兩階段提交。作為一個示例,Kafka Connect聯結器會將資料寫入HDFS,並儲存其讀取的資料的偏移量,以保證資料和偏移量要麼一起更新,要麼都不更新。我們對許多其他需要這些更強策略的資料系統採用了類似的模式,而這些訊息沒有主鍵來實現去重。

因此,Kafka 在Kafka Streams中有效支援了精確一次傳遞,並且事務性生產者/消費者通常可以用於在Kafka topic之間傳輸和處理資料時提供精確一次傳遞。對於其他目標系統,通常需要這些系統的配合,但Kafka提供的偏移量使實現這一點變得可行(另見Kafka Connect)。否則,Kafka預設保證至少一次傳遞,並允許使用者透過禁用生產者的重試功能和在消費者處理訊息批次前提交偏移量來實現最多一次傳遞。

相關文章