全部產品
Search
文件中心

ApsaraMQ for RocketMQ:訊息堆積和延遲問題

更新時間:Jul 01, 2024

本文主要介紹雲訊息佇列 RocketMQ 版TCP協議的Java用戶端使用過程中,經常會出現的訊息堆積和訊息延遲的問題。通過瞭解雲訊息佇列 RocketMQ 版用戶端的消費原理和訊息堆積的主要原因,協助您可以在業務部署前更好的規劃資源和配置,或在營運過程中及時調整商務邏輯,避免因訊息堆積和延遲影響業務運行。

背景資訊

訊息處理流程中,如果用戶端的消費速度跟不上服務端的發送速度,未處理的訊息會越來越多,這部分訊息就被稱為堆積訊息。訊息出現堆積進而會造成訊息消費延遲。以下情境需要重點關注訊息堆積和延遲的問題:
  • 業務系統上下遊能力不匹配造成的持續堆積,且無法自行恢複。
  • 業務系統對訊息的消費即時性要求較高,即使是短暫的堆積造成的訊息延遲也無法接受。

用戶端消費原理

雲訊息佇列 RocketMQ 版TCP協議用戶端的消費流程如下圖所示。消費原理
SDK用戶端使用Push模式消費訊息時,分為以下兩個階段:
  • 階段一:擷取訊息,SDK用戶端通過長輪詢批量拉取的方式從雲訊息佇列 RocketMQ 版服務端擷取訊息,將拉取到的訊息緩衝到本地緩衝隊列中。

    SDK擷取訊息的方式為批量拉取,常見內網環境下都會有很高的輸送量,例如:1個單線程單分區的低規格機器(4C8GB)可以達到幾萬TPS,如果是多個分區可以達到幾十萬TPS。所以這一階段一般不會成為訊息堆積的瓶頸。

  • 階段二:提交消費線程,SDK用戶端將本機快取的訊息提交到消費線程中,使用業務消費邏輯進行處理。

    此時用戶端的消費能力就完全依賴於商務邏輯的複雜度(消費耗時)和消費邏輯並發度了。如果業務處理邏輯複雜,處理單條訊息耗時都較長,則整體的訊息輸送量肯定不會高,此時就會導致用戶端本地緩衝隊列達到上限,停止從服務端拉取訊息。

通過以上用戶端消費原理可以看出,訊息堆積的主要瓶頸在於本地用戶端的消費能力,即消費耗時消費並發度。想要避免和解決訊息堆積問題,必須合理的控制消費耗時和訊息並發度,其中消費耗時的優先順序高於消費並發度,必須先保證消費耗時的合理性,再考慮消費並發度問題。

消費耗時

影響消費耗時的消費邏輯主要分為CPU記憶體計算和外部I/O操作,通常情況下代碼中如果沒有複雜的遞迴和迴圈的話,內部計算耗時相對外部I/O操作來說幾乎可以忽略。外部I/O操作通常包括如下商務邏輯:
  • 讀寫外部資料庫,例如MySQL資料庫讀寫。
  • 讀寫外部緩衝等系統,例如Redis讀寫。
  • 下遊系統調用,例如Dubbo調用或者下遊HTTP介面調用。
這類外部調用的邏輯和系統容量您需要提前梳理,掌握每個叫用作業預期的耗時,這樣才能判斷消費邏輯中I/O操作的耗時是否合理。通常消費堆積都是由於這些下遊系統出現了服務異常、容量限制導致的消費耗時增加。

例如:某業務消費邏輯中需要寫一條資料到資料庫,單次消費耗時為1 ms,平時訊息量小未出現異常。業務側進行大促活動時,寫資料庫TPS爆髮式增長,並很快達到資料庫容量限制,導致消費單條訊息的耗時增加到100 ms,業務側可以明顯感受到消費速度大幅下跌。此時僅通過調整雲訊息佇列 RocketMQ 版SDK的消費並發度並不能解決問題,需要對資料庫容量進行升配才能從根本上提高用戶端消費能力。

消費並發度

雲訊息佇列 RocketMQ 版消費訊息的並發度計算方法如下表所示。
訊息類型消費並發度
普通訊息單節點線程數*節點數量
定時和延時訊息
事務訊息
順序訊息Min(單節點線程數*節點數量,分區數)
用戶端消費並發度由單節點線程數和節點數量共同決定,一般情況下需要優先調整單節點的線程數,若單機硬體資源達到上限,則必須通過擴容節點來提高消費並發度。
說明 順序訊息的消費並發度還受Topic中分區個數的限制,具體分區數,請聯絡阿里雲支援人員根據業務情況進行評估。
單節點的並發度需要謹慎設定,不能盲目直接調大線程數,設定過大的線程數反而會帶來大量的線程切換的開銷。理想環境下單節點的最優線程數計算模型如下:
  • 單機vCPU核心數為C。
  • 線程切換耗時忽略不計,I/O操作不消耗CPU。
  • 線程有足夠訊息等待處理,且記憶體充足。
  • 邏輯中CPU計算耗時為T1,外部I/O操作為T2。
則單個線程能達到的TPS為1/(T1+T2),如果CPU使用率達到理想狀態100%,那麼單機達到最大能力時需要設定C*(T1+T2)/T1個線程。
重要 這裡計算的最大線程數僅僅是在理想環境下得到的理論資料,實際應用環境中建議逐步調大線程數並觀察效果再進行調整。

如何避免訊息堆積和延遲

為了避免在業務使用時出現非預期的訊息堆積和延遲問題,您需要在前期設計階段對整個商務邏輯進行完善的排查和梳理。整理出正常業務運行情境下的效能基準,才能在故障情境下迅速定位到阻塞點。其中最重要的就是梳理訊息的消費耗時和訊息消費的並發度。

  • 梳理訊息的消費耗時
    通過壓測擷取訊息的消費耗時,並對耗時較高的操作的代碼邏輯進行分析。查詢消費耗時,請參見擷取訊息消費耗時。梳理訊息的消費耗時需要關注以下資訊:
    • 訊息消費邏輯的計算複雜度是否過高,代碼是否存在無限迴圈和遞迴等缺陷。
    • 訊息消費邏輯中的I/O操作(如:外部調用、讀寫儲存等)是否是必須的,能否用本機快取等方案規避。
    • 消費邏輯中的複雜耗時的操作是否可以做非同步化處理,如果可以是否會造成邏輯錯亂(消費完成但非同步作業未完成)。
  • 設定訊息的消費並發度
    1. 逐步調大線程的單個節點的線程數,並觀測節點的系統指標,得到單個節點最優的消費線程數和訊息輸送量。
    2. 得到單個節點的最優線程數和訊息輸送量後,根據上下遊鏈路的流量峰值計算出需要設定的節點數,節點數=流量峰值/單線程訊息輸送量。

如何解決訊息堆積和延遲問題

想要快速避免訊息堆積和延遲給業務帶來的影響,您可以通過雲訊息佇列 RocketMQ 版提供的監控警示功能,設定警示規則提前預警訊息堆積問題,或通過業務埋點,觸發警示事件,及時監控到訊息堆積問題並進行處理。設定警示規則,請參見監控警示

說明 配置訊息堆積警示規則時,請根據業務情況合理設定閾值。若閾值設定過小可能會造成頻繁警示;閾值設定過大則不能及時收到警示並處理問題。

若收到訊息堆積警示,處理方法,請參見如何處理訊息堆積