[Day 24] Message Queue (二)

erichung0404
2024-08-24 16:16:26

雖然 Message Queue 沒有一個標準化規範, 實作會根據業務情境有些許不同, 但大多數都支援以下功能

生產者-消費者 模式 (Producer-Consumer Pattern)

傳送可靠性 (Delivery Reliability)

今天介紹基本的 Message Queue 如 ActiveMQ, RabbitMQ, RocketMQ 等
現在的 Message Queue 大部分都提供額外設定 (需更改預設值), 比如持久化訊息, 訊息多次傳遞等

生產者-消費者 模式

生產者-消費者 模式是一種 解綁兩個元件的模式, 像上篇提到的, 如果一個服務傳遞請求時, 由於發生分區錯誤而無法送達目標服務, 這個請求就永遠丟失了

生產者-消費者 模式則改善了這個問題, 將傳遞請求的服務視為 生產者 (Producer), 接收請求的服務為 消費者 (Consumer), 生產者 改將請求發給 Message Queue 等待, 消費者也改成從 Message Queue 中讀取請求處理

由於請求不需要立即處理, 如果 生產者 發送請求時, 消費者 發生分區錯誤, 就可以在重新上線時再從 Message Queue 中讀取請求

根據訊息可以被多少 消費者 處理, 可以分為

點對點模式 (Point-to-Point Pattern, P2P Pattern)

發布-訂閱 模式 (Publish-Subscribe Pattern, Pub/Sub Pattern)

P2P Pattern

即每個訊息只能夠被 "一個消費者" 處理, 適用於 分配任務, 分散請求等情境

Pub/Sub Pattern

即每個訊息可以傳送給 "多個消費者" 處理, 適用於跨服務的事件如 Logging, 事件通知, 訂閱服務等

傳送可靠性 (Delivery Guarantee)

和 P2P 與 Pub/Sub 不同著重於 一個訊息允許被多少消費者處理不同, 傳送可靠性是指 "一個訊息允許被傳送幾次"
主要是為了應對 消費者 沒有收到請求的情況

At-Least Once (至少一次)

即 每個訊息可以被同一個消費者讀取多次 (或者說 可以傳送多次, 看是 Server Push 還是 Polling, 請見 Day 6 介紹)

最簡單的方法就是 重試 (Retry) 直到 消費者 回覆收到請求, 適用於資料不能遺漏, 但可以收到多次相同請求的情境, 如 "重要" 通知訊息 (如轉帳, 開戶成功通知等, 雖然重複收到會有點惱人XD),

一個是否適用的判斷方式是, 該請求必須是 Idempotent (等冪) 的, 即每次請求後都會得到相同結果, 不涉及資料/狀態的修改

需要 確認 (Acknowledge, ACK) 機制

At-Most Once (最多一次)

即 每個訊息最多只能被處理一次, 但 "允許消費者沒有收到" (沒收到就算了XD)

通常適用於 "相對不重要" 或是 "非等冪" 的訊息如 線上餐廳訂位成功的通知 (Arguable, 通常會再打電話確認, 所以有 業務解 的情境也不一定要靠程式XD; ), Cache 更新 (非持久化的資料), Logging 等

Exactly Once (只有一次)

最難實作的傳送可靠性機制, 即保證 每個訊息 "只會" 被傳送一次
消費者 既不會收到重複的訊息, 也不會丟失訊息, 這會涉及到 一致性 的保證, 從而降低效能 (請見 Day 17)

標準的 Message Queue 如 RabbitMQ, RocketMQ 等 原生不一定支援此種傳送策略, 需要開發者自行實作 (累~"~)

如 交易系統 等需要一致性 (強一致性 或 最終一致性) 的情境

Reference

RabbitMQ - Reliability Guide

RocketMQ - Basic Best Practices