高性能JMS消息传递

我阅读了今年UberConf的幻灯片,其中一位发言人提出Spring JMS为您的消息队列系统增加了性能开销的论点,但我没有看到任何证据支持幻灯片。 发言者还说明点对点比传统的“发布 – 订阅”方法更快,因为每个消息只发送一次而不是广播给每个消费者。

我想知道是否有经验丰富的Java消息传递专家可以在这里权衡并澄清一些技术细节:

  • 使用Spring JMS而不仅仅是纯JMS实际上是否会产生性能开销? 如果是这样,它是如何以及在何处引入的? 它有什么办法吗?
  • 有什么实际证据支持P2P比pub-sub模型更快,如果是这样的话,是否有任何情况下你想要通过P2P发布sub-sub(即为什么变慢?!? )?

1)主要的,Spring JMS的开销是使用JmsTemplate来发送没有缓存机制的消息。 从本质上讲,JmsTemplate将为您发送的每条消息执行以下操作:

  • 创建连接
  • 创建会话
  • 创建制片人
  • 创建消息
  • 发信息
  • 关闭会话
  • 关闭连接

这可以与您重复使用的手动编写的代码进行比较:

  • 创建连接
  • 创建会话
  • 创建制片人
  • 创建消息
  • 发信息
  • 创建消息
  • 发信息
  • 创建消息
  • 发信息
  • 关闭会话
  • 关闭连接

由于连接,会话和生成器的创建需要客户端和JMS提供者之间的通信,当然还有资源分配,它会为许多小消息创建相当大的开销。

您可以通过缓存JMS资源轻松解决此问题。 例如,使用spring CachingConnectionFactory或ActiveMQs PooledConnectionFactory (如果您使用的是ActiveMQ,则标记此问题)。

如果您在一个完整的JavaEE容器中运行,那么当您检索JNDI连接工厂时,池内/缓存通常是内置的并且是隐式的。

当使用spring Default Message Listening Container接收时,Spring中有一个薄层可能会增加很少的开销,但主要方面是您可以根据并发性等来调整性能。 本文非常好地解释了它。

2)

PubSub是一种使用模式,发布者不需要知道存在哪些订阅者。 你不能简单地用p2p模仿它。 并且,如果您没有任何证据,我认为如果您想从一个应用程序向另外十个应用程序发送相同的消息,则pub-sub设置将比将消息发送十次p2p更快。

另一方面,如果您只有一个生产者和一个消费者,请选择带有队列的P2P模式,因为它在某些方面更容易管理。 P2P(队列)允许负载平衡,其中pub / sub没有(很容易)。

ActiveMQ还有一个混合版本VirtualDestinations–它本质上是负载平衡的主题。

不同供应商的实际实现有所不同,但主题和队列并没有根本不同,并且应该具有相似的性能。 你应该检查的是:

  • 持久性? (=慢)
  • 消息选择器? (=慢)
  • 并发?
  • 耐用用户? (=慢)
  • 请求/回复,“与”临时队列“同步”(=开销=较慢)
  • 队列预取(=在某些方面影响性能)
  • 高速缓存

你在谈论Mark Richards的幻灯片吗? 他发布了他的基准测试的源代码,因此您可以实际测试他关于JmsTemplate性能的断言。 他的基准代码确实使用了Spring的CachingConnectionFactory,但是尽管有缓存,它仍然表明JmsTemplate会显着降低性能。 我已经执行,分析和分析了他的代码。 简短的回答是JmsTemplate的开销可以忽略不计,他的代码中可衡量的性能差异与ActiveMQ的异步vs同步发送模式有关。 我在这里发布了我的分析:

JmsTemplate并不邪恶

1)Spring模板打开/关闭发送/接收的每条消息的连接/会话。 这就是它变慢的原因。 大多数JMS实现在连接/会话保持打开时表现更好,因此他们可以使用消息预取等优化,更不用说避免执行所有连接建立/拆除位的开销。

2)如果将数据复制/复制到多个消费者,主题通常会更慢。 这只是一个物理问题。 如果将10兆的消息队列发送到队列,则只需要将10兆的数据传输给消费者。 在主题上,如果您有10个消费者,并且向其发送10兆的数据,那么必须将100兆的数据传输给消费者。 因此,对于大多数JMS实现:

  • 向主题添加消费者只会降低您的消费率。
  • 将消费者添加到队列通常有助于提高出队率。

我不是传讯大师,我希望你不要在这里分享我的想法;)

  1. 总会有开销,因为你有额外的间接性。 即使它只是调用堆栈中的额外级别,它仍然是开销。 但是,我认为这种开销很小。 您可以查看JmsTemplate的源代码。 在发送过程中Spring没有添加太多额外的东西。 如果您正在使用JMS,JmsTemplate主要执行您需要执行的操作。 您总是可以争辩说,那些额外的检查和更深入的方法调用总是需要更多的CPU周期和内存。 这是真的,但我想知道它有多重要。

  2. PubSub和P2P(JMS术语中的主题和队列)只是两种不同的模型。 我相信他们不能互相替换。 您不能通过使用Queue进行“一次发送和广播到多个接收器”行为,同时在使用主题时无法保证传送行为(除非使用Durable Subscriber,但这是另一个主题)。 所以,选择正确的类型取决于你在做什么,而不是盲目地说P2P优于PubSub(我认为是无意义的)