如何應對 RocketMQ 訊息堆積
來源:https://mp.weixin.qq.com/s/FBBJGsMevCOg22q0psXh9A
這篇文章,我們聊聊如何應對 RocketMQ 訊息堆積。
1 基礎概念
消費者在消費的過程中,消費的速度跟不上服務端的傳送速度,未處理的訊息會越來越多,訊息出現堆積進而會造成訊息消費延遲。
雖然筆者經常講:RocketMQ 、Kafka 具備堆積的能力,但是以下場景需要重點關注訊息堆積和延遲的問題:
業務系統上下游能力不匹配造成的持續堆積,且無法自行恢復。
業務系統對訊息的消費實時性要求較高,即使是短暫的堆積造成的訊息延遲也無法接受。
2 消費原理
客戶端使用 Push 模式
啟動後,消費訊息時,分為以下兩個階段:
階段一:拉取訊息
客戶端透過長輪詢批次拉取的方式從 Broker 服務端獲取訊息,將拉取到的訊息快取到本地緩衝佇列中。
客戶端批次拉取訊息,常見內網環境下都會有很高的吞吐量,例如:1個單執行緒單分割槽的低規格機器(4C8GB)可以達到幾萬 TPS ,如果是多個分割槽可以達到幾十萬 TPS 。所以這一階段一般不會成為訊息堆積的瓶頸。
階段二:消費訊息
提交消費執行緒,客戶端將本地快取的訊息提交到消費執行緒中,使用業務消費邏輯進行處理。
此時客戶端的消費能力就完全依賴於業務邏輯的複雜度(消費耗時)和消費邏輯併發度了。如果業務處理邏輯複雜,處理單條訊息耗時都較長,則整體的訊息吞吐量肯定不會高,此時就會導致客戶端本地緩衝佇列達到上限,停止從服務端拉取訊息。
透過以上客戶端消費原理可以看出,訊息堆積的主要瓶頸在於本地客戶端的消費能力,即消費耗時和消費併發度。
想要避免和解決訊息堆積問題,必須合理的控制消費耗時和訊息併發度,其中消費耗時的優先順序高於消費併發度,必須先保證消費耗時的合理性,再考慮消費併發度問題。
3 消費瓶頸
3.1 消費耗時
影響消費耗時的消費邏輯主要分為 CPU 記憶體計算和外部 I/O 操作,通常情況下程式碼中如果沒有複雜的遞迴和迴圈的話,內部計算耗時相對外部 I/O 操作來說幾乎可以忽略。
外部 I/O 操作通常包括如下業務邏輯:
讀寫外部資料庫,例如 MySQL 資料庫讀寫。 讀寫外部快取等系統,例如 Redis 讀寫。 下游系統呼叫,例如 Dubbo 呼叫或者下游 HTTP 介面呼叫。
這類外部呼叫的邏輯和系統容量需要提前梳理,掌握每個呼叫操作預期的耗時,這樣才能判斷消費邏輯中I/O操作的耗時是否合理。
通常消費堆積都是由於這些下游系統出現了服務異常、容量限制導致的消費耗時增加。
例如:某業務消費邏輯中需要呼叫下游 Dubbo 介面 ,單次消費耗時為 20 ms,平時訊息量小未出現異常。業務側進行大促活動時,下游 Dubbo 服務未進行最佳化,消費單條訊息的耗時增加到 200 ms,業務側可以明顯感受到消費速度大幅下跌。此時,透過提升消費並行度並不能解決問題,需要大幅提高下游 Dubbo 服務效能才行。
3.2 消費併發度
絕大部分訊息消費行為都屬於 IO 密集型,即可能是運算元據庫,或者呼叫 RPC,這類消費行為的消費速度在於後端資料庫或者外系統的吞吐量,透過增加消費並行度,可以提高總的消費吞吐量,但是並行度增加到一定程度,反而會下降。
所以,應用必須要設定合理的並行度。如下有幾種修改消費並行度的方法:
同一個 ConsumerGroup 下,透過增加 Consumer 例項數量來提高並行度(需要注意的是超過訂閱佇列數的 Consumer 例項無效)。可以透過加機器,或者在已有機器啟動多個程式的方式。 提高單個 Consumer 例項的消費並行執行緒,透過修改引數 consumeThreadMin、consumeThreadMax 實現。
4 解決策略
當面對訊息堆積問題時,我們需要明確到底哪個環節出現問題了,不要慌張,也不要貿然動手。
4.1 確認訊息的消費耗時是否合理
首先,我們需要檢視消費耗時,確認訊息的消費耗時是否合理。檢視消費耗時一般來講有兩種方式:
1、列印日誌
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
try {
for (MessageExt messageExt : msgs) {
long start = System.currentTimeMillis();
// TODO 業務邏輯
logger.info("MessageId:" + messageExt.getMsgId() + " costTime:" + (System.currentTimeMillis() - start));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
} catch (Exception e) {
logger.error("consumeMessage error:", e);
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
}
2、檢視訊息軌跡
當確定好消費耗時後,可以根據耗時大小,採取不同的措施。
若檢視到消費耗時較長,則需要檢視客戶端 JVM 堆疊資訊排查具體業務邏輯,並最佳化消費邏輯。 若檢視到消費耗時正常,則有可能是因為消費併發度不夠導致訊息堆積,需要逐步調大消費執行緒或擴容節點來解決。
4.2 檢視客戶端 JVM 的堆疊
假如消費耗時非常高,需要檢視 Consumer 例項 JVM 的堆疊 。
透過
jps -m
或者ps -ef | grep java
命令獲取當前正在執行的 Java 程式,透過啟動主類即可獲得應用的程式 pid ;透過
jstack pid > stack.log
命令獲取執行緒的堆疊。執行以下命令,檢視
ConsumeMessageThread
的資訊 。
cat stack.log | grep ConsumeMessageThread -A 10 --color
常見的異常堆疊資訊如下:
示例1:空閒無堆積的堆疊 。
消費空閒情況下消費執行緒都會處於
WAITING
狀態等待從消費任務隊裡中獲取訊息。
示例2:消費邏輯有搶鎖休眠等待等情況 。
消費執行緒阻塞在內部的一個睡眠等待上,導致消費緩慢。
示例3:消費邏輯運算元據庫等外部儲存卡住 。
消費執行緒阻塞在外部的 HTTP 呼叫上,導致消費緩慢。
5 總結
客戶端使用 Push模式
啟動後,消費訊息時,分為以下兩個階段:拉取訊息和消費訊息。
客戶端消費原理可以看出,訊息堆積的主要瓶頸在於本地客戶端的消費能力,即消費耗時和消費併發度。
首先分析消費耗時,然後根據耗時大小,採取不同的措施。
若檢視到消費耗時較長,則檢視客戶端堆疊資訊排查具體業務邏輯,並最佳化消費邏輯。 若檢視到消費耗時正常,則有可能是因為消費併發度不夠導致訊息堆積,需要逐步調大消費執行緒或擴容節點來解決。
參考文件:
阿里雲官方文件:
https://help.aliyun.com/zh/apsaramq-for-rocketmq/cloud-message-queue-rocketmq-4-x-series/use-cases/message-accumulation-and-latency#concept-2004064
來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70024924/viewspace-3001170/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 關於 RocketMQ ClientID 相同引發的訊息堆積的問題MQclient
- 如何處理RabbitMQ 訊息堆積和訊息丟失問題MQ
- RabbitMQ,RocketMQ,Kafka 訊息模型對比分析MQKafka模型
- 《RabbitMQ》| 解決訊息延遲和堆積問題MQ
- RocketMQ普通訊息MQ
- RocketMQ訊息權重MQ
- [訊息佇列]rocketMQ佇列MQ
- RocketMQ -- 訊息拉取MQ
- Apache RocketMQ中如果一個topic堆積了非常多的訊息會導致rockemq出現什麼問題ApacheMQ
- 訊息中介軟體—RocketMQ訊息傳送MQ
- 解析 RocketMQ 業務訊息——“事務訊息”MQ
- 解析 RocketMQ 業務訊息--“順序訊息”MQ
- RocketMq如何順序消費的訊息offestMQ
- 訊息佇列RocketMQ應對雙十一流量洪峰的“六大武器”佇列MQ
- RocketMQ 訊息整合:多型別業務訊息-普通訊息MQ多型型別
- 訊息佇列之事務訊息,RocketMQ 和 Kafka 是如何做的?佇列MQKafka
- RabbitMQ,RocketMQ,Kafka 幾種訊息佇列的對比MQKafka佇列
- 訊息佇列之 RocketMQ佇列MQ
- RocketMQ(八):訊息傳送MQ
- 聊聊 RocketMQ 訊息軌跡MQ
- 【RocketMQ】MQ訊息傳送MQ
- rocketmq有序訊息的(四)MQ
- 【RocketMQ】訊息拉模式分析MQ模式
- 訊息佇列之RocketMQ佇列MQ
- 【RocketMQ】訊息的拉取MQ
- 【RocketMQ】訊息的儲存MQ
- RocketMQ 常用訊息型別MQ型別
- RocketMQ 訊息整合:多型別業務訊息——定時訊息MQ多型型別
- 【原始碼】RocketMQ如何實現獲取指定訊息原始碼MQ
- RocketMQ訊息丟失解決方案:事務訊息MQ
- RocketMQ定時/延時訊息MQ
- Python使用RocketMQ(訊息佇列)PythonMQ佇列
- RocketMQ 分散式事務訊息MQ分散式
- RocketMQ(九):訊息傳送(續)MQ
- RocketMQ -- 訊息消費過程MQ
- 6-RocketMQ傳送訊息MQ
- 7-RocketMQ拉取訊息MQ
- rocketMq 訊息偏移量 OffsetMQ