切換語言為:簡體
記一次RocketMQ Netty通訊頻繁出現 IDLE exception問題排查及修復

記一次RocketMQ Netty通訊頻繁出現 IDLE exception問題排查及修復

  • 爱糖宝
  • 2024-07-08
  • 2060
  • 0
  • 0

RocketMQ version

  • 5.1.0

背景

  1. 線上RocketMQ偶爾出現從Nameserve獲取後設資料TimeOut

TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
  1. 檢視Nameserve發現列印大量NETTY CLIENT PIPELINE: IDLE exceptionlog

記一次RocketMQ Netty通訊頻繁出現 IDLE exception問題排查及修復

初步解決方案

最開想的是既然超時了,那就直接增加超時時間,優先讓程式正常執行。

client增加如下配置

producer.setSendMsgTimeout(8000);

實際早起出現過類似的問題,超時時間由預設3s調整為5s了。現在暫時調整為8s看能不能解決這個問題

實際結果是增加了超時時間還是會出現TimeOut問題

由於之前分析過出現sendDefaultImpl call timeout 是還沒傳送訊息就超時了,所以這裏重點關注Nameserve

問題排查

透過閱讀原始碼發現幾個問題

  1. client會定時去掃描所有Nameserve並與所有Nameserve建立連線

            int connectTimeoutMillis = this.nettyClientConfig.getConnectTimeoutMillis();
            TimerTask timerTaskScanAvailableNameSrv = new TimerTask() {
                @Override
                public void run(Timeout timeout) {
                    try {
                        NettyRemotingClient.this.scanAvailableNameSrv();
                    } catch (Exception e) {
                        LOGGER.error("scanAvailableNameSrv exception", e);
                    } finally {
                        timer.newTimeout(this, connectTimeoutMillis, TimeUnit.MILLISECONDS);
                    }
                }
            };
            this.timer.newTimeout(timerTaskScanAvailableNameSrv, 0, TimeUnit.MILLISECONDS);

  1. 但是client並不會主動給Nameserve傳送心跳

  2. netty通訊模組clientserver都配置了空閒檢測

  • client

記一次RocketMQ Netty通訊頻繁出現 IDLE exception問題排查及修復

  • server

記一次RocketMQ Netty通訊頻繁出現 IDLE exception問題排查及修復

  1. nameserver只會定時30s從單個Nameserve獲取後設資料,這個操作也就是充當了clientNameserve的心跳機制

        this.scheduledExecutorService.scheduleAtFixedRate(() -> {
            try {
                MQClientInstance.this.updateTopicRouteInfoFromNameServer();
            } catch (Exception e) {
                log.error("ScheduledTask updateTopicRouteInfoFromNameServer exception", e);
            }
        }, 10, this.clientConfig.getPollNameServerInterval(), TimeUnit.MILLISECONDS);

問題定位

經過上面的原始碼分析就很清晰了。我們這裏舉例說明

現在比如有三個服務orderproducerpay

nameserver有三個節點Nameserve-aNameserve-bNameserve-c

  • order 連線 Nameserve-a ,與 Nameserve-bNameserve-c 頻繁觸發NETTY CLIENT PIPELINE: IDLE exception。, Nameserve-bNameserve-c為此產生大量 NETTY CLIENT PIPELINE: IDLE exception,然後觸發頻繁的斷線重連

  • producer 連線 Nameserve-b ,與 Nameserve-aNameserve-c 頻繁觸發NETTY CLIENT PIPELINE: IDLE exception。, Nameserve-aNameserve-c為此產生大量 NETTY CLIENT PIPELINE: IDLE exception,然後觸發頻繁的斷線重連

  • pay 連線 Nameserve-c ,與 Nameserve-aNameserve-b 頻繁觸發NETTY CLIENT PIPELINE: IDLE exception。, Nameserve-aNameserve-b為此產生大量 NETTY CLIENT PIPELINE: IDLE exception,然後觸發頻繁的斷線重連

記一次RocketMQ Netty通訊頻繁出現 IDLE exception問題排查及修復

如何修復

定位到問題之後就很好修復了。

實際我們client並不需要與所有nameserver建立連線,僅與單個nameserver建立連線即可。

如果單個nameserver掛了,client會自動切換到其他nameserver

相關程式碼

記一次RocketMQ Netty通訊頻繁出現 IDLE exception問題排查及修復

所以修復方式很簡單,我們不讓client與所有nameserver建立連線,僅與單個nameserver建立連線即可


0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.