Kafka 訊息交付可靠性保障

2021-10-12 06:31:11 字數 3066 閱讀 2587

所謂的訊息交付可靠性保障,是指 kafka 對 producer 和 consumer 要處理的訊息提供什麼樣的承諾。常見的承諾有以下三種:

目前,kafka 預設提供的交付可靠性保障是 至少一次。

訊息「已提交「的含義為:只有 broker 成功「提交」訊息且 producer 接到 broker 的應答才會認為該訊息傳送成功。

不過倘若訊息成功」提交「,但 broker 的應答沒有成功返回 producer 客戶端(比如網路出現瞬時抖動),那麼 producer 就無法確定訊息是否真的提交成功了。因此,它只能選擇重試,也就是再次傳送相同的訊息。這就是 kafka 預設提供至少一次可靠性保障的原因,不過這會導致訊息重**送。

kafka 也可以提供最多一次的交付保障,只需要讓 producer 禁止重試即可。這樣一來,訊息要麼寫入成功,要麼寫入失敗,但絕不會重**送。

無論是至少一次還是最多一次,都不如精確一次來得有吸引力。大部分使用者還是希望訊息只會被交付一次,這樣的話,訊息既不會丟失,也不會被重複處理。或者說,即使 producer 端重**送了相同的訊息,broker 端也能做到自動去重。在下游 consumer 看來,訊息依然只有一條。

那麼 kafka 是怎麼做到精確一致性的呢?簡單來說,這是通過兩種機制冪等性(idempotence)和事務(transaction)。

在 kafka 中,producer 預設不是冪等性的,但我們可以建立冪等性 producer。它其實是 0.11.0.0 版本引入的新功能。在此之前,kafka 向分割槽傳送資料時,可能會出現同一條訊息被傳送了多次,導致訊息重複的情況。在 0.11 之後,指定 producer 冪等性的方法很簡單,僅需要設定乙個引數即可,即 props.put(「enable.idempotence」, ture),或 props.put(producerconfig.enable_idempotence_config, true)。

enable.idempotence 被設定成 true 後,producer 自動公升級成冪等性 producer,其他所有的**邏輯都不需要改變。kafka 自動幫你做訊息的重複去重。底層具體的原理很簡單,就是經典的用空間去換時間的優化思路,即在 broker 端多儲存一些字段。當 producer 傳送了具有相同字段值的訊息後,broker 能夠自動知曉這些訊息已經重複了,於是可以在後台默默地把它們「丟棄」掉。當然,實際的實現原理並沒有這麼簡單,但你大致可以這麼理解。

看上去,冪等性 producer 的功能很酷,使用起來也很簡單,僅僅設定乙個引數就能保證訊息不重複了,但實際上,我們必須要了解冪等性 producer 的作用範圍。

首先,它只能保證單分割槽上的冪等性,即乙個冪等性 producer 能夠保證某個主題的乙個分割槽上不出現重複訊息,它無法實現多個分割槽的冪等性。其次,它只能實現單會話上的冪等性,不能實現跨會話的冪等性。這裡的會話,你可以理解為 producer 程序的一次執行。當你重啟了 producer 程序之後,這種冪等性保證就喪失了。

那麼你可能會問,如果我想實現多分割槽以及多會話上的訊息無重複,應該怎麼做呢?答案就是事務(transaction)或者依賴事務型 producer。這也是冪等性 producer 和事務型 producer 的最大區別!

kafka 的事務概念類似於我們熟知的資料庫提供的事務。在資料庫領域,事務提供的安全性保障是經典的 acid,即原子性(atomicity)、一致性 (consistency)、隔離性 (isolation) 和永續性 (durability)。

kafka 自 0.11 版本開始也提供了對事務的支援,目前主要是在 read committed 隔離級別上做事情。它能保證多條訊息原子性地寫入到目標分割槽,同時也能保證 consumer 只能看到事務成功提交的訊息。下面我們就來看看 kafka 中的事務型 producer。

事務型 producer 能夠保證將訊息原子性地寫入到多個分割槽中。這批訊息要麼全部寫入成功,要麼全部失敗。另外,事務型 producer 也不懼程序的重啟。producer 重啟回來後,kafka 依然保證它們傳送訊息的精確一次處理。

設定事務型 producer 的方法也很簡單,滿足兩個要求即可:

此外,你還需要在 producer **中做一些調整,如這段**所示:

producer.

inittransactions()

;try

catch

(kafkaexception e)

和普通 producer **相比,事務型 producer 的顯著特點是呼叫了一些事務 api,如 inittransaction、begintransaction、committransaction 和 aborttransaction,它們分別對應事務的初始化、事務開始、事務提交以及事務終止

這段**能夠保證 record1 和 record2 被當作乙個事務統一提交到 kafka,要麼它們全部提交成功,要麼全部寫入失敗。實際上即使寫入失敗,kafka 也會把它們寫入到底層的日誌中,也就是說 consumer 還是會看到這些訊息。因此在 consumer 端,讀取事務型 producer 傳送的訊息也是需要一些變更的。修改起來也很簡單,設定 isolation.level 引數的值即可。當前這個引數有兩個取值:

read_uncommitted:這是預設值,表明 consumer 能夠讀取到 kafka 寫入的任何訊息,不論事務型 producer 提交事務還是終止事務,其寫入的訊息都可以讀取。很顯然,如果你用了事務型 producer,那麼對應的 consumer 就不要使用這個值。

read_committed:表明 consumer 只會讀取事務型 producer 成功提交事務寫入的訊息。當然了,它也能看到非事務型 producer 寫入的所有訊息。

簡單來說,冪等性 producer 和事務型 producer 都是 kafka 社群力圖為 kafka 實現精確一次處理語義所提供的工具,只是它們的作用範圍是不同的。冪等性 producer 只能保證單分割槽、單會話上的訊息冪等性;而事務能夠保證跨分割槽、跨會話間的冪等性。從交付語義上來看,自然是事務型 producer 能做的更多。

不過,切記天下沒有免費的午餐。比起冪等性 producer,事務型 producer 的效能要更差,在實際使用過程中,我們需要仔細評估引入事務的開銷,切不可無腦地啟用事務。

Kafka訊息可靠性

如果mq沒有類似資料庫事務結構和保證,是不可能達到訊息投遞100 可靠的,極端情況下訊息投遞要麼丟失或重複。下面咋們從producer,broker,consumer的角度分析一下kafka中會出現哪些情況。目前生產者傳送訊息 request.required.acks 有三種方式。acks 0 p...

kafka原理解析之 訊息可靠性保障

本文討論的是假設存在完美無缺的producer和consumer,從broker角度保障資料可靠的機制。當isr集合發生增減 或者isr集合中任一副本leo發生變化時,都會影響整個分割槽的hw。如上圖所示 leader的leo為9,follower的leo為7,而follower2的leo為6,若判...

kafka 九 Kafka訊息的可靠性

沒有乙個中介軟體能夠做到百分之百的完全可靠,可靠性更多的還是基於幾個9的衡量指標,比如4個9 5 個9.軟體系統的可靠性只能夠無限去接近100 但不可能達到100 所以kafka如何是實現最大可能的可靠性呢?你可以建立更多的分割槽來提公升可靠性,但是分割槽數過多也會帶來效能上的開銷,一般來說,3個副...