You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ActiveMQ 5.15.3线程池线程阻塞求助:阻塞于ensureConnectionInfoSent()及createSession

解决ActiveMQ 5.15.3线程阻塞在ensureConnected的问题

看起来你遇到了ActiveMQ客户端线程大面积阻塞的棘手问题,我之前也处理过类似的情况,结合你给出的线程栈信息——大量messagePool线程卡在org.apache.activemq.ActiveMQConnection.ensureConnected(),咱们一步步拆解可能的原因和解决思路:

先搞懂为什么会阻塞在ensureConnected

ensureConnected()是ActiveMQ客户端用来确保和broker的连接处于可用状态的核心方法,调用createSession()时必然会触发这个检查。线程卡在这里,本质上是客户端在尝试建立/恢复连接时,要么拿不到内部锁,要么broker端迟迟不给响应。

可能的原因及对应的排查方案

1. 连接池配置和线程池不匹配

你用了PooledConnectionFactory,如果连接池的配置和业务线程池的规模不搭,很容易导致连接争抢:

  • 连接池最大连接数太小:如果你的ThreadPoolExecutor线程数远大于PooledConnectionFactory的maxConnections,大量线程会排队等连接,进而阻塞在连接池的锁或者连接建立逻辑上。
    • 先核对配置:看看maxConnections是不是远小于线程池的核心/最大线程数,比如线程池开了30个线程,连接池却只给了10个连接,那肯定不够用。
    • 调整参数:把setMaxConnections()的值调到和线程池规模匹配,同时设置合理的idleTimeout,让闲置连接自动回收,避免资源浪费。
  • 连接池内部锁竞争:PooledConnectionFactory的连接复用逻辑是加锁的,如果大量线程同时抢连接,锁等待会非常明显。
    • 可以试试开启useExclusiveConnections(如果业务允许),让每个线程独占一个连接,减少锁竞争,但这会增加总连接数,得配合broker端的连接数限制一起调。

2. ActiveMQ Broker端扛不住了

如果broker本身出问题,客户端会一直重试连接,自然会卡在ensureConnected:

  • 连接数超限:ActiveMQ默认最大连接数是1000(通过transportConnector的maxConnections配置),如果客户端连接数超过这个数,broker会拒绝新连接,客户端就会一直重试,导致阻塞。
    • 先查broker日志,搜搜有没有Too many connections的错误,或者登录管理控制台(默认http://localhost:8161/admin)看当前连接数。
    • 要么调大broker的maxConnections,要么优化客户端连接池减少连接数。
  • broker线程池耗尽:broker有自己的线程池处理客户端请求,如果线程池满了,客户端的连接请求会被挂起。
    • 看broker日志里有没有线程相关的警告,或者用JMX查看org.apache.activemq:type=Broker,brokerName=localhost,connector=clientConnectors,connectorName=openwire下的线程指标。
  • 网络波动:客户端和broker之间网络不稳定,连接频繁断连重连,ensureConnected一直在尝试重建连接却失败。
    • 先测测网络连通性,比如ping、telnet看看有没有丢包或者延迟过高的情况。
    • 可以在客户端加个配置wireFormat.maxInactivityDurationInitalDelay,延长初始连接超时时间,避免过早触发重连逻辑。

3. 客户端代码有资源泄漏或线程不安全问题

虽然PooledConnectionFactory是线程安全的,但代码写得不对也会出问题:

  • 没正确释放Session/Connection:如果线程拿了连接后,没在finally块里关闭Session、归还Connection(PooledConnectionFactory会自动回收连接,但Session必须手动关),会导致连接池里的连接被占死,其他线程拿不到连接就会阻塞。
    • 检查代码,确保每次发完消息都在finally里关闭资源,比如这样:
      Connection connection = null;
      Session session = null;
      MessageProducer producer = null;
      try {
          connection = pooledConnectionFactory.createConnection();
          connection.start();
          session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
          Destination queue = session.createQueue("your-queue");
          producer = session.createProducer(queue);
          // 发送消息逻辑
          TextMessage msg = session.createTextMessage("test message");
          producer.send(msg);
      } catch (JMSException e) {
          // 异常处理
      } finally {
          // 倒序关闭资源
          if (producer != null) try { producer.close(); } catch (Exception ignored) {}
          if (session != null) try { session.close(); } catch (Exception ignored) {}
          if (connection != null) try { connection.close(); } catch (Exception ignored) {}
      }
      
  • 跨线程复用Session/Connection:如果多个线程共享同一个Session甚至Connection,会导致线程争抢Session的内部锁,进而卡在createSession或者其他操作上。
    • 一定要保证每个线程独立获取Connection和Session,Session绝对不能跨线程用。

4. ActiveMQ 5.15.3的版本bug

5.15.3是比较老的版本了,可能存在一些连接池相关的已知bug:

  • 比如某些场景下,连接池里的连接会变成无效状态,但没被及时回收,导致线程一直等无效连接。
    • 能升级的话,尽量升到5.16.x或者更高的稳定版,很多老bug都被修复了。
    • 暂时不能升级的话,把PooledConnectionFactory的testOnBorrow设为true,每次拿连接时检查有效性,无效就重新创建。

快速排查优先级

  1. 先看broker日志,有没有连接数超限、线程池满这类明确的错误;
  2. 核对客户端连接池和线程池的配置,看看是不是连接数不够;
  3. 检查代码里的资源释放逻辑,有没有泄漏;
  4. 用Jstack/VisualVM看线程栈,确认是不是所有阻塞线程都在等同一个锁对象。

内容的提问来源于stack exchange,提问作者Sabya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:29:15