MQ消息積壓 / Rocketmq 積壓 最全的處理方案。 (秒懂+圖解+史上最全)
本文 的 原文 地址
原始的內容,請參考 本文 的 原文 地址
本文作者:
- 第一作者 老架構師 肖恩(肖恩 是尼恩團隊 高級架構師,負責寫此文的第一稿,初稿 )
- 第二作者 老架構師 尼恩 (45歲老架構師, 負責 提升此文的 技術高度,讓大家有一種 俯視 技術、俯瞰技術、 技術自由 的感覺)
尼恩說在前面:
在40歲老架構師 尼恩的讀者交流群(50+)中,最近有小伙伴拿到了一線互聯網企業如得物、阿里、滴滴、極兔、有贊、shein 希音、shopee、百度、網易的面試資格,遇到很多很重要的面試題:
MQ消息積壓、如何監控、如何排查?
你知道如何解決 MQ消息積壓 嘛?
你們生產環境 這么高的吞吐量,沒有出現過 MQ積壓嗎? 不可能吧? 怎么解決 的?
前幾天 小伙伴面試 美團,遇到了這個問題。但是由于 沒有回答好,導致面試掛了。
小伙伴面試完了之后,來求助尼恩。那么,遇到 這個問題,該如何才能回答得很漂亮,才能 讓面試官刮目相看、口水直流。
所以,尼恩給大家做一下系統化、體系化的梳理,使得大家內力猛增,可以充分展示一下大家雄厚的 “技術肌肉”,讓面試官愛到 “不能自已、口水直流”,然后實現”offer直提”。
尼恩提示:回答問題的時,首先 從一個 現場故事講起。

現場事故:凌晨2點 報警群突然炸了
凌晨2點, 凌晨2:15,監控系統觸發MQ積壓告警,核心業務消息隊列積壓量在15分鐘內從50萬激增至1000萬條,導致訂單支付、物流推送等核心業務鏈路出現嚴重延遲。
報警群突然炸了——各種催命電話, 把我從被窩里 催起來。
我頂著黑眼圈打開MQ 監控一看,發現上游系統異常推送800萬條營銷消息 。
-
直接誘因:夜間批量促銷活動未做流量評估,上游系統異常推送800萬條營銷消息
-
架構缺陷:消費者采用單線程串行消費模式,監控閾值設置過高(500萬才觸發告警)
然后,加班熬夜一通宵 的時間,徹底把問題解決。并且,把我的絕招整理成了下面的方案,提供給其他同學學習使用。
方案分兩個部分:
- 緊急的 止血救命包 (臨時方案)
- 長期的 架構治根 ( 長期方案)
?
緊急止血 + 架構治根 ,一共是5個步驟

第1步: 定位原因:
第2步: 緊急止血包-極速擴容:
臨時擴容Consumer實例和開啟批量消費。
第3步: 棄卒保帥-非核心業務降級:
暫停非關鍵業務的消費者和降低非關鍵業務消費者線程數。
第4步: 并行爆破-上重武器:
消息轉儲 和 消費者更大規模擴容。
第5步:架構治根。 長治久安-上牛逼的架構方案:
高吞吐架構升級和高并發壓的應急預案。
?
第1步:定位原因
-
生產側問題(較少見,10%)
-
Broker側問題(較少見,10%)
-
消費側問題(最可能,80%)

第2步:緊急止血包(臨時消費者擴容)
- 臨時擴容Consumer實例
- 開啟批量消費。

第3步. 棄卒保帥:消費者降級
- 暫停非關鍵業務的消費者
- 降低非關鍵業務消費者線程數。

第4步. 并行爆破:上重武器
? 消息轉儲 和 消費者更大規模擴容。

第5步. 架構治根:架構升級, 長治久安
-
高吞吐架構升級
-
高并發壓的應急預案。

接下來,尼恩給大家說詳細方案:
第1步:定位消息積壓原因
在消息處理流程中,若客戶端的消費速度跟不上服務端的發送速度,未處理的消息會不斷累積,這部分消息就是堆積消息。
消息堆積會直接導致消費延遲,想要高效排查和解決這類問題,首先定位原因。
- 第一步:定位消息積壓原因
定位消息積壓原因
遇到消息積壓時,很多人第一反應是“擴容消費者”,但在操作前必須先明確:到底是什么拖慢了消費速度?
RocketMQ的消費鏈路就像一條流水線,任何環節“堵車”都會引發積壓,我們得先給這條流水線做個全面“檢查”。
MQ消息積壓的核心本質:生產速率>消費速率,導致消息在Broker隊列中堆積。
全鏈路分析如下:

生產側問題(較少見,10%)
- 業務高峰(如秒殺、大促)、補償機制重發、生產端線程池失控等導致的瞬時流量沖擊。
Broker側問題(較少見,10%)
- 磁盤IO瓶頸(PageCache刷盤慢);
- 主從同步延遲;
- 網絡分區或資源限制。
消費側問題(最可能,80%)
(1)性能瓶頸:
- Consumer陷入死循環,導致卡死;
- 業務邏輯復雜(如慢SQL、外部API調用、高耗時計算);
- 單條消息處理時間過長(超過100ms需警惕)。
(2)資源不足:
- 消費者實例數量不足(未隨流量動態擴容);
- 消費者宕機或線程阻塞(如GC停頓、死鎖)。
(3)配置缺陷:
- 順序消費中單條消息卡住會阻塞整個隊列(順序消息會持續重試,普通消息僅重試16次);
- 廣播模式下重復處理導致效率低下。
(4)重試風暴:
- 消息因依賴服務異常等原因頻繁失敗重試。

消息積壓本質是“生產速度>消費速度+Broker轉發能力”。
由于Broker通常是高可用集群,生產側若無人工故障也較穩定,因此排查時應優先考慮消費側問題。
大致的排查步驟如下:
排查Consumer是否處于“假死”狀態
打開RocketMQ Dashboard(運維必備工具),查看Consumer分組的“在線客戶端”列表。若某臺服務器的Consumer長時間未上報心跳(LastHeartbeatTime超過2分鐘),大概率是“消費者假死”。
這種情況多因消費者線程被Full GC卡住或代碼中存在死循環。例如曾遇到某臺服務器因循環中頻繁打印日志導致CPU占用100%,Consumer線程直接卡死,積壓量持續增加。
注意:需為Consumer配置JVM監控,重點關注GC頻率和耗時。比如假死機器的Young GC耗時超500ms,老年代頻繁Full GC,就會直接影響Consumer正常工作。

檢查隊列負載是否均衡
RocketMQ的Consumer采用“隊列均分”策略,每個Consumer分配多個Message Queue(MQ)。若某臺Consumer分配100個MQ,另一臺僅分配10個,會導致“忙閑不均”。
通過Dashboard可查看每個Consumer實例的“已分配隊列數”。比如三臺新擴容服務器因網絡配置問題未連接NameServer,導致老服務器承擔80%隊列,消費能力被壓垮。
實操建議:若隊列分配不均,可先重啟Consumer實例觸發重新負載均衡;若問題持續,檢查Consumer分組配置,確保consumeFromWhere和messageModel設置正確(默認CLUSTERING模式會自動均衡)。
消費端負載均衡策略詳細情況,參考最后一個小節
檢查消費線程是否“效率低下”
RocketMQ Consumer默認消費線程數為20(由consumeThreadMin和consumeThreadMax控制)。若業務邏輯復雜(如涉及數據庫查詢、接口調用),20個線程可能不足,導致大量任務排隊。
比如日志中發現線程池任務堆積量超1000,而實際工作線程僅10個——因為初始化時誤將consumeThreadMin和Max均設為10,無法應對流量激增。
重點:線程數并非越多越好,需結合CPU核心數調整。IO密集型任務可設為CPU核心數的5-10倍(如50);CPU密集型任務超過32通常無意義,反而會因上下文切換降低效率。
節點線程數計算模型:
單節點并發度需合理設置,過大易增加線程切換開銷。理想環境下最優線程數計算模型:
- 單機vCPU核數為C;
- 忽略線程切換耗時,I/O操作不消耗CPU;
- 線程有足夠消息處理,內存充足;
- 邏輯中CPU計算耗時為T1,外部I/O操作為T2。
則單個線程的TPS為1/(T1+T2),若CPU使用率達100%,單機最大線程數為C*(T1+T2)/T1。
第2步:緊急止血包(臨時消費者擴容)
明確原因后進入“急救階段”,需先讓消費速度追上生產速度,再逐步消化歷史積壓。
第一招:臨時擴容Consumer
這是最直接的方法,相當于增加高速公路車道。RocketMQ的Consumer無狀態,理論上可無限擴容,但需注意兩點:
擴容數量不超過MQ總數
每個MQ同一時間僅能被一個Consumer消費。
例如集群有100個MQ,最多可擴容至100個Consumer實例(每個實例分配1個MQ);
若集群有200個MQ且當前僅10個Consumer,理論上可先擴容至50個實例,充分利用隊列資源。
第二招:開啟批量消費,提高單次處理量
RocketMQ支持批量消費,默認每次拉取1條消息(參數consumeMessageBatchMaxSize默認值為1)。
若業務允許,可改為一次拉取10-32條,減少網絡交互,提升吞吐量。
比如將該參數改為16,配合擴容后消費速度從500條/秒提升至8000條/秒——相當于從每次搬1箱貨變為搬16箱,效率顯著提升。但需注意:
保持冪等性
批量處理可能出現重復消費(如處理到第10條時消費者掛了,重啟后16條消息會重新消費),因此業務代碼必須支持冪等(如用唯一ID去重)。比如因未做冪等導致數據庫出現重復訂單,后面還得腳本去重。
避免參數過大
超過32后吞吐量提升不明顯,反而增加內存壓力。曾嘗試設為100,導致Consumer內存使用率超80%,險些觸發OOM,最終確定16-32為最佳范圍。

第3步. 棄卒保帥:消費者降級+ 暫停Producer或限流
消費者降級
- 暫停非關鍵業務的消費者
- 降低非關鍵業務消費者線程數。
暫停Producer或限流,控制消息源頭
若積壓量極大(比如千萬級以上)且消費速度短期內無法追上,可暫時讓Producer停止發消息或降低發送頻率。
注意:暫停Producer前必須與業務方溝通。
例如電商大促期間,暫停支付回調消息會影響商家收款,比如與前端協商在用戶支付成功頁增加“稍后刷新”提示,同時將Producer從2000 TPS限流至500 TPS,為消費者爭取緩沖時間。
注意:
暫停后需監控Consumer的“堆積量”是否下降(理想狀態為每分鐘下降10-20萬條)。
若未變化,可能是消費者重試邏輯導致消息反復投遞(如消息處理失敗后進入重試隊列,積壓量“假死”),此時需檢查maxReconsumeTimes參數(默認16次,超過后進入死信隊列)。
第4步. 并行爆破:上重武器
消息轉儲 和 消費者更大規模擴容。

解決第一步 臨時擴容場景下的 MQ 分區總數不足的解決方案
若前期MQ數量不足(如僅4個MQ且已分配4個Consumer),第一步的臨時擴容Consumer 意義不大,可按以下步驟處理:
1、 臨時轉儲隊列 : 創建原隊列數10倍(或N倍)的新Topic , 也就是 臨時轉儲隊列;
2、 消息轉儲 : 開發臨時轉發程序,將積壓消息均勻分發至新Topic的隊列中;
3、 消費者更大規模擴容: 對應擴容Consumer(10倍),每個Consumer消費一個臨時隊列,同時擴容依賴的業務服務(如緩存、數據庫);
4、消費完成后恢復原有架構,避免資源浪費。

對應擴容Consumer(10倍),每個Consumer消費一個臨時隊列,同時擴容依賴的業務服務(如緩存、數據庫);

實操步驟:
1、 臨時創建新Consumer分組(如加后綴-tmp),避免與原有消費者競爭資源;
2、 啟動時指定--consumerThreadMin 50 --consumerThreadMax 50(臨時調高線程數);
3、 觀察Dashboard的“消費速度”,理想狀態下每臺新服務器分配4-5個MQ,消費速度可提升3-5倍。
第5步. 架構治根:架構升級,徹底 根治
- 高吞吐架構升級
- 積壓 的應急預案。

5.1: 高吞吐架構升級:從 “被動應對” 到 “主動防御”
高吞吐架構的核心目標是:讓生產速率≤消費速率 + Broker 承載能力,從根源上減少積壓風險。需從生產端、消費端、Broker 端三個維度系統性優化,結合業務場景(如秒殺、大促)設計針對性方案。
(1)生產端:控制 “消息源頭” 的速率與質量
生產端是消息的 “起點”,需通過限流、瘦身、異步化等手段,避免瞬時流量沖擊 MQ。
生產端 動態限流:給生產端裝 “剎車”
核心措施:基于 MQ Broker 的 “消息堆積量” 動態調整生產速率。
實現方式:
在 Producer 端集成 “積壓量監測接口”(如調用 RocketMQ Dashboard 的/topic/stats接口),當某 Topic 積壓量超過 50 萬條時,自動觸發限流(通過令牌桶算法將 TPS 從 2000 降至 500)。
業務適配:
秒殺場景下,結合前端限流(如按鈕置灰、排隊提示)和后端限流(Redis 計數器 + Lua 腳本),確保生產速率不超過消費端最大處理能力的 80%(預留 20% 緩沖)。
生產端 消息 “瘦身”:減少無效數據傳輸
核心問題:大消息(>1MB)會導致 Broker 存儲效率下降、消費端處理耗時增加(如解析大 JSON 耗時 100ms+)。
優化措施:
- 消息體只保留 “核心字段”(如訂單 ID、用戶 ID、金額),非核心字段(如用戶地址、商品詳情)通過 “消息 + 數據庫” 組合獲取(消費端拿到消息后,再查 DB 補充信息);
- 大字段壓縮:使用 Protobuf 替代 JSON(壓縮率提升 50%+),或對超過 500KB 的消息進行 GZIP 壓縮;
- 禁止 “日志型消息”:如非必要,不將接口調用日志、調試信息寫入 MQ(改用 ELK 日志系統)。
(2)消費端:提升 “處理效率” 與 “容錯能力”
消費端是消息處理的 “主力”.
消費端 需通過并行化、輕量化、隔離化設計,將單條消息處理耗時壓縮至 50ms 以內(非復雜業務)。
隊列拆分:
按 “業務類型” 或 “用戶 ID 哈希” 拆分 Topic 隊列,避免單隊列阻塞。
示例:原 “訂單消息” Topic(100 個隊列)拆分為 “支付訂單”(50 個隊列)、“取消訂單”(30 個隊列)、“退款訂單”(20 個隊列),分別對應獨立消費者組,避免某類消息(如退款)處理慢阻塞全量;
線程池優化:
核心參數優化:
IO 密集型業務(如調用外部 API、查 DB)→ 線程數 = CPU 核心數 ×5(如 8 核 CPU→40 線程);
CPU 密集型業務(如數據計算)→ 線程數 = CPU 核心數 ×2;
線程池隔離:
使用 Hystrix 或 Resilience4j 為不同消息類型分配獨立線程池(如支付消息用payThreadPool,物流消息用logisticsThreadPool),避免某類消息線程池滿導致全局阻塞。
業務邏輯輕量化:砍掉 “慢操作”
慢 SQL 優化:消費端涉及的 DB 操作必須加索引,禁止select *、復雜 JOIN(耗時>50ms 的 SQL 需拆分或異步化);
外部依賴緩存:調用第三方接口(如支付回調、物流查詢)時,增加本地緩存(Caffeine,過期時間 5 分鐘)+ 分布式緩存(Redis),減少遠程調用耗時(從 200ms→10ms);
異步處理非核心步驟:如訂單消息消費時,“扣減庫存”(核心)同步處理,“發送短信通知”(非核心)丟入本地線程池異步執行(失敗后不影響主流程)。
批量消費 + 冪等設計:提升吞吐量 + 防重復
批量消費參數固化:consumeMessageBatchMaxSize固定為 16-32(經實測,此范圍吞吐量提升最明顯,且內存可控);
冪等實現:
- 消息層面:為每條消息生成唯一 ID(如 UUID),消費端首次處理時寫入 “消息處理表”(ID + 狀態),重復消息直接跳過;
- 業務層面:訂單支付消息通過 “訂單 ID + 支付狀態” 去重(如已支付的訂單,再次收到支付消息時直接返回成功)。
(3)Broker 端:強化 “承載能力” 與 “穩定性”
Broker 是消息存儲與轉發的核心,需通過硬件升級、集群擴容、參數優化提升極限承載能力(目標:單 Broker 支持 10 萬 TPS+,集群支持百萬 TPS+)。
硬件與存儲優化
- 磁盤:使用 SSD(隨機讀寫速度是機械硬盤的 10 倍 +),且單 Broker 磁盤容量≥1TB(避免頻繁清理舊消息);
- 內存:為 Broker 配置足夠大的 PageCache(如 16 核 32G 機器,分配 16G 作為 PageCache),減少磁盤 IO 壓力(消息先寫入 PageCache,再異步刷盤);
- 網絡:Broker 節點間使用萬兆網卡,避免跨機房部署(主從節點同機房,延遲控制在 1ms 內)。
集群擴容與負載均衡
- 集群規模:按 “生產 TPS×2” 配置 Broker 節點(如預估生產端 50 萬 TPS,集群部署 10 個 Broker 節點,單節點承載 5 萬 TPS);
- 隊列均衡:每個 Topic 的隊列數 = Broker 節點數 ×8(如 10 個 Broker→80 個隊列),確保隊列均勻分布在各 Broker(避免某臺 Broker 負載過高);
- 主從架構:每個 Broker 配置 1 個從節點,主節點故障時自動切換(RocketMQ 支持主從自動切換,切換時間<30 秒)。
刷盤與清理策略優化
- 刷盤策略:高吞吐場景用
ASYNC_FLUSH(異步刷盤,寫入 PageCache 即返回成功,由后臺線程定時刷盤),犧牲部分一致性換性能; - 消息清理:設置合理的
fileReservedTime(消息保留時間),非核心消息保留 24 小時,核心消息保留 7 天(避免舊消息占用磁盤空間)。
5.2 : 應急預案:從 “無序應對” 到 積壓的 “標準化處理流程”
由于平臺 篇幅限制, 此處省略1000字+
剩下的內容,請參加原文地址原始的內容,請參考 本文 的 原文 地址
浙公網安備 33010602011771號