服务器连接通道的 mq 连接过多,这些连接不是由队列创建的



根据我们的配置,我们的WAS版本是8.5.5.11,IBM MQ版本是7.5.0.3。我们使用 2 个通道连接到 WMQ,一个将 MAXINST 设置为 250,另一个设置为 500。两者的 SHARECNV 都设置为 10。现在,我们有一个上限,即在队列管理器中最多建立 2000 个连接,但在连续运行 WAS 服务器 3-4 天后,我们最终超过了该限制。 经过一些分析,我们可以看到,在任何时间点,我们只有 120-160 个活动连接。DIS CONN 命令给出了与 OBJNAME、OBJTYPE empty 和 ASTATE "NONE" 的大量连接。即使这些连接也是从我们的 WAS 服务器 IP 建立的,但似乎它们不是由队列创建的,因为 OBJTYPE 不是这些连接的队列。这些连接在一段时间内不断增长,最终达到 2000 个连接的极限。

有人可以帮助确定创建这些连接的原因并确保它们像正常的空闲连接一样关闭。 这就是在应用程序中建立和关闭连接的方式:我们有一个由所有 MDB 扩展的 abstrack bean 类。

@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class TrackBeanV2 extends AbstractServiceBean implements MessageListener {//code}

abstrack bean 按以下方式处理连接的创建和关闭:

public abstract class AbstractServiceBean {
@Resource(name = "myQCF", type = QueueConnectionFactory.class, shareable =     true, description = "Reply Connection Factory")
private ConnectionFactory replyCF; 
@PostConstruct
private void postConstruct() {
replyConnection = replyCF.createConnection();
}  catch (JMSException e) {
throw new RuntimeException("Failed to create JMS Connection");
}
}
@PreDestroy
private void preDestroy() {
try {
replyConnection.close();
} catch (JMSException e) {
throw new RuntimeException("Failed to close JMS connection", e);
}
}
private void sendResponseMessage(String outputMessageText, String  jmsMessageID , Destination replyDestination) {
TextMessage replyMessage = null;
try {           
createSession();    
createProducer();
replyMessage = createReplyMessage(outputMessageText , jmsMessageID);    
sendReply(replyMessage, replyDestination);  
closeProducer();
closeSession();
} catch (JMSException exp) {
handleException(exp);
}
}
private void createSession() throws JMSException{
replySession = replyConnection.createSession(true, 0);                  
}`
private void createProducer() throws JMSException{                              
replyProducer = replySession.createProducer(null);      
}
private void closeSession() throws JMSException {
if (replySession != null) {
replySession.close();
}
}
private void closeProducer() throws JMSException{
if (replyProducer != null) {            
replyProducer.close();          
}
}   
private void sendReply(TextMessage replyMessage, Destination replyDestination) throws JMSException {    
logMessages(replyMessage.getText(), "RESPONSE MESSAGE");
replyProducer.send(replyDestination, replyMessage);
}

以下命令的输出

echo "DIS CONN(*) TYPE(*) CONNAME CHANNEL OBJNAME OBJTYPE" | mqsc -e -m QPDC1GC2 -p width=1000 | grep -o '^w+:|w+[(][^)]+[)]' | awk -F '[()]' -v OFS="," 'function printValues() { if ("CHANNEL" in p) { print p["CHANNEL"], p["CURSHCNV"], p["CONNAME"],p["CHSTADA"],p["CHSTATI"],p["LSTMSGDA"],p["LSTMSGTI"],p["OBJNAME"],p["OBJTYPE"],p["ASTATE"],p["APPLDESC"],p["APPLTAG"] } } /^w+:/ { printValues(); delete p; next } { p[$1] = $2 } END { printValues() }' | grep MYCHANNEL 

看起来像这样

A.QMGR1.MYCHANNEL,,10.217.278.15,,,,,VALIDATE_GET_01,QUEUE,ACTIVE,WebSphere MQ Channel,WebSphere MQ Client for Java
A.QMGR1.MYCHANNEL,,10.217.278.15,,,,,,,NONE,WebSphere MQ Channel,WebSphere MQ Client for Java
A.QMGR1.MYCHANNEL,,10.217.278.15,,,,,,,NONE,WebSphere MQ Channel,WebSphere MQ Client for Java
A.QMGR1.MYCHANNEL,,10.217.278.15,,,,,,,NONE,WebSphere MQ Channel,WebSphere MQ Client for Java
A.QMGR1.MYCHANNEL,,10.217.278.15,,,,,,,NONE,WebSphere MQ Channel,WebSphere MQ Client for Java
A.QMGR1.MYCHANNEL,,10.217.278.15,,,,,,,NONE,WebSphere MQ Channel,WebSphere MQ Client for Java
A.QMGR1.MYCHANNEL,,10.217.278.15,,,,,VALIDATE_GET_01,QUEUE,ACTIVE,WebSphere MQ Channel,WebSphere MQ Client for Java
A.QMGR1.MYCHANNEL,,10.217.278.15,,,,,GETDETAILSGET_01,QUEUE,NONE,WebSphere MQ Channel,WebSphere MQ Client for Java

这是 qm.ini 中的配置。

Channels:
MaxChannels=2000
MaxActiveChannels=2000

注释中提供的命令的输出:

"841DD95801B5DC20","A.QMGR1.MYCHANNEL","10.217.278.15","GETDETAILSGET_01","QUEUE","ACTIVE","WebSphere MQ Channel","WebSphere MQ Client for Java","MQOO_INPUT_SHARED,MQOO_BROWSE,MQOO_INQUIRE,MQOO_SAVE_ALL_CONTEXT,MQOO_FAIL_IF_QUIESCING"
"841DD958AB2CF820","A.QMGR1.MYCHANNEL","10.217.278.15","GETDETAILSGET_01","QUEUE","NONE","WebSphere MQ Channel","WebSphere MQ Client for Java","MQOO_INPUT_SHARED,MQOO_INQUIRE,MQOO_SAVE_ALL_CONTEXT,MQOO_FAIL_IF_QUIESCING,MQOO_NO_READ_AHEAD"

症状表明应用程序连接未正确关闭。 我有 IBM MQ 管理员背景,而不是 Java 开发背景,但根据您到目前为止发布的内容,在我看来,您正在尝试正确关闭连接。 希望具有更多 JMS 开发背景的 IBM MQ 类的人可以看看。 @Roger?


以下脚本将显示特定通道名称的通道实例数。 它还将显示该通道实例之间的共享对话总数、唯一 CONN 的数量以及 CONN 打开的对象总数,包括未打开对象的 CONN。 请注意,当 IBM MQ 客户机进程连接到队列管理器时,将创建到队列管理器的唯一 CONN,如果进程打开对象(如队列管理器、队列或主题),DIS CONN 也会显示这些打开的对象。

这可能有助于观察这些数字随时间的增加,以帮助您了解您遇到的连接/通道泄漏。


示例输出:

./mq-info.ksh MQ.CHANNEL.NAME QMGR.NAME
Total Number of channel instances: 53
Total shared conversations: 94
Unique CONNs: 94
Objects opened by CONNs:
15 ""
45 "QMGR"
120 "QUEUE"

请注意,如果通道配置的 SHARECNV 至少为 1,则Total shared conversationsUnique CONNs的值应始终匹配。

在示例中,共享对话的输出 15 没有打开任何对象。 其余 70 个共享对话的队列管理器本身打开了 45 次,队列对象打开了 120 次。


mq-info.ksh 如下:

#!/bin/ksh
CHL=${1}
QMGR=${2}
echo "Total Number of channel instances: $(echo "DIS CHS(${CHL}) ALL"|runmqsc $QMGR| grep -o '^w+:|w+[(][^)]+[)]' | awk -F '[()]' -v OFS="," 'function printValues() { if ("CHANNEL" in p) { print p["CHANNEL"], p["CURSHCNV"], p["CONNAME"] } } /^w+:/ { printValues(); delete p; next } { p[$1] = $2 } END { printValues() }'|wc -l)"
echo "Total shared conversations: $(expr $(echo $(echo "DIS CHS(${CHL}) ALL"|runmqsc $QMGR| grep -o '^w+:|w+[(][^)]+[)]' | awk -F '[()]' -v OFS="," 'function printValues() { if ("CHANNEL" in p) { print p["CHANNEL"], p["CURSHCNV"], p["CONNAME"] } } /^w+:/ { printValues(); delete p; next } { p[$1] = $2 } END { printValues() }'|awk -F, '{print $2}')|sed -e 's/ / + /g'))"
echo "Unique CONNs: $(echo "dis conn(*) type(all) where(channel eq ${CHL})"|runmqsc $QMGR|grep -o '^w+:|w+[(][^)]+[)]' | awk -F '[()]' -v OFS='","' 'function printValues() { if ("CONN" in p) { print p["CONN"], p["CHANNEL"], p["CONNAME"], p["OBJNAME"], p["OBJTYPE"], p["ASTATE"], p["APPLDESC"], p["APPLTAG"], p["OPENOPTS"] } } /^w+:/ { if (x !~ /YES/) {printValues()}; x = "NO"; delete p; next } { p[$1] = $2 } { if ("OPENOPTS" in p) { printValues() ; delete p["OPENOPTS"]; x = "YES"} } END { if (x !~ /YES/) {printValues()} }'|sed -e 's/^/"/g' -e 's/$/"/g'|awk -F, '{print $1}'|sort -u|wc -l)"
echo "Objects opened by CONNs:"
echo "dis conn(*) type(all) where(channel eq ${CHL})"|runmqsc $QMGR|grep -o '^w+:|w+[(][^)]+[)]' | awk -F '[()]' -v OFS='","' 'function printValues() { if ("CONN" in p) { print p["CONN"], p["CHANNEL"], p["CONNAME"], p["OBJNAME"], p["OBJTYPE"], p["ASTATE"], p["APPLDESC"], p["APPLTAG"], p["OPENOPTS"] } } /^w+:/ { if (x !~ /YES/) {printValues()}; x = "NO"; delete p; next } { p[$1] = $2 } { if ("OPENOPTS" in p) { printValues() ; delete p["OPENOPTS"]; x = "YES"} } END { if (x !~ /YES/) {printValues()} }'|sed -e 's/^/"/g' -e 's/$/"/g'|awk -F, '{print $5}'|sort|uniq -c

最新更新