訊息儲存
訊息儲存方式
非持久化
-
訊息生成者傳送訊息到 MQ
-
MQ 返回 ACK(Acknowledge Character)給生產者
-
MQ push 訊息給對應的消費者
-
訊息消費者返回 ACK 給 MQ
持久化
-
訊息生成者傳送訊息到 MQ
-
MQ 收到訊息,將訊息進行持久化,儲存該訊息
-
MQ 返回 ACK 給生產者
-
MQ push 訊息給對應的消費者
-
訊息消費者返回 ACK 給 MQ
-
MQ 刪除訊息
注意:
①第 5 步 MQ 在指定時間內接到訊息消費者返回 ACK,MQ 認定訊息消費成功,執行 6 。
②第 5 步 MQ 在指定時間內未接到訊息消費者返回 ACK,MQ 認定訊息消費失敗,重新執行 4、5、6 。
訊息儲存介質
資料庫
-
實現:ActiveMQ
-
缺點:資料庫瓶頸將成為 MQ 瓶頸
檔案系統
-
實現:RocketMQ/Kafka/RabbitMQ
-
解決方案:採用訊息刷盤機制進行資料儲存
-
缺點:硬碟損壞的問題無法避免
訊息儲存與讀寫方式
SSD(Solid State Disk):固態硬碟
-
隨機寫(100 KB/s)
-
順序寫(600 MB/s):1秒1部電影
Linux 系統傳送資料的方式
- “零拷貝”技術
- 資料傳輸由傳統的 4 次複製簡化成 3 次複製,減少 1 次複製過程
- Java 語言中使用 MappedByteBuffer 類實現了該技術
- 要求:預留儲存空間,用於儲存資料(1G 儲存空間起步)
訊息儲存結構
如圖所示,MQ 資料儲存區域包含如下內容:
- 訊息資料儲存區域
- topic
- queueId
- message
- 消費邏輯佇列
- minOffset
- maxOffset
- consumerOffset
- 索引
- key 索引
- 建立時間索引
- ……
刷盤機制
同步刷盤
-
生產者傳送訊息到 MQ,MQ 接到訊息資料
-
MQ 掛起生產者傳送訊息的執行緒
-
MQ 將訊息資料寫入記憶體
-
記憶體資料寫入硬碟
-
磁碟儲存後返回 SUCCESS
-
MQ 恢復掛起的生產者執行緒
-
傳送 ACK 到生產者
非同步刷盤
-
生產者傳送訊息到 MQ,MQ 接到訊息資料
-
MQ 將訊息資料寫入記憶體
-
傳送 ACK 到生產者
小結
- 同步刷盤:安全性高,效率低,速度慢(適用於對資料安全要求較高的業務)
- 非同步刷盤:安全性低,效率高,速度快(適用於對資料處理速度要求較高的業務)
# 刷盤方式
#- ASYNC_FLUSH 非同步刷盤
#- SYNC_FLUSH 同步刷盤
flushDiskType=SYNC_FLUSH
高可用
高可用實現
nameserver
- 無狀態 + 全伺服器註冊
訊息伺服器
- 主從架構(2M-2S)
訊息生產
- 生產者將相同的 topic 繫結到多個 group 組,保證即使 broker master 掛掉,其他 master 仍可正常進行訊息接收。
訊息消費
- RocketMQ 自身會根據 broker master 的壓力確認是否由 master 承擔訊息讀取的功能,當 master 繁忙時候,自動切換由 slave 承擔資料讀取的工作。
主從複製
同步複製:
- master 接到訊息後,先複製到 slave,然後反饋給生產者寫操作成功
- 優點:資料安全,不丟資料,出現故障容易恢復
- 缺點:影響資料吞吐量,整體效能低
非同步複製:
- master 接到訊息後,立即返回給生產者寫操作成功,當訊息達到一定量後再非同步複製到slave
- 優點:資料吞吐量大,操作延遲低,效能高
- 缺點:資料不安全,會出現資料丟失的現象,一旦 master 出現故障,從上次資料同步到故障時間的資料將丟失
配置方式:
#Broker 的角色
#- ASYNC_MASTER 非同步複製Master
#- SYNC_MASTER 同步雙寫Master
#- SLAVE
brokerRole=SYNC_MASTER
負載均衡
Producer 負載均衡:
- 內部實現了不同 broker 叢集中對同一 topic 對應訊息佇列的負載均衡
Consumer 兩種負載均衡策略:
-
平均分配
-
迴圈平均分配
訊息重試
當訊息消費後未正常返回消費成功的資訊將啟動訊息重試機制
兩種訊息重試機制:
-
順序訊息重試
-
無序訊息重試
順序訊息重試
- 當消費者消費訊息失敗後,RocketMQ 會自動進行訊息重試(每次間隔時間為 1 秒)。
- 注意:應用會出現訊息消費被阻塞的情況,因此,要對順序訊息的消費情況進行監控,避免阻塞現象的發生。
無序訊息重試
- 無序訊息包括普通訊息、定時訊息、延時訊息、事務訊息。
- 無序訊息重試僅適用於負載均衡(叢集)模型下的訊息消費,不適用於廣播模式下的訊息消費。
- 為保障無序訊息的消費,MQ 設定了合理的訊息重試間隔時長。
死信佇列
概念:
-
當訊息消費重試到達了指定次數(預設 16 次)後,MQ 將無法被正常消費的訊息稱為死信訊息(Dead-Letter Message)。
-
死信訊息不會被直接拋棄,而是儲存到了一個全新的佇列中,該佇列稱為死信佇列(Dead-Letter Queue)。
死信佇列的特徵:
- 歸屬某一個組(Gourp Id),而不歸屬 Topic,也不歸屬消費者。
- 一個死信佇列中可以包含同一個組下的多個 Topic 中的死信訊息。
- 死信佇列不會進行預設初始化,當第一個死信出現後,此佇列首次初始化。
死信佇列中的訊息的特徵:
- 不會被再次重複消費。
- 死信佇列中的訊息有效期為 3 天,達到時限後將被清除。
死信處理:
- 在監控平臺中,通過查詢死信,獲取死信的 messageId,然後通過 id 對死信進行精準消費。
訊息冪等
訊息重複消費
訊息重複消費原因:
- 生產者傳送了重複的訊息
- 網路閃斷
- 生產者當機
- 訊息伺服器投遞了重複的訊息
- 網路閃斷
- 動態的負載均衡過程
- 網路閃斷/抖動
- broker重啟
- 訂閱方應用重啟(消費者)
- 客戶端擴容
- 客戶端縮容
訊息冪等
對同一條訊息,無論消費多少次,結果保持一致,稱為訊息冪等性。
解決方案:
-
使用業務 id 作為訊息的 key 。
-
在消費訊息時,客戶端對 key 做判定,未使用過放行,使用過拋棄。
- 注意:messageId 由 RocketMQ 產生,messageId 並不具有唯一性,不能作用冪等判定條件。
常見的冪等方法示例:
- 新增(不冪等):insert into order values(……)
- 查詢(冪等)
- 刪除(冪等):delete from 表 where id=1
- 修改(不冪等):update account set balance = balance+100 where no=1
- 修改(冪等):update account set balance = 100 where no=1