【问题标题】:JMS performanceJMS 性能
【发布时间】: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:它们是本地实用工具链的一部分。本质上,他们只是执行空检查并关闭对象,而不是火箭科学。

标签: java jms weblogic message-queue


【解决方案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,以防它们断开连接......
    • 如果连接或会话在某一时刻失败怎么办?我们需要重新创建连接吗?
    猜你喜欢
    • 2011-05-03
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    • 2015-05-12
    • 2023-03-16
    • 2012-02-15
    • 1970-01-01
    • 2014-06-19
    相关资源
    最近更新 更多