JMS 性能
Posted
技术标签:
【中文标题】JMS 性能【英文标题】:JMS performance 【发布时间】:2011-07-25 03:35:32 【问题描述】:我在从性能角度理解 JMS 时遇到了一些麻烦。我们的应用程序中有这个非常简单的代码:
QueueConnection connection = null;
QueueSession session = null;
QueueSender sender = null;
TextMessage msg = null;
try
// The JNDIHelper uses InitialContext to look up things
QueueConnectionFactory qcf = JNDIHelper.lookupFactory();
Queue destQueue = JNDIHelper.lookupQueue();
// These objects are created for every message, which is quite slow
connection = qcf.createQueueConnection();
session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
sender = session.createSender(destQueue);
// This is the actual message
msg = session.createTextMessage(xmlMsg);
sender.setTimeToLive(0);
sender.send(msg);
finally
// Close all objects again
JMSUtilities.safeClose(sender);
JMSUtilities.safeClose(session);
JMSUtilities.safeClose(connection);
代码是正确的,但可能上述一些人工制品可以重复用于多条消息。这些是我们的配置:
我们使用 Oracle Weblogic 10.3.3 Weblogic 连接到用于 JMS 的 IBM MQ 7.0(6.0 也出现问题) 上述逻辑由后端服务器上的单个线程执行。将一些对象(QueueConnection
、QueueSession
、QueueSender
)保留在内存中会很简单,因为不涉及并发。
我的问题
哪些类型的对象可以在多条消息之间共享? (当然我们会包括错误恢复、恢复那些共享对象) 提高性能的最佳做法是什么?【问题讨论】:
我对您的 finally 块中的 JMSUtilities.safeClose() 方法非常感兴趣。它们是 IBM MQ 7.0 的一部分吗? (我没有使用)或其他什么?通过搜索找不到太多。实现我的第一次发送到 JMS,希望避免一个丑陋的 finally 块与大量的空检查。 @user640118:它们是本地实用工具链的一部分。本质上,他们只是执行空检查并关闭对象,而不是火箭科学。 【参考方案1】:这里是jms spec的一些相关部分:
第 2.8 节多线程
JMS Object Supports Concurrent Use
Destination YES
ConnectionFactory YES
Connection YES
Session NO
MessageProducer NO
MessageConsumer NO
第 4.4.14 节客户端代码的串行执行
JMS 不会导致客户端代码的并发执行,除非客户端明确请求它。这样做的一种方法是定义一个会话序列化所有异步传递的消息
所以如前所述,尽可能多地重用。为所有线程重用 ConnectionFactory、Connection 和 Destinations。为每个线程重用消费者和生产者。
如果您正在重用 JMS 连接,请注意,JMS 提供程序将在该连接上多路复用不同的会话。因此,即使重用连接是安全的,为您需要的每个会话创建一个连接可能会更快。
【讨论】:
【参考方案2】:定义“分享”。
如果您打算在不同的线程之间共享,这是非常危险的。您可以安全地共享 QueueConnectionFactory 对象以及JMS Connection 对象。您不得共享 Session、Sender/Consumer 或 Message 对象。这就是 TIBCO EMS 的工作方式我不确定 IBM 平台,但我想这非常相似。
如果您可以确定您的“发送”方法没有被不同的线程调用,您可以将其封装到带有 Connection、Session 和 Sender 成员变量的 MySender 类中。但要小心!在退出时正确关闭资源。这就是 Heiko Rupp 的建议。是这样的:
class MySender
private QueueConnection connection = null;
private QueueSession session = null;
private QueueSender sender = null;
public MySender(...) /* initialize conn/sess/sender */
public send(String xmlMsg) /* sender.send(session.createTextMessage(xmlMsg)) */
public close() /* close all resources */
关于性能。 JMS 标准没有太大的改进空间。保持消息小并优化服务器设置。仅在需要时使用持久目的地等。阅读您平台的文档。但是在客户端没有太多空间。一些平台为 JMS 提供了额外的功能,允许一些额外的性能提升(批量发送等),但这取决于平台。我不知道 IBM。
【讨论】:
@Izap:查看我关于配置的部分:上述逻辑由后端服务器上的单个线程执行。我不确定您对无法优化客户端的一般假设是否正确。毕竟这些都是Weblogic服务器配合MQ分配和管理的资源…… 说你不应该共享JMS Connection对象是错误的,来自the Connection javadoc... Connections支持并发使用 @Matt,Izap 区分 should not 和 must not,这在Sessions
是单线程对象的方式上是有意义的,但是Connections
不是。我不知道为什么我不应该这样做,但对于 TIBCO 来说不一定是错的,是不是……?
@Matt:JMS 规范确实没有说明线程安全。这取决于实施。但对于 Connections,你是对的。你可以分享它。
@lzap:是的,请参阅多线程规范的第 2.8 节。【参考方案3】:
您需要一次又一次地创建msg
本身 - 如果您要发送到同一个队列。
所以是的,您可以记住连接、会话和发件人。
【讨论】:
是的,队列总是一样的。那么保持会话活动时没有缺点吗?当然,我们会有故障转移逻辑来恢复Connection
、Session
和Sender
,以防它们断开连接......
如果连接或会话在某一时刻失败怎么办?我们需要重新创建连接吗?以上是关于JMS 性能的主要内容,如果未能解决你的问题,请参考以下文章