1. 如何應對消息堆積?

        共 4794字,需瀏覽 10分鐘

         ·

        2024-04-11 13:17

        這篇文章,我們聊聊如何應對 RocketMQ 消息堆積。

        2de6cf9784889839df5f353a7e1c11f1.webp 1 基礎概念

        消費者在消費的過程中,消費的速度跟不上服務端的發(fā)送速度,未處理的消息會越來越多,消息出現(xiàn)堆積進而會造成消息消費延遲。

        雖然筆者經(jīng)常講:RocketMQ 、Kafka 具備堆積的能力,但是以下場景需要重點關注消息堆積和延遲的問題:

        1. 業(yè)務系統(tǒng)上下游能力不匹配造成的持續(xù)堆積,且無法自行恢復。

        2. 業(yè)務系統(tǒng)對消息的消費實時性要求較高,即使是短暫的堆積造成的消息延遲也無法接受。

        2 消費原理 cd7e293224b5b560a5ec9d36e41b036c.webp

        客戶端使用 Push 模式 啟動后,消費消息時,分為以下兩個階段:

        • 階段一:拉取消息

          客戶端通過長輪詢批量拉取的方式從 Broker 服務端獲取消息,將拉取到的消息緩存到本地緩沖隊列中。

          客戶端批量拉取消息,常見內(nèi)網(wǎng)環(huán)境下都會有很高的吞吐量,例如:1個單線程單分區(qū)的低規(guī)格機器(4C8GB)可以達到幾萬 TPS ,如果是多個分區(qū)可以達到幾十萬 TPS 。所以這一階段一般不會成為消息堆積的瓶頸。

        • 階段二:消費消息

          提交消費線程,客戶端將本地緩存的消息提交到消費線程中,使用業(yè)務消費邏輯進行處理。

          此時客戶端的消費能力就完全依賴于業(yè)務邏輯的復雜度(消費耗時)和消費邏輯并發(fā)度了。如果業(yè)務處理邏輯復雜,處理單條消息耗時都較長,則整體的消息吞吐量肯定不會高,此時就會導致客戶端本地緩沖隊列達到上限,停止從服務端拉取消息。

        通過以上客戶端消費原理可以看出,消息堆積的主要瓶頸在于本地客戶端的消費能力,即消費耗時消費并發(fā)度。

        想要避免和解決消息堆積問題,必須合理的控制消費耗時和消息并發(fā)度,其中消費耗時的優(yōu)先級高于消費并發(fā)度,必須先保證消費耗時的合理性,再考慮消費并發(fā)度問題。

        如果想學Java項目的,強烈推薦我的??項目消息推送平臺Austin10K stars),可以用作畢業(yè)設計,可以用作校招,可以看看生產(chǎn)環(huán)境是怎么推送消息的。 

        倉庫地址(可點擊閱讀原文跳轉):https://gitee.com/zhongfucheng/austin

        3 消費瓶頸

        3.1 消費耗時

        影響消費耗時的消費邏輯主要分為 CPU 內(nèi)存計算和外部 I/O 操作,通常情況下代碼中如果沒有復雜的遞歸和循環(huán)的話,內(nèi)部計算耗時相對外部 I/O 操作來說幾乎可以忽略。

        外部 I/O 操作通常包括如下業(yè)務邏輯:

        • 讀寫外部數(shù)據(jù)庫,例如 MySQL 數(shù)據(jù)庫讀寫。
        • 讀寫外部緩存等系統(tǒng),例如 Redis 讀寫。
        • 下游系統(tǒng)調(diào)用,例如 Dubbo 調(diào)用或者下游 HTTP 接口調(diào)用。

        這類外部調(diào)用的邏輯和系統(tǒng)容量需要提前梳理,掌握每個調(diào)用操作預期的耗時,這樣才能判斷消費邏輯中I/O操作的耗時是否合理。

        通常消費堆積都是由于這些下游系統(tǒng)出現(xiàn)了服務異常、容量限制導致的消費耗時增加。

        例如:某業(yè)務消費邏輯中需要調(diào)用下游 Dubbo 接口 ,單次消費耗時為 20 ms,平時消息量小未出現(xiàn)異常。業(yè)務側進行大促活動時,下游 Dubbo 服務未進行優(yōu)化,消費單條消息的耗時增加到 200 ms,業(yè)務側可以明顯感受到消費速度大幅下跌。此時,通過提升消費并行度并不能解決問題,需要大幅提高下游 Dubbo 服務性能才行。

        3.2 消費并發(fā)度

        絕大部分消息消費行為都屬于 IO 密集型,即可能是操作數(shù)據(jù)庫,或者調(diào)用 RPC,這類消費行為的消費速度在于后端數(shù)據(jù)庫或者外系統(tǒng)的吞吐量,通過增加消費并行度,可以提高總的消費吞吐量,但是并行度增加到一定程度,反而會下降。

        所以,應用必須要設置合理的并行度。如下有幾種修改消費并行度的方法:

        • 同一個 ConsumerGroup 下,通過增加 Consumer 實例數(shù)量來提高并行度(需要注意的是超過訂閱隊列數(shù)的 Consumer 實例無效)??梢酝ㄟ^加機器,或者在已有機器啟動多個進程的方式。
        • 提高單個 Consumer 實例的消費并行線程,通過修改參數(shù) consumeThreadMin、consumeThreadMax 實現(xiàn)。
        4 解決策略

        當面對消息堆積問題時,我們需要明確到底哪個環(huán)節(jié)出現(xiàn)問題了,不要慌張,也不要貿(mào)然動手。

        4.1 確認消息的消費耗時是否合理

        首先,我們需要查看消費耗時,確認消息的消費耗時是否合理。查看消費耗時一般來講有兩種方式:

        1、打印日志

              
              public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
             try {
                for (MessageExt messageExt : msgs) {
                   long start = System.currentTimeMillis();
                   // TODO 業(yè)務邏輯
                  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、查看消息軌跡

        f64c9366c5c0391f19efe895fa29ea93.webp

        當確定好消費耗時后,可以根據(jù)耗時大小,采取不同的措施。

        • 若查看到消費耗時較長,則需要查看客戶端 JVM 堆棧信息排查具體業(yè)務邏輯,并優(yōu)化消費邏輯。
        • 若查看到消費耗時正常,則有可能是因為消費并發(fā)度不夠導致消息堆積,需要逐步調(diào)大消費線程或擴容節(jié)點來解決。

        4.2 查看客戶端 JVM 的堆棧

        假如消費耗時非常高,需要查看 Consumer 實例 JVM 的堆棧 。

        1. 通過 jps -m 或者 ps -ef | grep java 命令獲取當前正在運行的 Java 程序,通過啟動主類即可獲得應用的進程 pid ;

        2. 通過 jstack pid > stack.log 命令獲取線程的堆棧。

        3. 執(zhí)行以下命令,查看 ConsumeMessageThread 的信息 。

              
              cat stack.log | grep ConsumeMessageThread -A 10 --color

        常見的異常堆棧信息如下:

        • 示例1:空閑無堆積的堆棧 。

          消費空閑情況下消費線程都會處于 WAITING 狀態(tài)等待從消費任務隊里中獲取消息。

        d3156b0d2e9954f200150698ad48b026.webp
        • 示例2:消費邏輯有搶鎖休眠等待等情況 。

          消費線程阻塞在內(nèi)部的一個睡眠等待上,導致消費緩慢。

        2feaddcdd61c0043c53fae36caed716d.webp
        • 示例3:消費邏輯操作數(shù)據(jù)庫等外部存儲卡住 。

          消費線程阻塞在外部的 HTTP 調(diào)用上,導致消費緩慢。

          7e4eb4b535960b4020b50e8474f81c67.webp
        5 總結

        客戶端使用 Push模式 啟動后,消費消息時,分為以下兩個階段:拉取消息消費消息。

        客戶端消費原理可以看出,消息堆積的主要瓶頸在于本地客戶端的消費能力,即消費耗時消費并發(fā)度

        首先分析消費耗時,然后根據(jù)耗時大小,采取不同的措施。

        • 若查看到消費耗時較長,則查看客戶端堆棧信息排查具體業(yè)務邏輯,并優(yōu)化消費邏輯。
        • 若查看到消費耗時正常,則有可能是因為消費并發(fā)度不夠導致消息堆積,需要逐步調(diào)大消費線程或擴容節(jié)點來解決。

        參考文檔:

        阿里云官方文檔:

        https://help.aliyun.com/zh/apsaramq-for-rocketmq/cloud-message-queue-rocketmq-4-x-series/use-cases/message-accumulation-and-latency#concept-2004064

        Java項目訓練營

        我開通了 項目股東服務 ,已經(jīng)有不少消息推送平臺項目股東拿了阿里/vivo等大廠offer了。 我是沒找到網(wǎng)上有跟我提供相同的服務,價格還比我低的 。

        ??一對一周到的服務: 有很多人的自學能力和基礎確實不太行,不知道怎么開始學習,從哪開始看起,學習項目的過程中會走很多彎路,很容易就迷茫了。付費最跟自學最主要的區(qū)別就是我的服務會更周到。我會告訴你怎么開始學這個開源項目,哪些是重點需要掌握的,如何利用最短的時間把握整個系統(tǒng)架構和編碼的設計,把時間節(jié)省下來去做其他事情。學習經(jīng)驗/路線/簡歷編寫/面試經(jīng)驗知無不言

        ??本地直連遠程服務: 生產(chǎn)環(huán)境的應用系統(tǒng)肯定會依賴各種中間件,我專門買了兩臺服務器已經(jīng)搭建好必要的環(huán)境??,在本地就可以直接啟動運行體驗和學習,無須花額外的時間自行搭建調(diào)試。

        ??細致的文檔&視頻: 巨細致的語雀文檔11W+ 字,共106個文檔,項目視頻還在持續(xù)制作更新中(20個),不怕你學不會。

        ??付費社群 優(yōu)質的社群里需篩選過濾,學習氛圍是很重要的,多跟同輩或前輩聊聊,會少走很多彎路??

        ??清爽干練commit: 專屬股東倉庫,一步一步從零復現(xiàn)austin,每個commit都帶著文檔&視頻學習。

        如果想獲取上面的權益,可以看看?? Java項目訓練營

        瀏覽 47
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 国内一级片 | 欧美一级免费黄片 | 18国产一二三精品国产 | 老色批影院 | 男j操女p |