流媒體平台中的消息傳遞語義
一、概述
在本教程中,我們將討論流媒體平台中的消息傳遞語義。
首先,我們將快速了解流經流平台主要組件的事件流。接下來,我們將討論此類平台中數據丟失和重複的常見原因。然後,我們將專注於可用的三個主要交付語義。
我們將討論如何在流媒體平台中實現這些語義,以及它們如何處理數據丟失和重複問題。
在每個交付語義中,我們將非常簡要地介紹在 Apache Kafka 中獲得交付保證的方法。
2. 流媒體平台基礎
簡而言之,Apache Kafka 和 Apache ActiveMQ 等流媒體平台以實時或接近實時的方式處理來自一個或多個源(也稱為生產者)的事件,並將它們傳遞到一個或多個目的地(也稱為消費者)以進行進一步處理、轉換、分析或存儲。
生產者和消費者通過代理解耦,這實現了可擴展性。
流式應用程序的一些用例可能是電子商務網站中的大量用戶活動跟踪、實時金融交易和欺詐檢測、需要實時處理的自主移動設備等。
消息傳遞平台有兩個重要的考慮因素:
- 準確性
- 潛伏
通常,在分佈式實時系統中,我們需要在延遲和準確性之間進行權衡,具體取決於對系統更重要的是什麼。
這是我們需要了解開箱即用的流媒體平台提供的交付保證或使用消息元數據和平台配置實現所需的交付保證的地方。
接下來,讓我們簡要地看一下流媒體平台中的數據丟失和重複問題,然後我們將討論交付語義來管理這些問題
3. 可能的數據丟失和重複場景
為了了解流媒體平台中的數據丟失和/或重複,讓我們快速退後一步,看看流媒體平台中事件的高級流程:
在這裡,我們可以看到從生產者到消費者的流程中可能存在多個故障點。
通常,這會導致數據丟失、滯後和消息重複等問題。
讓我們關注上圖中的每個組件,看看可能出現的問題及其對流系統的可能後果。
3.1。生產者失敗
生產失敗可能會導致一些問題:
- 生產者生成消息後,它可能會在通過網絡發送之前失敗。這可能會導致數據丟失。
- 生產者在等待接收代理的確認時可能會失敗。當生產者恢復時,它會嘗試重新發送消息,假設缺少來自代理的確認。這可能會導致代理的數據重複。
3.2.生產者和經紀人之間的網絡問題
生產者和代理之間可能存在網絡故障:
- 由於網絡問題,生產者可能會發送一條永遠不會到達代理的消息。
- 也可能存在broker收到消息並發送確認,但生產者由於網絡問題而從未收到確認的情況。
在這兩種情況下,生產者都會重新發送消息,這會導致代理處的數據重複。
3.3.經紀人失敗
同樣,broker 故障也可能導致數據重複:
- 在將消息提交到持久存儲之後和向生產者發送確認之前,代理可能會失敗。這可能會導致生產者重新發送數據,從而導致數據重複。
- 代理可能正在跟踪消費者到目前為止已閱讀的消息。在提交此信息之前,代理可能會失敗。這可能會導致消費者多次讀取相同的消息,從而導致數據重複。
3.4.消息持久性問題
從內存狀態向磁盤寫入數據時可能會出現故障,導致數據丟失。
3.5.消費者和經紀人之間的網絡問題
代理和消費者之間可能存在網絡故障:
- 儘管代理髮送了消息並記錄了它發送了消息,但消費者可能永遠不會收到消息。
- 類似地,消費者可能在收到消息後發送確認,但確認可能永遠不會到達代理。
在這兩種情況下,代理都可能重新發送導致數據重複的消息
3.6.消費者失敗
- 消費者在處理消息之前可能會失敗。
- 消費者可能會在它處理消息的持久性存儲中記錄之前失敗。
- 消費者也可能在記錄它處理了消息之後但在發送確認之前失敗。
這可能會導致消費者再次向代理請求相同的消息,從而導致數據重複。
接下來,讓我們看看流媒體平台中可用的交付語義來處理這些問題,以滿足個別系統的需求。
4. 交付語義
交付語義定義了流媒體平台如何保證在我們的流媒體應用程序中將事件從源傳送到目的地。
有三種不同的交付語義可用:
- 最多一次
- 至少一次
- 恰好一次
4.1。最多一次交付
在這種方法中,消費者首先保存最後接收到的事件的位置,然後處理它。
簡單來說,如果中途事件處理失敗,消費者重啟後,就無法返回讀取舊事件。
因此,不能保證所有接收到的事件都能成功處理事件。
至多語義對於某些數據丟失不是問題並且準確性不是強制性的情況是理想的。
考慮使用消息偏移量的 Apache Kafka 的示例,At-Most-Once 保證的順序為:
- 持續偏移
- 堅持結果
為了在 Kafka 中啟用 At-Most-Once 語義,我們需要在消費者處將“ enable.auto.commit”
設置為“ true”
。
如果發生故障並且消費者重新啟動,它將查看最後一個持久的偏移量。由於偏移量在實際事件處理之前被保留,我們無法確定消費者收到的每個事件是否都已成功處理。在這種情況下,消費者最終可能會錯過一些事件。
讓我們可視化這個語義:
4.2.至少一次交付
在這種方法中,消費者處理接收到的事件,將結果保存在某個地方,然後最後保存最後接收到的事件的位置。
與 at-most-once 不同,在這裡,如果發生故障,消費者可以讀取並重新處理舊事件。
在某些情況下,這可能會導致數據重複。讓我們考慮消費者在處理和保存事件之後但在保存最後一個已知事件位置(也稱為偏移量)之前失敗的示例。
消費者將重新啟動並從偏移量中讀取。在這裡,消費者不止一次地重新處理事件,因為即使在失敗之前成功處理了消息,最後接收到的事件的位置也沒有成功保存:
這種方法非常適合任何更新代碼或儀表以顯示當前值的應用程序。但是,需要準確聚合的用例(如求和和計數器)對於至少一次處理來說並不理想,主要是因為重複事件會導致不正確的結果。
因此,在這種交付語義中,不會丟失任何數據,但可能會出現重新處理相同事件的情況。
為了避免多次處理同一個事件,我們可以使用冪等消費者。
本質上,冪等消費者可以多次消費一條消息,但只處理一次。
以下方法的組合使冪等消費者能夠進行至少一次交付:
- 生產者為每條消息分配一個唯一的
messageId
。 - 消費者在數據庫中維護所有已處理消息的記錄。
- 當新消息到達時,消費者會根據持久存儲表中現有的
messageId
來檢查它。 - 如果匹配,消費者會更新偏移量而不重新消費,發回確認,並有效地將消息標記為已消費。
- 當事件不存在時,將啟動一個數據庫事務,並插入一個新的
messageId
。接下來,根據所需的任何業務邏輯處理此新消息。消息處理完成後,事務最終提交
在 Kafka 中,為了確保至少一次語義,生產者必須等待代理的確認。
如果生產者沒有收到代理的任何確認,它會重新發送消息。
此外,由於生產者將消息批量寫入代理,如果寫入失敗並且生產者重試,則批處理中的消息可能會在 Kafka 中寫入多次。
但是,為了避免重複,Kafka 引入了冪等生產者的特性。
本質上,為了在 Kafka 中啟用至少一次語義,我們需要:
- 在生產者端將屬性“
ack
”設置為值“1”
- 在消費者端將“
enable.auto.commit
”屬性設置為“false
”。 - 將“
enable.idempotence
”屬性設置為“true
” - 將序列號和生產者 ID 附加到來自生產者的每條消息
Kafka Broker 可以使用序列號和生產者 ID 識別主題上的消息重複。
4.3.一次性交付
這種交付保證類似於至少一次語義。首先,處理接收到的事件,然後將結果存儲在某處。在失敗和重啟的情況下,消費者可以重新讀取和重新處理舊的事件。但是,**與 at-least-once 處理不同,任何重複的事件都將被丟棄並且不被處理,從而導致完全一次處理。**
這對於任何對準確性很重要的應用程序來說都是理想的,例如涉及聚合的應用程序,例如準確的計數器或其他任何需要事件只處理一次且不會丟失的應用程序。
順序如下:
- 堅持結果
- 持續偏移
讓我們看看當消費者在處理事件後失敗但沒有保存下圖中的偏移量時會發生什麼:
我們可以通過以下方式刪除完全一次語義中的重複:
- 冪等更新——我們將結果保存在生成的唯一鍵或 ID 上。在重複的情況下,生成的鍵或 ID 已經在結果中(例如數據庫),因此消費者可以刪除重複項而不更新結果
- 事務更新——我們將分批保存需要事務開始和事務提交的結果,因此在提交的情況下,事件將被成功處理。在這裡,我們將簡單地刪除重複的事件而不更新任何結果。
讓我們看看我們需要做些什麼來在 Kafka 中啟用完全一次語義:
- 通過為每個生產者設置“
transaction.id
”的唯一值,在生產者上啟用冪等生產者和事務功能 - 通過將屬性“
isolation.level
”設置為值“read_committed
”來啟用消費者的事務功能
5. 結論
在本文中,我們看到了流媒體平台中使用的三種交付語義之間的差異。
在簡要概述了流式平台中的事件流之後,我們研究了數據丟失和重複問題。然後,我們看到瞭如何使用各種交付語義來緩解這些問題。然後我們研究了至少一次交付,然後是最多一次,最後是精確一次交付語義。