0%

网络 && JDK虚拟线程 触发RabbitMQ - The channelMax limit is reached

场景

  • 项目JDK版本升级, 从JDK8升至JDK 21,Spring Boot设置为3.3.4
  • JDK和Spring Boot在该版本均支持虚拟线程
  • 业务属于接收数据, 数据清洗, 存储数据库逻辑, 较轻量化
  • 开发机服务, 向SIT环境RabbitMQ发送数据

异常

将原本自定义线程池, 直接替换为 ExecutorService executors = Executors.newVirtualThreadPerTaskExecutor() 后,触发了RabbitMQ的 ChannelMax reached异常

定位问题

  1. 尝试业务RabbitMQ的Config限制使用channel数量

    1
    2
    3
    ConnectionFactory factory = new ConnectionFactory();
    factory.setChannelMax(50); // 限制每个连接的最大通道数
    Connection connection = factory.newConnection();

    测试无效

  2. 由于是测试状态, 直接发送给Queue, 尝试添加fanout交换机, 不等待response
    测试无效

  3. 查看当前每次都是OOM后, 出现该异常

  • Heap Dump检查几乎都是byte[]数据, 定位问题到定时抓取数据业务, 细化方法, 提前提取需要的数据, 将传入值设置为null, 触发尽快GC业务
    解决了OOM的问题, 但仍然会出现该错误
  1. 网络问题
  • 由于是本地电脑网络, 与服务器在其他国家, 中途需要代理,所以经常出现异常
    1
    2
    3
    clean channel shutdown; protocol method: #method<channel.close>(reply-code=406, reply-text=TIMEOUT WAITING FOR ACK, class-id=0, method-id=0)
    Shutdown Signal: clean channel shutdown; protocol method: #method<channel.close>(reply-code=406, reply-text=TIMEOUT WAITING FOR ACK, class-id=0, method-id=0)
    Received a frame on an unknown channel, ignoring it

推测原因

  1. 虚拟线程无限创建线程
  2. 猜测为平台数据频率过高, 且每一个虚拟线程都创建Channel
  3. 网络稳定性问题, 经常出现channel异常

由于接收端频率高, 因此一直发送消息, 但与MQ网络环境不稳定问题, 导致channel经常还未成功销毁时就新建, 并且是虚拟线程, 会无限创建对应数据的新channel

处理

由于MQ是多个服务公用的, 所以不对 channel_max 进行更改

  1. 还原为原本的自定义ClientPoolComponent, 通过复用线程减少channel频繁创建频率
  2. 优化网络环境