JMS主题与队列

233
我想知道JMS队列和JMS主题之间有什么区别。 ActiveMQ页面上说:
主题: 在JMS中,主题实现了“发布和订阅”的语义。当你发布一条消息时,所有感兴趣的订阅者都会收到消息的副本,所以可能会有零到多个订阅者接收到消息。只有在代理接收到消息时有活动订阅的订阅者才会收到消息的副本。
队列: JMS队列实现了“负载均衡”的语义。一条消息只会被一个消费者接收。如果在发送消息时没有可用的消费者,消息将被保留,直到有可以处理消息的消费者可用。如果消费者在关闭之前接收到消息但没有确认,那么消息将被重新发送给另一个消费者。队列可以有多个消费者,消息会在可用的消费者之间进行“负载均衡”。
我想将每条消息的副本按照代理接收到的顺序发送给每个订阅者。
有什么想法吗?
10个回答

175

这意味着主题(topic)是合适的。队列(queue)意味着消息只会发送给一个可能的订阅者。而主题会发送给每个订阅者。


5
你知道JMS或WSO2 MB中的队列负载均衡是如何工作的吗? - Kulasangar
很有趣,因为我正在尝试调试一些订阅者,当发送主题时,订阅者没有被调用,但是当发送到队列时它起作用了。 - vmrvictor
1
更准确地说,例如使用RabbitMQ,您可以使用扇出交换机制将相同的消息发送到所有分配的队列,因此许多消费者将接收它。虽然不完全是发布-订阅模式,但可以实现类似的功能。 - user07
问题的第二部分是“按照接收顺序”。据我所知,主题并不能保证消息的顺序,或者至少队列在消息顺序方面有更强的保证。 - undefined

75

就是这么简单:

队列 = 插入 > 取出 (发送给单个订阅者) 1:1

主题 = 插入 > 广播 (发送给所有订阅者) 1:n

输入图像描述


9
一个简单的社交网络可以作为例子。有人“点赞”了一篇文章,后端会向主题发布一个“POST LIKE”事件。这个事件被3个订阅者所接收:notificationProcessor(向帖子作者发送通知),karmaProcessor(给点赞者和帖子作者增加声望值),feedProcessor(将该帖子在人们的动态中向上移动)。当然所有这些都是异步完成的。 - Siddhartha
@Siddhartha,这可能是一个带有示例的答案,谢谢! - SeleM

62

主题用于发布-订阅模型,而队列用于点对点。


1
这是文档的原文,请更详细地说明。 - Wildhammer

45
一个JMS主题是一对多模型中的目标类型。 所有消费者订阅者都会接收到相同的已发布消息。您也可以将其称为“广播”模型。您可以将主题视为分布式计算中Observer设计模式中的Subject的等价物。一些JMS提供者有效地选择将其实现为UDP而不是TCP。对于主题,消息传递是“发送并忘记”-如果没有人听取,消息就会消失。如果这不是您想要的,可以使用“持久性订阅”。 JMS队列是消息的一对一目标。消息仅由一个接收方接收器接收(请注意:始终使用订阅者用于“主题客户端”,使用接收器用于队列客户端避免混淆)。发送到队列的消息存储在磁盘或内存中,直到有人接收它或过期。因此,队列(和持久性订阅)需要一些主动的存储管理,您需要考虑慢速消费者。
在大多数情况下,我会认为主题是更好的选择,因为您可以随时添加其他组件而无需更改架构。添加的组件可以是监视、日志记录、分析等。你永远不知道项目开始时1年、5年、10年后的要求会是什么样子。变化是不可避免的,接受它吧 :-)

13

队列

优点

  • 简单的消息传递模式和透明的通信流程
  • 可以通过将消息放回队列中来恢复它们

缺点

  • 只有一个使用者可以获取消息
  • 意味着生产者和消费者之间存在耦合,因为这是一种一对一的关系

主题

优点

  • 多个消费者可以获取消息
  • 生产者和消费者之间解耦(发布-订阅模式)

缺点

  • 更复杂的通信流程
  • 无法为单个侦听器恢复消息

8
关于订单保留,请参见此ActiveMQ页面。简而言之:对于单个消费者,保留顺序,但是对于多个消费者,交付顺序不能保证。

4
如果您有N个消费者,则:
JMS主题将向N个中的N个传递消息 JMS队列将向1个中的N个传递消息
您说您“希望拥有一个‘东西’,可以将消息的副本发送给每个订阅者,顺序与ActiveMQ代理接收到消息的顺序相同。”
因此,您希望使用主题,以便所有N个订阅者都收到消息的副本。

3

主题:主题是一对多的通信方式...(多点或发布/订阅) 例如:想象一下,一个发布者在YouTube上发布了一部电影,那么它的所有订阅者都会收到通知... 队列:队列是一对一的通信方式... 例如:当发布充值请求时,它只会发送给一个接收者... 请始终记住,如果请求发送到所有接收者,则会发生多次充值,因此在开发过程中要分析哪种方式适用于应用程序。


1
我更喜欢对主题和队列进行深入解释,而不是简单比较。如果你真的想了解它们的区别,那么详细的解释会很有帮助:
在默认配置中,队列和主题中的消费者“接收”消息,而不是“获取”消息,它们“监听”,而代理服务器“发送”消息。 代理服务器将消息“推送”给消费者。 这是因为推送消息具有高吞吐量,并且可扩展。 这个过程始终是异步的。
你可以在队列中“获取”消息,但不能在主题中。当你“获取”一条消息时,这个过程是同步的,而且不可扩展。

enter image description here

在队列中,有很多消费者,只有第一个消费者会收到消息。 通常,队列使用“轮询模式”来传递消息。 轮询模式是一种平均分配消息的方式,代理将第一条消息发送给消费者A,然后将第二条消息发送给消费者B,再发送给消费者C。在发送给所有消费者之后,代理再次将下一条消息发送给消费者A,依此类推。
在主题中,所有订阅者都会接收到消息。 如果主题中的某个订阅者离线,其他订阅者会收到消息,但离线的订阅者将丢失该消息。 如果所有订阅者都离线,消息将会丢失。

enter image description here

Topic中,如果您将订阅者配置为持久性,则如果其离线,代理会等待订阅者重新上线: 非持久性订阅者离线丢失消息的情况 enter image description here 持久性订阅者离线不会丢失消息的情况 enter image description here 另一方面,如果Queue中的消费者离线,代理将等待消费者回来(前提是队列不是竞争消费者)。
总之,当代理接收到新消息时,它会寻找正在监听队列的其中一个消费者,并获取其引用,然后发送消息。当代理从消费者那里收到确认消息成功接收到的确认后,代理会删除Queue的消息。
当一个主题时,代理咨询当前正在监听它的所有订阅者,将消息发送给每个人,并等待他们的回复(确认)。当所有订阅者都发送了确认时,它删除消息。
在具有竞争消费者的队列中,或者在代理集群中,您可以提供一种标识一组相关消息的方式。
使用组ID可以保证消息处理的顺序。例如,您不希望在执行插入操作之前处理订单的更新。
消息可以通过任何方式相关联-例如,客户订单号码。基本上,JMS代理提供了一个保证:属于特定组的任何消息始终由一个共同的消费者消费。

-1
队列是JMS管理的对象,用于保存等待订阅者消费的消息。当所有订阅者都消费了消息后,消息将从队列中移除。
主题是当消息发布时,所有订阅该主题的订阅者都会收到相同的消息。

2
队列消息只能被单个消费者消费一次,这就是为什么队列实现了负载均衡。主题订阅可以是持久的:订阅者可以在发布后很长时间收到消息(例如,如果订阅者关闭并再次启动)。 - Gruber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接