JMS (ActiveMQ) 性能

发布于 2024-09-30 00:20:21 字数 2784 浏览 0 评论 0原文

我有一个 Java 应用程序,其中有许多通过 JMS (ActiveMQ) 进行通信的组件。目前,应用程序和 JMS Hub 位于同一服务器上,尽管我们最终计划拆分组件以实现可扩展性。我们在性能方面存在重大问题,最值得注意的是,所有这些问题似乎都与 JMS 相关,而这个问题的焦点是向主题发布消息所花费的时间。

我们有大约 50 个动态创建的主题,用于应用程序组件之间的通信。一个组件从表中读取记录并一次处理一条记录,该处理涉及创建一条 JMS 对象消息并将其发布到其中一个主题。此处理无法跟上将记录写入源表的速率~23/秒,因此我们更改了处理以创建 JMS 对象消息并将其添加到队列中。创建了一个新线程,该线程从此队列中读取并将消息发布到适当的主题。显然,这不会加快处理速度,但它确实使我们能够通过查看队列的大小来了解我们落后了多远。

在一天开始时,没有消息通过整个系统,这会迅速从第一个小时内通过集线器的 1560000 条(433 条/秒)消息增加到第三个小时内的 2100000 条(582 条/秒)消息,然后保持不变在那个级别。在第一个小时开始时,从数据库表中读取记录的组件发布的消息保持不变,但是到该小时结束时,队列中有 2000 条消息等待发送,到了第 3 小时,队列中有 9000 条消息其中的消息。

以下是发送 JMS 消息的代码的相应部分。非常感谢任何有关我们做错了什么或如何提高性能的建议。查看网络上的统计数据,JMS 应该能够轻松处理每秒约 1000-2000 条大消息或每秒约 10000 条小消息。我们的每条消息大约有 500 字节,所以我想它位于该规模的中间位置。

获取发布者的代码:

private JmsSessionPublisher getJmsSessionPublisher(String topicName) throws JMSException {
    if (!this.topicPublishers.containsKey(topicName)) {
        TopicSession pubSession = (ActiveMQTopicSession) topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

        ActiveMQTopic topic = getTopic(topicName, pubSession);

        // Create a JMS publisher and subscriber
        TopicPublisher publisher = pubSession.createPublisher(topic);

        this.topicPublishers.put(topicName, new JmsSessionPublisher(pubSession, publisher));
    }
    return this.topicPublishers.get(topicName);
}

发送消息:

JmsSessionPublisher jmsSessionPublisher = getJmsSessionPublisher(topicName);
    
ObjectMessage objMessage = jmsSessionPublisher.getSession().createObjectMessage(messageObj);
objMessage.setJMSCorrelationID(correlationID);
objMessage.setJMSTimestamp(System.currentTimeMillis());
jmsSessionPublisher.getPublisher().publish(objMessage, false, 4, 0);

将消息添加到队列的代码:

List<EventQueue> events = eventQueueDao.getNonProcessedEvents();
for (EventQueue eventRow : events) {
    IEvent event = eventRow.getEvent();
    AbstractEventFactory.EventType eventType = AbstractEventFactory.EventType.valueOf(event.getEventType());
    String topic = event.getTopicName() + topicSuffix;
    EventMsgPayload eventMsg = AbstractEventFactory.getFactory(eventType).getEventMsgPayload(event);
    synchronized (queue) {
        queue.add(new QueueElement(eventRow.getEventId(), topic, eventMsg));
        queue.notify();
    }
}

线程中从队列中删除项目的代码:

jmsSessionFactory.publishMessageToTopic(e.getTopic(), e.getEventMsg(), Integer.toString(e.getEventMsg().hashCode()));

publishMessageToTopic 执行上面的“发送消息”代码。

如果一致认为 ActiveMQ 可能不是最佳选择,那么其他 JMS 实现也是一个选择。

I have a Java application with a number of components communicating via JMS (ActiveMQ). Currently, the application and the JMS Hub are on the same server, although we eventually plan to split out the components for scalability. We have significant issues with performance, all seemingly around JMS, most notably, and the focus of this question, is the amount of time it is taking to publish a message to a topic.

We have around 50 dynamically created topics used for communication between the components of the application. One component reads records from a table and processes them one at a time, the processing involves creating a JMS object message and publishing it to one of the topics. This processing could not keep up with the rate at which records were being written to the source table ~23/sec, so we changed the processing to create the JMS object message and add it to a queue. A new thread was created which reads from this queue and published the message to the appropriate topic. Obviously, this does not speed the processing up, but it did allow us to see how far behind we were getting by looking at the size of the queue.

At the start of the day, no messages are going through the whole system, this quickly ramps up from 1560000 (433/sec) messages through the hub in the first hour to 2100000 (582/sec) in the 3rd hour, and then staying at that level. At the start of the first hour, the message publishing from the component reading records from the database table keeps up, but by the end of that hour there are 2000 messages in the queue waiting to be sent and by the 3rd hour the queue has 9000 messages in it.

Below are the appropriate sections of the code which send the JMS messages. Any advice on what we are doing wrong or how we can improve this performance are much appreciated. Looking at stats on the web, JMS should be able to easily handle ~1000-2000 large messages/sec or ~10000 small messages/sec. Our messages are around 500 bytes each, so I imagine sit somewhere in the middle of that scale.

Code for getting the publisher:

private JmsSessionPublisher getJmsSessionPublisher(String topicName) throws JMSException {
    if (!this.topicPublishers.containsKey(topicName)) {
        TopicSession pubSession = (ActiveMQTopicSession) topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

        ActiveMQTopic topic = getTopic(topicName, pubSession);

        // Create a JMS publisher and subscriber
        TopicPublisher publisher = pubSession.createPublisher(topic);

        this.topicPublishers.put(topicName, new JmsSessionPublisher(pubSession, publisher));
    }
    return this.topicPublishers.get(topicName);
}

Sending the message:

JmsSessionPublisher jmsSessionPublisher = getJmsSessionPublisher(topicName);
    
ObjectMessage objMessage = jmsSessionPublisher.getSession().createObjectMessage(messageObj);
objMessage.setJMSCorrelationID(correlationID);
objMessage.setJMSTimestamp(System.currentTimeMillis());
jmsSessionPublisher.getPublisher().publish(objMessage, false, 4, 0);

Code which adds messages to the queue:

List<EventQueue> events = eventQueueDao.getNonProcessedEvents();
for (EventQueue eventRow : events) {
    IEvent event = eventRow.getEvent();
    AbstractEventFactory.EventType eventType = AbstractEventFactory.EventType.valueOf(event.getEventType());
    String topic = event.getTopicName() + topicSuffix;
    EventMsgPayload eventMsg = AbstractEventFactory.getFactory(eventType).getEventMsgPayload(event);
    synchronized (queue) {
        queue.add(new QueueElement(eventRow.getEventId(), topic, eventMsg));
        queue.notify();
    }
}

Code in the thread removing items from the queue:

jmsSessionFactory.publishMessageToTopic(e.getTopic(), e.getEventMsg(), Integer.toString(e.getEventMsg().hashCode()));

The publishMessageToTopic executes the 'Sending the message' code above.

Other JMS implementations are an option if the consensus is that ActiveMQ may not be the best option.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无尽的现实 2024-10-07 00:20:21

并不是 100% 清楚您在哪里遇到性能缓慢的情况,但听起来您所描述的是发布消息的速度缓慢。您每次发布消息时都会创建一个新的发布者吗?如果是这样,那么效率非常低,您应该考虑创建一个发布者并一遍又一遍地使用它来发送消息。此外,如果您要发送持久消息,那么您可能正在使用同步发送到代理。您可能需要考虑使用异步发送来加快速度。有关更多信息,请参阅有关 异步发送 的文档

另外,消费者的性能如何?有多少消费者正在使用?他们能否跟上消息发布的速度?

此外,您正在使用的代理配置是什么?它已经被调整了吗?

布鲁斯

It's not 100% clear where you are experiencing the slow performance, but it sounds like what you are describing is slowness in publishing the messages. Are you creating a new publisher every time you publish a message? If so, this is terribly inefficient and you should consider creating one publisher and use it over and over to send messages. Furthermore, if you are sending persistent messages, then you are probably using synchronous sends to the broker. You might want to consider using asynchronous sends to speed things up. For more info, see the doc about Async Sends

Also, how is the performance of the consumers? How many consumers are being used? Are they able to keep pace with the rate at which messages are being published?

Additionally, what is the broker configuration that you are using? Has it been tuned at all?

Bruce

暮年慕年 2024-10-07 00:20:21

尽管这是一个老问题,但缺少一个非常非常重要的建议:

  • 调查您拥有的主题和队列的数量。

ActiveMQ 将订阅主题保留在单独的线程中。特别是,当您有大量不同的主题时,这会拖累任何服务器。考虑使用 JMS 选择器。

我遇到了类似的情况,每秒有数千条市场数据消息。当我天真地将每条消息转储到市场工具特定通道中时,服务器能够在向消息生产者吐出错误消息之前等待大约一个小时。我更改了设计以拥有一个通道“MARKET_DATA”,然后在所有生成的消息上设置标头属性,并在消费者端设置一个选择器以仅选择我想要的消息。请注意,我的选择器采用类似 SQL 的语法,并且在服务器上运行...(是的,让我们跳过 CEP 营销炒作)...

Although this is an old question, there is one very very important advice missing:

  • Investigate the amount of topics and queues that you have.

ActiveMQ keeps subscription topics in separate threads. Particularly, when you have large amounts of different topics, this will drag down any server. Think about using JMS selectors instead.

I ran into a similar situation where I had thousands of market data messages per second. When I naively dumped each message into a market instrument specific channel, the server was able to stand about an hour before it was spitting out error messages to the message producers. I changed the design to have ONE channel "MARKET_DATA" and I then set header properties on all produced messages and set a selector on the consumer side to select just the messages that I want. Note that my selector is in SQL like syntax and runs on the server though ... (yeah, let's skip the CEP marketing hype bashing) ...

苏别ゝ 2024-10-07 00:20:21

我们不使用ActiveMQ,但我们遇到了类似的问题,我们发现问题出在后端处理而不是Java端。这里可能存在多个问题:

  1. 处理来自队列的消息的程序可能很慢(例如大型机上的 CICS),它可能无法跟上发送到队列的消息。一种可能的解决方案是提高处理能力(或优化处理消息的后端代码)
  2. 检查队列上的消息,有时队列上有很多未提交的有害消息,我们使用单独的队列来处理此类消息消息。

We do not use ActiveMQ, but we ran into similar issues, we discovered that the issues were with the back-end processing and not with the Java side. There could be multiple issues here:

  1. The program processing the messages from the queue could be slow (e.g. CICS on mainframe) it might not be able to keep up with the messages that are sent to the queue. One possible solution for this is to increase the processing power (or optimize the back end code which processes the messages)
  2. Check the messages on the queue, sometimes there are are lots of uncommitted poison messages on the queue, we use a separate queue for such messages.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文