PAYATHON 2026

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 ConnectionJMS API 层的连接对象,可以创建多个 Sessions
JMS SessionJMS 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
仅创建 Connection1
再创建 5 个 Sessions6
关闭这 5 个 Sessions,保留 Connection1
关闭 Connection0

核对时应比较测试应用带来的变化,不能把 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 连接数量的关系,应先使用不带这些包装的独立程序。

备注:内容仅供参考。