Spring Boot微服务与ActiveMQ Classic重连异常问题排查
问题描述
我正在开发基于Spring Boot的微服务后端应用,使用ActiveMQ Classic实现服务间通信。生产环境中,因维护重启ActiveMQ Classic的Kubernetes实例后,其他微服务均重新连接成功,唯独一个服务持续重试却无法重连。
本地环境经过160多次重试后,仅复现一次该问题,能获取的微服务日志如下:
Could not refresh JMS Connection for destination '<queueName>' - retrying using FixedBackOff{interval=5000, currentAttempts=128, maxAttempts=unlimited}. Cause: The JMS connection has failed: java.io.EOFException
该错误出现概率极低,但确实存在。配置方面无异常,服务会每5秒无限重试(正常情况可立即重连成功),在Amazon MQ中未找到相关配置参数。
我猜测可能是两个微服务同时重连时,其中一个覆盖了另一个的连接,这种情况是否可能?还有其他可能性吗?
完整堆栈日志:
jakarta.jms.JMSException: java.io.EOFException at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:67) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.ActiveMQConnection.onAsyncException(ActiveMQConnection.java:2033) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.ActiveMQConnection.onException(ActiveMQConnection.java:2052) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:114) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.ResponseCorrelator.onException(ResponseCorrelator.java:126) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:114) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:114) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.WireFormatNegotiator.onException(WireFormatNegotiator.java:173) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.AbstractInactivityMonitor.onException(AbstractInactivityMonitor.java:346) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.TransportSupport.onException(TransportSupport.java:96) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:219) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na] Caused by: java.io.EOFException: null at java.base/java.io.DataInputStream.readInt(DataInputStream.java:398) ~[na:na] at org.apache.activemq.openwire.OpenWireFormat.unmarshal(OpenWireFormat.java:280) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.java:240) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:232) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:215) ~[activemq-client-jakarta-5.18.3.jar:5.18.3] ... 1 common frames omitted
问题分析与解答
首先,你猜测的“两个微服务同时重连时互相覆盖连接”不可能发生。ActiveMQ的每个客户端连接都是独立的TCP连接,服务端会为每个连接分配唯一的会话标识,不存在互相覆盖的情况。
以下是几种可能的原因:
- TCP连接半开状态:ActiveMQ重启后,客户端旧的TCP连接可能处于半开状态(服务器端已经关闭连接,但客户端未感知)。当客户端尝试用这个旧连接发送请求时,会触发EOFException。如果重试逻辑没有正确关闭旧连接并创建新连接,就会持续失败。
- WireFormat协商异常:堆栈日志显示错误发生在
OpenWireFormat.unmarshal阶段,说明客户端和服务器端在协商通信格式时出现问题。可能是ActiveMQ重启后,服务器端的WireFormat配置临时异常,或者客户端在重连时没有重新发起完整的协商流程。 - Kubernetes网络波动:Kubernetes环境中,服务重启后的网络策略、负载均衡转发可能存在短暂异常。比如该服务的Pod被调度到网络延迟较高的节点,或者Service的端点更新不及时,导致TCP连接建立后立即被中断。
- 客户端连接池问题:如果该服务使用了JMS连接池,重启ActiveMQ后,连接池中的旧连接没有被正确回收,重试时一直在复用无效连接。检查连接池配置,是否开启了连接有效性校验(比如
testOnBorrow)。 - ActiveMQ连接数限制:虽然其他服务都连上了,但该服务可能在重连时触发了ActiveMQ的连接数阈值(比如
maxConnections),导致服务器拒绝新连接。不过这种情况通常会返回明确的拒绝错误,而非EOFException,但仍值得排查。
建议的排查方向:
- 在该服务的重连逻辑中,确保每次重试都关闭旧连接并创建全新连接,不要复用之前的连接实例。
- 开启ActiveMQ客户端的详细日志,查看重连时的WireFormat协商过程,确认是否有异常。
- 检查Kubernetes中该服务Pod的网络状态,重启该服务Pod后观察是否能恢复连接——如果能恢复,大概率是本地连接资源未释放导致的。
- 配置连接池的连接校验参数,比如在Spring Boot中设置
spring.activemq.pool.test-on-borrow=true,确保每次获取连接时都验证有效性。
内容的提问来源于stack exchange,提问作者Ferran Veciana Buixeda
相关产品推荐
相关产品推荐

