如何维持失效未断开的IBM MQ连接持续存活?
IBM MQ跨版本桥接闲置后连接失效问题排查与解决
问题描述
我们采用adapter=>channel=>adapter模式,通过<int-jms:message-driven-channel-adapter>和<int-jms:outbound-channel-adapter>实现从MQSeries Broker(9+)到MQSeries Broker(6+)的消息传递,连接工厂使用com.ibm.mq.jms.MQConnectionFactory。多数接收端运行正常,但其中一个接收端在闲置一段时间后连接变为无效,新消息到达时发送失败。预期连接工厂会在检测到出站连接断开后自动重连,但实际未检测到断开,复用旧连接导致失败。
报错信息
Caused by: javax.jms.JMSException: MQJMS2007: failed to send message to MQ queue.... Caused by: com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2009'.
环境信息
- MQSeries目标端版本:6
- IBM MQ客户端类版本:9.1.5
- Spring Integration版本:5.5.13
- MQSeries目标端配置:
- HBINT:60
- KAINT:120
- SHARECNV:版本6不支持
原因分析
- 连接缓存未失效:使用
CachingConnectionFactory时,默认不会主动检测缓存的连接是否有效,闲置过久的连接可能已被MQ Broker或中间网络设备(如防火墙)断开,但客户端未感知,复用旧连接导致报错2009(连接已断开)。 - 跨版本保活机制不兼容:MQ 6与MQ 9客户端的心跳/保活机制存在差异,MQ 6的KAINT(Keep-Alive间隔)配置可能未被高版本客户端正确识别,导致客户端未主动发送保活包,连接被闲置断开。
- 网络层无主动断开通知:部分网络设备(如防火墙)在连接闲置超时后会静默断开连接,不发送TCP FIN/RST包,导致客户端无法及时感知连接失效。
解决方案
1. 调整CachingConnectionFactory的连接失效检测
CachingConnectionFactory可以配置关闭生产者缓存,并开启异常后重置连接,确保失效连接被及时丢弃:
<bean id="connectionFactoryCaching2" class="org.springframework.jms.connection.CachingConnectionFactory"> <property name="targetConnectionFactory" ref="jmsConnectionFactory_cred2" /> <property name="sessionCacheSize" value="..." /> <!-- 关闭生产者缓存,避免复用失效连接 --> <property name="cacheProducers" value="false" /> <!-- 异常发生时重置所有缓存的连接 --> <property name="resetConnectionsOnException" value="true" /> </bean>
2. 配置IBM MQ客户端的连接保活
在MQConnectionFactory中启用TCP保活和MQ心跳,与Broker配置保持一致:
<bean id="jmsConnectionFactory2" class="com.ibm.mq.jms.MQConnectionFactory"> <property name="queueManager" value="..." /> <property name="connectionNameList" value="..." /> <property name="channel" value="..." /> <property name="transportType" value="1" /> <!-- 启用TCP层面的保活机制 --> <property name="tcpKeepAlive" value="true" /> <!-- 设置MQ客户端心跳间隔,与Broker的HBINT值匹配 --> <property name="heartbeatInterval" value="60" /> </bean>
注:
tcpKeepAlive依赖操作系统TCP保活配置,需确保系统层面已开启对应功能。
3. 为出站适配器添加重试机制
通过Spring Integration的重试拦截器,在发送失败时自动重试并触发连接重建:
<int-jms:outbound-channel-adapter channel="channelMQ_MQ" id="jmsOut" destination="jmsQueueOut" connection-factory="connectionFactoryCaching2" delivery-persistent="true" explicit-qos-enabled="true" session-transacted="true" > <int-jms:request-handler-advice-chain> <bean class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice"> <property name="retryTemplate"> <bean class="org.springframework.retry.support.RetryTemplate"> <property name="retryPolicy"> <bean class="org.springframework.retry.policy.SimpleRetryPolicy"> <property name="maxAttempts" value="3" /> <!-- 指定需要重试的异常类型 --> <property name="retryableExceptions"> <map> <entry key="com.ibm.mq.MQException" value="true" /> <entry key="javax.jms.JMSException" value="true" /> </map> </property> </bean> </property> <property name="backOffPolicy"> <bean class="org.springframework.retry.backoff.FixedBackOffPolicy"> <property name="backOffPeriod" value="2000" /> </bean> </property> </bean> </property> </bean> </int-jms:request-handler-advice-chain> </int-jms:outbound-channel-adapter>
4. 缩短连接闲置超时(可选)
若消息量不大,可减小缓存会话数,降低闲置连接的存在时长:
<bean id="connectionFactoryCaching2" class="org.springframework.jms.connection.CachingConnectionFactory"> <property name="targetConnectionFactory" ref="jmsConnectionFactory_cred2" /> <property name="sessionCacheSize" value="1" /> <property name="cacheProducers" value="false" /> </bean>
内容的提问来源于stack exchange,提问作者Marvin
相关产品推荐
相关产品推荐

