记一次RocketMQ Netty通信频繁出现 IDLE exception问题排查及修复

这里是小奏 ,觉得文章不错可以关注公众号小奏技术

RocketMQ version

  • 5.1.0

背景

  1. 线上RocketMQ偶尔出现从Nameserve获取元数据TimeOut
java 复制代码
TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());

之前排查过一次,可以参考线上RocketMQ偶发sendDefaultImpl call timeout问题排查及优化方向总结:mp.weixin.qq.com/s/bPxq-knvO...

  1. 查看Nameserve发现打印大量NETTY CLIENT PIPELINE: IDLE exceptionlog

初步解决方案

最开想的是既然超时了,那就直接增加超时时间,优先让程序正常运行。

client增加如下配置

java 复制代码
producer.setSendMsgTimeout(8000);

实际早起出现过类似的问题,超时时间由默认3s调整为5s了。现在暂时调整为8s看能不能解决这个问题

实际结果是增加了超时时间还是会出现TimeOut问题

由于之前分析过出现sendDefaultImpl call timeout 是还没发送消息就超时了,所以这里重点关注Nameserve

问题排查

通过阅读源码发现几个问题

  1. client会定时去扫描所有Nameserve并与所有Nameserve建立连接
java 复制代码
            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
  • server

Netty心跳检测机不熟悉的朋友可以参考我之前的文章 Netty心跳检测机制实战(附源码):mp.weixin.qq.com/s/-luniYo8v...

  1. nameserver只会定时30s从单个Nameserve获取元数据,这个操作也就是充当了clientNameserve的心跳机制
java 复制代码
        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,然后触发频繁的断线重连

如何修复

定位到问题之后就很好修复了。

实际我们client并不需要与所有nameserver建立连接,仅与单个nameserver建立连接即可。

如果单个nameserver挂了,client会自动切换到其他nameserver

相关代码

所以修复方式很简单,我们不让client与所有nameserver建立连接,仅与单个nameserver建立连接即可

相关修复pr: github.com/apache/rock...

相关推荐
加油,旭杏3 分钟前
【go语言】grpc 快速入门
开发语言·后端·golang
brzhang23 分钟前
墙裂推荐一个在 Apple Silicon 上创建和管理虚拟机的轻量级开源工具:lume
前端·后端
沈韶珺2 小时前
Visual Basic语言的云计算
开发语言·后端·golang
沈韶珺2 小时前
Perl语言的函数实现
开发语言·后端·golang
美味小鱼2 小时前
Rust 所有权特性详解
开发语言·后端·rust
我的K84092 小时前
Spring Boot基本项目结构
java·spring boot·后端
慕璃嫣3 小时前
Haskell语言的多线程编程
开发语言·后端·golang
晴空๓3 小时前
Spring Boot项目如何使用MyBatis实现分页查询
spring boot·后端·mybatis
Hello.Reader7 小时前
深入浅出 Rust 的强大 match 表达式
开发语言·后端·rust