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 也出现问题) 上述逻辑由后端服务器上的单个线程执行。将一些对象(QueueConnectionQueueSessionQueueSender)保留在内存中会很简单,因为不涉及并发。

我的问题

哪些类型的对象可以在多条消息之间共享? (当然我们会包括错误恢复、恢复那些共享对象) 提高性能的最佳做法是什么?

【问题讨论】:

我对您的 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 notmust not,这在 Sessions 是单线程对象的方式上是有意义的,但是Connections 不是。我不知道为什么我不应该这样做,但对于 TIBCO 来说不一定是错的,是不是……? @Matt:JMS 规范确实没有说明线程安全。这取决于实施。但对于 Connections,你是对的。你可以分享它。 @lzap:是的,请参阅多线程规范的第 2.8 节。【参考方案3】:

您需要一次又一次地创建msg 本身 - 如果您要发送到同一个队列。

所以是的,您可以记住连接、会话和发件人。

【讨论】:

是的,队列总是一样的。那么保持会话活动时没有缺点吗?当然,我们会有故障转移逻辑来恢复ConnectionSessionSender,以防它们断开连接...... 如果连接或会话在某一时刻失败怎么办?我们需要重新创建连接吗?

以上是关于JMS 性能的主要内容,如果未能解决你的问题,请参考以下文章

使用 Jms 发送对象 - HornetQ(性能问题)[关闭]

JMeter4.0学习JMeter对JMS性能测试脚本开发

JMS 动态消息选择

Camel ActiveMQ 性能调优

负载,性能测试工具-Gatling

使用线程池的 JMS 侦听器