WebSphere MQ 高连接数问题
WebSphere MQ High Connection Count Issue
根据我们的配置,我们的 WAS 版本是 8.5.5.1,IBM MQ 版本是 7.5.0.3。我们使用 2 个通道连接到 WMQ,一个 MAXINST 设置为 250,一个设置为 500。两者的 SHARECNV 都设置为 10。现在我们有在队列管理器中建立最多 1600 个连接的上限,但在 WAS 服务器连续 运行 3-4 天后我们最终超过了该限制。
我想了解 WAS 端的参数如何影响此计数。我们正在使用 Queue Connection Factory 和 Act Spec 来建立连接,我们每个都有 23 个。在这 22 个中,Act Spec 和 QCF 中的设置保持默认设置,例如最大服务器会话 = 10,连接池中的最大连接 = 10,会话池中的最大会话设置为 10。此服务的 tps 非常低,约为 15-20每分钟请求。它们中的所有 22 个都使用相同的通道连接到队列管理器,MAXINST 设置为 250。1 获得相当高的负载,峰值为每秒 80 个请求(每个服务器大约 40 个),其中最大服务器会话 = 40,连接池中的最大连接 = 40,会话池中的最大会话设置为 10.Connection 超时、获取时间、未使用超时和过时超时值均保持默认值。
通过这些设置,在连续 运行 2-3 天后,我们最终在 22 个服务使用的频道上建立了大约 1200 个连接,在另一个频道上建立了大约 500 个连接。这些在一段时间内积累起来。
现在我想调整这些设置,这样我们就不会超过连接计数限制,也不会最终没有可用连接。
所以我有几个问题:
从性能的角度来看,什么是更好的选择 - 减少连接池中的最大连接数或会话池中的最大会话数。前面提到的负载的理想值应该是多少。
连接池和会话池的未使用超时的理想值应该是多少,默认设置为 30 分钟。如果我们将它减少到 5 分钟,它对无法获得连接的性能有什么影响。
是否可以在 WMQ 端进行一些设置,以便关闭 idle/unused 连接,或者这只能在客户端发生。
DISCINT 参数值设置为零,HBINT 设置为 300。理想值应该是多少。
我运行下面命令查看连接
echo "DIS CONN(*) TYPE(*) CONNAME CHANNEL OBJNAME OBJTYPE" | mqsc -e -m QM-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"] } } /^\w+:/ { printValues(); delete p; next } { p[] = } END { printValues() }' | grep MYCHANNEL
MYCHANNEL,,10.215.161.65,,,,,,,NONE
MYCHANNEL,,10.215.161.65,,,,,,,SUSPENDED
MYCHANNEL,,10.215.161.65,,,,,MYQUEUE01,QUEUE,ACTIVE
我可以看到很多处于 None 和挂起状态的连接,它们没有关联任何 OBJNAME 或 OBJTYPE。
我已经尝试在测试中模拟问题,同样的事情发生了,并且随着我们不断满足请求,这些连接不断增加。有人能告诉我为什么要创建这些连接吗?此外,应用程序似乎永远不会使用这些连接。
这是在应用程序中建立和关闭连接的方式:
我们有一个抽象 bean class,它由所有 MDB
扩展
@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);
}
我还没有添加 class 的其他方法 marshalling/unmarshalling 和其他东西。
IBM developerWorks 博客 post “Avoiding run-away numbers of channels” 作者 @MoragHughson 详细介绍了队列管理器上的各种设置,以限制整个队列管理器的总最大通道数 (MaxChannels in qm.ini)、单个通道 (MAXINST) 和连接到通道 (MAXINSTC) 的单个客户端计算机。
@MoragHughson 也有 MQGem 软件博客 post“MaxChannels vs DIS QMSTATUS CONNS”(感谢 Morag 的帮助 posts)详细介绍了连接 (DIS CONN
) 和通道 (DIS CHS
) 之间的区别。
下面是一些可以帮助协调事物的命令(注意我已经在 Linux 上测试了这些命令,如果你在另一个 OS 上 运行 而他们没有工作让我知道,我将尝试为此提供一个工作示例 OS):
下面的命令将显示连接标识符、与连接关联的通道名称(如果有)和 IP 地址(如果有),输出为 CONN,CHANNEL,CONNAME
。
echo "DIS CONN(*) CHANNEL CONNAME"|runmqsc <QMGR> | grep -o '^\w\+:\|\w\+[(][^)]\+[)]' | awk -F '[()]' -v OFS="," 'function printValues() { if ("CONN" in p) { print p["CONN"], p["CHANNEL"], p["CONNAME"] } } /^\w+:/ { printValues(); delete p; next } { p[] = } END { printValues() }'
下面的命令将显示每个 运行 频道实例、共享对话的数量以及连接到频道的 IP 地址,输出为 CHANNEL,CURSHCNV,CONNAME
.
echo "DIS CHS(*) 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[] = } END { printValues() }'
以上两个命令都可以修改为使用您在评论中展示的 mqsc
程序。
在进行更多分析并尝试不同的 WAS 和 MQ 设置后,我们排除了配置和代码方面的任何问题。在研究时发现以下 link http://www-01.ibm.com/support/docview.wss?uid=swg21605479。问题出在用于监控 WAS 服务器的 Wily Introscope 工具,它正在与 MQ 建立连接而不是释放它们。我们从服务器上删除了监控,从那以后它运行良好。在此感谢大家的支持。
我们有一个类似的问题,一旦应用程序保持活动数小时,连接数就会达到其限制。
我们的收获是调用队列管理器的 disconnect() post 入队或出队,而不是 close()。所以确保你的 finally 块看起来像这样。
finally
{
queue.close();
qMgr.disconnect(); //rather than qMgr.close();
}
根据我们的配置,我们的 WAS 版本是 8.5.5.1,IBM MQ 版本是 7.5.0.3。我们使用 2 个通道连接到 WMQ,一个 MAXINST 设置为 250,一个设置为 500。两者的 SHARECNV 都设置为 10。现在我们有在队列管理器中建立最多 1600 个连接的上限,但在 WAS 服务器连续 运行 3-4 天后我们最终超过了该限制。
我想了解 WAS 端的参数如何影响此计数。我们正在使用 Queue Connection Factory 和 Act Spec 来建立连接,我们每个都有 23 个。在这 22 个中,Act Spec 和 QCF 中的设置保持默认设置,例如最大服务器会话 = 10,连接池中的最大连接 = 10,会话池中的最大会话设置为 10。此服务的 tps 非常低,约为 15-20每分钟请求。它们中的所有 22 个都使用相同的通道连接到队列管理器,MAXINST 设置为 250。1 获得相当高的负载,峰值为每秒 80 个请求(每个服务器大约 40 个),其中最大服务器会话 = 40,连接池中的最大连接 = 40,会话池中的最大会话设置为 10.Connection 超时、获取时间、未使用超时和过时超时值均保持默认值。
通过这些设置,在连续 运行 2-3 天后,我们最终在 22 个服务使用的频道上建立了大约 1200 个连接,在另一个频道上建立了大约 500 个连接。这些在一段时间内积累起来。 现在我想调整这些设置,这样我们就不会超过连接计数限制,也不会最终没有可用连接。 所以我有几个问题:
从性能的角度来看,什么是更好的选择 - 减少连接池中的最大连接数或会话池中的最大会话数。前面提到的负载的理想值应该是多少。
连接池和会话池的未使用超时的理想值应该是多少,默认设置为 30 分钟。如果我们将它减少到 5 分钟,它对无法获得连接的性能有什么影响。
是否可以在 WMQ 端进行一些设置,以便关闭 idle/unused 连接,或者这只能在客户端发生。
DISCINT 参数值设置为零,HBINT 设置为 300。理想值应该是多少。
我运行下面命令查看连接
echo "DIS CONN(*) TYPE(*) CONNAME CHANNEL OBJNAME OBJTYPE" | mqsc -e -m QM-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"] } } /^\w+:/ { printValues(); delete p; next } { p[] = } END { printValues() }' | grep MYCHANNEL
MYCHANNEL,,10.215.161.65,,,,,,,NONE
MYCHANNEL,,10.215.161.65,,,,,,,SUSPENDED
MYCHANNEL,,10.215.161.65,,,,,MYQUEUE01,QUEUE,ACTIVE
我可以看到很多处于 None 和挂起状态的连接,它们没有关联任何 OBJNAME 或 OBJTYPE。 我已经尝试在测试中模拟问题,同样的事情发生了,并且随着我们不断满足请求,这些连接不断增加。有人能告诉我为什么要创建这些连接吗?此外,应用程序似乎永远不会使用这些连接。
这是在应用程序中建立和关闭连接的方式: 我们有一个抽象 bean class,它由所有 MDB
扩展@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);
}
我还没有添加 class 的其他方法 marshalling/unmarshalling 和其他东西。
IBM developerWorks 博客 post “Avoiding run-away numbers of channels” 作者 @MoragHughson 详细介绍了队列管理器上的各种设置,以限制整个队列管理器的总最大通道数 (MaxChannels in qm.ini)、单个通道 (MAXINST) 和连接到通道 (MAXINSTC) 的单个客户端计算机。
@MoragHughson 也有 MQGem 软件博客 post“MaxChannels vs DIS QMSTATUS CONNS”(感谢 Morag 的帮助 posts)详细介绍了连接 (DIS CONN
) 和通道 (DIS CHS
) 之间的区别。
下面是一些可以帮助协调事物的命令(注意我已经在 Linux 上测试了这些命令,如果你在另一个 OS 上 运行 而他们没有工作让我知道,我将尝试为此提供一个工作示例 OS):
下面的命令将显示连接标识符、与连接关联的通道名称(如果有)和 IP 地址(如果有),输出为 CONN,CHANNEL,CONNAME
。
echo "DIS CONN(*) CHANNEL CONNAME"|runmqsc <QMGR> | grep -o '^\w\+:\|\w\+[(][^)]\+[)]' | awk -F '[()]' -v OFS="," 'function printValues() { if ("CONN" in p) { print p["CONN"], p["CHANNEL"], p["CONNAME"] } } /^\w+:/ { printValues(); delete p; next } { p[] = } END { printValues() }'
下面的命令将显示每个 运行 频道实例、共享对话的数量以及连接到频道的 IP 地址,输出为 CHANNEL,CURSHCNV,CONNAME
.
echo "DIS CHS(*) 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[] = } END { printValues() }'
以上两个命令都可以修改为使用您在评论中展示的 mqsc
程序。
在进行更多分析并尝试不同的 WAS 和 MQ 设置后,我们排除了配置和代码方面的任何问题。在研究时发现以下 link http://www-01.ibm.com/support/docview.wss?uid=swg21605479。问题出在用于监控 WAS 服务器的 Wily Introscope 工具,它正在与 MQ 建立连接而不是释放它们。我们从服务器上删除了监控,从那以后它运行良好。在此感谢大家的支持。
我们有一个类似的问题,一旦应用程序保持活动数小时,连接数就会达到其限制。
我们的收获是调用队列管理器的 disconnect() post 入队或出队,而不是 close()。所以确保你的 finally 块看起来像这样。
finally
{
queue.close();
qMgr.disconnect(); //rather than qMgr.close();
}