怎麼做才能不丟消息?

現在主流的消息隊列產品都提供了非常完善的消息可靠性保證機制,可以做到在消息傳遞的過程中,即使發生網絡中斷或者硬件故障,也能確保消息的可靠傳遞、不丟消息。

絕大部分丟消息的原因都是由於開發者不熟悉消息隊列,沒有正確使用和配置消息隊列導致的。

檢測消息丟失的方法

用消息隊列最尷尬的情況不是丟消息,而是丟了消息還不知道。因此,我們需要設計一套機制來監控消息是否有丟失。

根據項目的成熟程度,一般有兩種方式來檢測:

  1. 如果項目基礎設施比較完善,那麼可以使用分佈式鏈路追蹤系統來追蹤每一條消息。
  2. 如果項目初期,系統剛上線,那麼可以利用消息隊列的有序性來檢測是否有消息丟失。

我們可以在Producer端發出的每一條消息附加一個連續遞增的序號,然後在Consumer端檢測這個序號的連續性。如果沒有消息丟失,Consumer收到的消息的序號必然是連續遞增的,如果檢測到序號不連續,那麼就是丟消息了,還可以通過缺失的序號來確定丟失的是哪一條消息。

針對這種檢測方法,有3條建議:

  1. 像Kafka和RocketMQ這樣的消息隊列,它不保證消息在Topic上的嚴格順序,只能保證消息在分區(隊列)上是有序的,所以我們在發消息的時候必須要指定分區,並且每個分區單獨檢測消息序號的連續性。
  2. 如果系統中有多個Producer實例,並且不好協調多個Producer之間的發送順序,那麼也需要針對每個Producer分別生成各自的消息序號,並且需要附加上Producer標識,在Consumer端按照每個Producer分別來檢測序號的連續性。
  3. Consumer實例的數量最好和分區數量一致,做到Consumer和分區一一對應,這樣比較方便在Consumer內檢測消息序號的連續性。

消息可靠傳遞

一條消息從生產到消費完成的過程,可以分爲三個階段:

  1. 生產階段:消息在Producer創建出來,經過網絡傳輸到Broker端。
  2. 存儲階段:消息在Broker端存儲,如果是集羣,消息還會被複制到其他副本上。
  3. 消費階段:Consumer從Broker上拉取消息,經過網絡傳輸到Consumer上。

消息生產階段

在生產階段,消息隊列最常用的是請求-確認機制,來保證消息的可靠傳遞:當代碼調用發消息方法時,消息隊列的客戶端會把消息發送到Broker,Broker收到消息後,會給客戶端返回一個確認響應,表示消息已經收到了。

只要Producer收到了Broker的確認響應,就可以保證消息在生產階段不會丟失。有的消息隊列會在長時間沒有收到發送確認響應後,自動重試,如果重試再失敗,就會以返回值或者異常的方式告知用戶。

消息存儲階段

在存儲階段正常情況下,只要Broker在正常運行,就不會出現丟失消息的問題,但是如果Broker出現了故障,還是有可能會丟消息。

如果對消息的可靠性要求非常高,可以通過配置Broker參數來避免因爲宕機丟消息。

如果Broker是由多個節點組成的集羣,那麼需要將Broker集羣配置成:至少將消息發送到2個以上的節點後,再給客戶端回覆發送確認響應。

消息消費階段

消費階段採用和生產階段類似的請求-確認機制來保證消息的可靠傳遞,客戶端從Broker拉取消息後,執行用戶的消費業務邏輯,成功後,纔會給Broker發送消費確認響應。

如果Borker沒有收到消費確認響應,下次拉消息時還會返回同一條消息,確保消息不回在網絡傳輸過程中丟失,也不會因爲客戶端在執行消費邏輯中出錯導致丟失。

我們需要注意,不要在收到消息後就立即發送消費確認,而是應該在執行完所有消費業務邏輯之後,再發送消費確認。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章