何時需要消息隊列?
| 場景 | 適用性 | 核心價值 |
| 業務解耦 | ✅ 強推薦 | 生產者不關心消費者邏輯,只發通知 |
| 最終一致性 | ✅ 推薦 | 跨服務事務(扣款/加款)通過可靠消息實現 |
| 廣播/扇出 | ✅ 強推薦 | 一條消息多下游消費,新接入零改造 |
| 錯峰流控 | ✅ 推薦 | 削峰填谷,保護下游脆弱服務(如短信網關) |
| 強一致性/即時結果 | ❌ 不適合 | 請用同步 RPC |
消息隊列核心模型:Push vs Pull
Push 模型(傳統 JMS/RabbitMQ/RocketMQ)
- Broker 主動推送 → Consumer
- **痛點**:慢消費導致堆積、推送速度不可控、需 ACK 機制保證可靠
- **優勢**:實時性高、編程模型簡單
Pull 模型(Kafka/MetaQ/Pulsar)
- Consumer 主動拉取 → Broker
- **優勢**:消費者可控速率、天然支持回溯/重消費、Broker 無狀態易擴展
- **痛點**:長輪詢延遲、忙等開銷、順序消費需分區設計
從零設計 MQ 關鍵模塊
1. RPC 通信層
- **不要造輪子**:復用公司現有 RPC(Thrift/Dubbo/gRPC)
- 兩大核心接口:`send(Message)`、`ack(MessageId)`
- 冪等設計:Broker 多節點共享存儲(DB/分布式 KV)天然冪等
2. 高可用架構
- **共享存儲模式**:多 Broker 掛載同一 DB/NAS,單點故障秒級切換
- **主備分區模式**(Kafka):Partition + ISR(In-Sync Replica),Controller 選主
- Failover 由定時任務補償(重發未 ACK 消息)
3. 消息存儲子系統選型
| 存儲類型 | 性能 | 可靠性 | 適用場景 |
| 內存 | 極高 | 低(掉電丟失) | 日志/監控/允許丟失業務 |
| 分布式 KV (Redis/Mongo/HBase) | 高 | 中 | 一般業務、開發效率優先 |
| 文件系統 (順序寫 + 索引) | 高 | 高 | 核心交易/高吞吐/自研存儲引擎 |
| 關係型數據庫 | 中(受限 IOPS) | 極高 | 支付/交易/強一致性要求 |
4. 消費關系解析(訂閱模型)
- 本質:**組間廣播、組內單播**
- 設計:Consumer Group 共享 Group ID → 單播;不同 Group ID → 廣播
- 元數據存儲:ZooKeeper / Nacos / Consul / etcd
5. 可靠投遞(最終一致性)核心流程
- Producer 本地事務落地消息(DB 表)+ 業務數據同一事務
- 異步發送 → Broker 持久化 → 返回 ACK
- Producer 刪除本地消息表記錄
- 定時掃描未 ACK 消息 → 重發(冪等鍵去重)
- Consumer 處理成功 → 發送 ACK → Broker 標記消費完成
- Consumer 失敗/拒絕 → 重試策略(指數退避/死信隊列)
**核心權衡**:**寧可重複不可丟失** → Consumer 必須冪等(業務主鍵/狀態機/版本號去重)
高級特性深度
事務消息 vs 普通消息
- **事務消息**:本地事務綁定業務+消息落地,適合扣款/下單核心鏈路
- **普通可靠消息**:無本地事務,僅 Broker 持久化保證,適合通知/日志
- **非持久消息**:純內存,極高吞吐,允許丟失,適合監控/指標
重複消息與順序消費解決方案
| 方案 | 原理 | 適用性 |
| 業務主鍵去重 | DB 唯一索引 / Redis SETNX | 冪等寫入場景 |
| 版本號/序列號 | Consumer 維護版本,僅處理 > 當前版本 | 狀態流轉場景(上線/下線) |
| 狀態機校驗 | 定義狀態轉移規則,非法轉移拒絕並要求重發 | 複雜業務流程 |
| 分區有序 | 同一 Key 進同一 Partition,單 Consumer 消費 | 訂單/日志順序需求 |
性能優化:批量 + 異步
- **客戶端半同步半異步**:線程池提交發送任務(不阻塞主線程),任務內同步等待 Broker ACK
- **服務端異步落地**:NIO + 批量刷盤(`mmap`/`sendfile`),合並小包大包寫入
- **批量發送策略**:定時(如 100ms)或定量(如 100 條)觸發 flush,平衡延遲與吞吐
Pull 模型系統設計精髓
- **Consumer 控制節奏**:拉取速率 = 處理能力,無背壓問題
- **Offset 管理**:Consumer 維護消費位點,支持回溯/重消費/精確一次
- **長輪詢優化**:無消息時掛起連接,Broker 有新消息喚醒,減少空輪詢
- **順序消費**:Topic 分區 + 單分區單消費者 = 全局有序(同 Key 有序)
總結:MQ 設計決策清單
- 業務是否需要強一致?→ 是 → RPC;否 → 考慮 MQ
- 選 Push 還是 Pull?→ 實時性敏感/消費快 → Push;消費慢/需回溯/大吞吐 → Pull
- 存儲選型?→ 交易核心 → DB/文件引擎;一般業務 → 分布式 KV;允許丟失 → 內存
- 可靠性等級?→ 事務消息 > 可靠消息 > 普通消息 > 非持久消息
- 重複消息如何兜底?→ 業務冪等設計(主鍵/版本號/狀態機)
- 順序需求?→ 分區 + 單消費者,接受性能代價
沒有完美的 MQ,只有最適合當前業務階段的架構。從簡單開始,隨著規模演進:
單機內存隊列 → 嵌入式 Broker → 叢集化 Broker → 多租戶/多數據中心 → 流處理平台。
來源:美團技術團隊《消息隊列設計精要》