IBM MQ:多个 JMS sessions 下 CONNS 与 CURSHCNV 为何相同?
CONNS 与 CURSHCNV 的值相同,通常是正常现象。CONNS 统计 queue manager 上的 MQ 连接,CURSHCNV 统计某个 SVRCONN 通道实例承载的 conversations。多个 MQ 连接可以共享一个 TCP 连接,因此这两个计数都不能直接当作物理连接数。
在 IBM MQ classes for JMS 的常规客户端模式下,1 个 JMS Connection 加 5 个 JMS Session 通常对应 6 个 conversations。如果它们全部共享同一个 TCP 连接,应在一个通道实例上看到 CURSHCNV(6),以及相应的 MQ 连接数增量,不能据此预期 CONNS(1)。IBM 官方说明
四种对象分别统计什么
| 对象或指标 | 含义 |
|---|---|
JMS Connection | JMS API 层的连接对象,可以创建多个 Sessions |
JMS Session | JMS API 层的消息操作与事务上下文 |
| MQ connection / conversation | 客户端与 queue manager 之间的 MQ 逻辑连接 |
| TCP connection | 操作系统层的网络连接,可以承载多个 conversations |
DISPLAY QMSTATUS CONNS 统计整个 queue manager 的连接,包括客户端连接、本地 bindings 连接,以及某些 MQ 进程建立的连接。因此,即使测试程序只使用一个 TCP 连接,CONNS 也可能明显大于 1。IBM 连接计数说明
CURSHCNV 按 SVRCONN 通道实例分别返回。同一个通道名称可能对应多个正在运行的实例,需要检查完整输出。DISPLAY CHSTATUS 文档
为什么两个场景都可能出现相同的计数
假设某个 SVRCONN 实例的状态为:
CURSHCNV(5)
这表示该实例正在承载 5 个 conversations,它们也对应 queue manager 上的 MQ 连接。即使共享 TCP 连接,CONNS 也不会将它们合并计为 1。
如果整个 queue manager 当时恰好只有这 5 个 MQ 连接,就可能同时出现:
CONNS(5)
CURSHCNV(5)
仅凭这组数值,无法判断是否建立了 5 个 TCP 连接。两个测试场景需要分别核对:
- 在 JMS 场景中,
JMS Connection本身占一个 conversation,每个JMS Session再占一个。如果简单测试直接使用 IBM MQ JMS 客户端,没有容器池化包装,且对象均已建立,1 个 Connection 加 5 个 Sessions 应按 6 个 conversations 核对。若实际只看到 5 个,需要检查完整通道状态,以及对象创建和关闭的时序。两个汇总值不足以解释这一差异。IBM JMS conversation 数量示例 - 在 Java base API 场景中,5 个已连接的
MQQueueManager实例对应 5 个 MQ 逻辑连接,但独立的逻辑连接不一定使用独立的 TCP socket。IBM MQ classes for Java 提供MQEnvironment.sharingConversations等配置来控制多路复用。MQEnvironment 文档
如何核实 conversations 和 TCP 连接数
1. 检查通道定义与实际协商结果
先检查配置:
DISPLAY CHANNEL(SYSTEM.DEF.SVRCONN) CHLTYPE(SVRCONN) SHARECNV
再检查运行中的实例:
DISPLAY CHSTATUS(SYSTEM.DEF.SVRCONN) CURRENT CONNAME STATUS CURSHCNV MAXSHCNV
检查输出中的以下信息:
- 返回的通道实例数量。
- 每个实例的
CURSHCNV值。 - 每个实例的
MAXSHCNV值。
SHARECNV 是配置值,MAXSHCNV 是该实例实际协商出的 conversation 上限。客户端和服务端配置不一致时,通常采用较小值,判断时应以运行状态中的协商结果为准。共享配置说明、MAXSHCNV 定义
下面两种状态仅作示意,并非实际测试结果:
一个通道实例:
CURSHCNV(5) MAXSHCNV(10)
这种状态表示 5 个 conversations 共享该实例对应的 TCP 连接。
五个通道实例,每个实例:
CURSHCNV(1) MAXSHCNV(1)
这种状态表示这些 conversations 分别使用独立的通道实例。连接稳定建立后,对应 5 个 TCP 连接。
2. 列出具体的 MQ 逻辑连接
执行:
DISPLAY CONN(*) TYPE(CONN) ALL WHERE(CHANNEL EQ 'SYSTEM.DEF.SVRCONN')
根据应用名称、客户端地址、用户及可用的进程信息识别测试程序,统计其不同的连接记录。TYPE(CONN) 用于查看连接,避免把对象句柄记录混入计数。DISPLAY CONN 文档
对于启用 conversation sharing 的目标 SVRCONN 通道,应将所有相关实例的 conversations 数相加:
目标通道 conversations 总数 = Σ 每个相关实例的 CURSHCNV
这个总数仍不等于 JMS Sessions 数,因为其中还可能包含 JMS Connection 自身及其他应用建立的 conversations。
3. 从操作系统核实 TCP socket
在稳定运行期间,可以用目标应用已建立的 SVRCONN 实例数核对 TCP 连接数。要直接确认物理连接,还应查看操作系统 socket。
例如,在 Linux 客户端上,假设 MQ listener 使用端口 1414:
ss -tnp state established '( dport = :1414 )'
结合目标 queue manager 的 IP 地址和 Java 进程 PID 筛选。每个唯一的本地地址、本地端口、远端地址、远端端口组合对应一个 TCP 连接。
不要把 LISTEN 或 TIME_WAIT 算入当前已建立的连接。同机测试时,也不要重复计算客户端和服务端两端的 socket 记录。命令中的端口应替换为 listener 实际配置的值。
用最小 JMS 示例逐步观察
以下示例采用 javax.jms API。cf 应是已配置好主机、端口、queue manager、通道及认证信息的 MQConnectionFactory,并使用 client transport。测试时直接使用 IBM MQ 的 factory,便于排除应用服务器连接池的影响。
import javax.jms.Connection;
import javax.jms.Session;
import com.ibm.mq.jms.MQConnectionFactory;
import com.ibm.msg.client.wmq.WMQConstants;
public static void observeConnections(MQConnectionFactory cf)
throws Exception {
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
cf.setShareConvAllowed(
WMQConstants.WMQ_SHARE_CONV_ALLOWED_YES);
Connection connection = cf.createConnection();
try {
System.out.println("已创建 1 个 JMS Connection");
Thread.sleep(60000);
Session[] sessions = new Session[5];
for (int i = 0; i < sessions.length; i++) {
sessions[i] = connection.createSession(
false, Session.AUTO_ACKNOWLEDGE);
}
System.out.println("已创建 5 个 JMS Sessions");
Thread.sleep(60000);
for (Session session : sessions) {
session.close();
}
System.out.println("Sessions 已关闭,Connection 仍保留");
Thread.sleep(60000);
} finally {
connection.close();
}
}
setShareConvAllowed(...) 控制是否允许共享,不能指定每个 socket 的 conversation 数量。MQConnectionFactory API
运行前先记录基线,再在每个暂停阶段重复执行上述 MQSC 命令和 socket 检查。在常规模式、无池化且没有其他活动变化的前提下,应按以下增量核对:
| 阶段 | 应用的 MQ connections / conversations |
|---|---|
| 仅创建 Connection | 1 |
| 再创建 5 个 Sessions | 6 |
| 关闭这 5 个 Sessions,保留 Connection | 1 |
| 关闭 Connection | 0 |
核对时应比较测试应用带来的变化,不能把 queue manager 的绝对 CONNS 值直接当作该应用的连接数。
SHARECNV(10) 下还要注意什么
正确语法是 SHARECNV(10),表示一个通道实例最多承载 10 个 conversations。它不会自动创建 10 个 conversations,也不限制每个 JMS Connection 最多只能创建 10 个 Sessions。
能否共享还取决于客户端是否允许共享,以及连接参数是否兼容:
SHARECNV(1)禁止在同一个 TCP socket 上共享 conversations。SHARECNV(0)使用旧式行为,此时CURSHCNV(0)不能解释为没有应用连接。- JMS 的
SHARECONVALLOWED(NO)会使每个 JMS Connection 和 Session 使用各自的通道实例,即使服务端配置了SHARECNV(10)。共享行为说明、SHARECONVALLOWED 文档
在允许共享、连接参数兼容且同处一个 JVM 的简单场景中,6 个 conversations 可以全部使用同一个 TCP 连接。不过,IBM MQ JMS 会尽力复用连接,允许共享并不保证每次新建对象都会复用已有 socket。共享策略、目标地址、凭据和 TLS 参数都会影响结果,仍需结合通道实例与操作系统 socket 核实。IBM TCP 共享机制说明
验证时,应让被测客户端断开后重新连接,再检查新实例的 MAXSHCNV。如果应用使用连接池或 Session 缓存,调用 close() 后,资源也可能仍由池保留。要验证对象数量与 MQ 连接数量的关系,应先使用不带这些包装的独立程序。
备注:内容仅供参考。
