【问题标题】:How does JMS Receive work internally?JMS Receive 如何在内部工作?
【发布时间】:2011-08-22 13:41:10
【问题描述】:

我一直在研究各种通信技术/架构/模式/实现(阅读:流行语),包括 Web 服务(WCF、Axis2)、ESB、SOA,并且想了解有关消息传递方面 JMS 的更多信息。

从概念上讲,JMS 听起来很简单。我的看法是,它是一个中间代理,它管理来自发布者的消息并将它们路由到适当的订阅者。这是通过在消息发布时将消息排队并在收到消息时将其出列来完成的。

问题一:我对 JMS 的基本理解正确吗?

在阅读有关技术的文章时,让我感到困扰的一件事是,当某项功能发生某种程度的(有意或无意的)挥手时。

根据我的基本理解,必须运行 JMS 提供程序才能发送或接收消息。我对发布的假设是 JMS Provider 只是等待消息发布,然后将其存储在队列中(内存或数据库支持,取决于实现)。但是,我不太确定接收是如何工作的。

问题 2:如果没有可用的消息,接收(通常)会阻塞吗?

问题 2b:如果是这样,如何实现阻塞?客户端是否不断轮询消息?服务器是否只是在消息发布之前不响应(如何在没有超时的情况下工作?)提供者是否向接收者发起调用?

问题 2c:如果不是,如何确保及时收到消息而不影响性能?

基本描述似乎倾向于单个 JMS 提供程序,以确保消息得到集中管理而不会丢失。我可以看到缩放是一个问题。

问题 3:JMS 如何扩展?

在扩展时,我可以看到确保将单个消息传递给所有适当的订阅者的复杂性,无论哪个物理服务器接收消息。

问题 3b:JMS 实施如何确保在扩展环境中可靠交付?

请注意,尽管这些问题与 JMS 有关,但它们可能适用于任何消息传递基础架构。我欢迎针对 JMS 以及更通用甚至针对其他技术的答案。

【问题讨论】:

  • 如果您想深入了解,horneq 是开源的并提供了 jms 实现。获取源代码here 的说明。您可能还想阅读the docs 中的架构和概念部分,它可能会帮助您在一定程度上缩小问题的范围。

标签: java jms message-queue messaging


【解决方案1】:

JMS 中有两种类型的消息传递域。

  1. Point-To-Point(PTP) 消息域
  2. 发布者/订阅者消息域

在 PTP 模型中,一条消息仅传递给一个接收者。在这里,队列被用作M消息O面向M中间件(MOM)。

队列负责保存消息直到接收者准备好。

在 PTP 模型中,发送方和接收方之间没有时间依赖关系。


在 Pub/Sub 模型中,将一条消息传递给所有订阅者。这就像广播。在这里,Topic 被用作一个面向消息的中间件,负责保存和传递消息。

在 PTP 模型中,发布者和订阅者之间存在时间依赖性。


JMS 编程模型

source


M留言D撕裂Bean (MDB)

  • MDB 是一个包含业务逻辑的 bean。但是,它是通过传递消息来调用的。所以,它就像 JMS Receiver。
  • MDB 异步接收并处理消息。
  • MDB 接收来自队列或主题的消息。
  • MDB 就像无状态会话 bean,封装了业务逻辑,不维护 bean 的状态。

【讨论】:

    【解决方案2】:

    我试图根据我在 JMS 上的经验回答几个问题。

    答案1:- JMS 是Java Message Service API;它为 Java 客户端访问消息传递框架提供了统一的接口。在 JMS API 之下是一个与 JMS 兼容的消息传递提供程序,例如 WebSphere MQ 提供程序。 JMS 支持通过任何消息传递协议将有效负载传输到目的地,即。队列和主题。 这些是 JMS 的基础知识。

    接收是如何工作的? JMS 规范提供了两个重要的类:-MessageConsumerMessageListenerMessageConsumer 类允许 JMS 客户端通过调用其任何 receive() 方法来同步接收 JMS 消息。此调用将阻塞线程,直到收到消息。 否则,可以通过将MessageListener 的对象注册到MessageConsumer 来进行异步接收。 JMSProvider 知道消息已到达其本地目的地,它的工作是将消息传递到轮询消息消费者线程或非轮询注册消息侦听器线程。

    答案 2:- MessageConsumer API 有两种接收变体:receive()receive(long timeout)。后一种变体让MessageConsumer 线程阻塞,直到消息在特定超时期限内到达,否则超时。

    不同的消息传递框架可能以不同的方式实现阻塞功能。由于 JMS 对象是 JNDI 管理的对象,并且提供者特定的代理对象返回给 JMS 客户端,这意味着客户端不知道阻塞是如何在后台发生的。特定的消息传递框架可能会在特定时间段后选择消息消费者线程轮询。或者,它可以选择阻止直到发送通知。

    我不确定您是否正在寻找特定 JMS 兼容消息传递框架的答案?

    答案 3:- 我想通过 JMS 扩展,您的意思是能够拥有许多发布者/订阅者,在多台物理机器上拥有许多目的地。 JMS 扩展需要支持底层消息传递提供程序以支持某种集群/故障转移。因此,JMS 规范不支持可伸缩性。如果我错了,请纠正我?例如,我曾在提供集群支持的 JMS 兼容 WebSphere MQ 上工作。

    【讨论】:

    • 我意识到 JMS 只是一个规范,所以我基本上将您的回答读作“它取决于实现”(这是完全可以接受的)。我希望获得有关与轮询/等相关的阻塞方面的更多技术细节。一个更普遍的问题可能是异步消息传递架构如何扩展而不会对性能产生负面影响(假设所有订阅者都在轮询、打开连接和阻塞或等待广播)。
    【解决方案3】:

    问题1:我对JMS的基本理解正确吗?

    让我们先搞清楚术语。你不能说JMS Provider must be running,因为提供者是一个已经构建了JMS 服务器的实体,它是必须运行的JMS 服务器。因此,当我们说 JMS 时,我们的意思是提供者实现的一组 API(从技术上讲是接口)。所以基本上供应商编写自己的 JMS 实现。例如,Active MQ is a JMS serverApache(provider) 提供

    我对发布的假设是,JMS Provider 只是等待消息发布,然后将其存储在队列中(内存或数据库支持,具体取决于实现)。

    在某种程度上是正确的。有不同的模型遵循。 JMS 服务器保持一个套接字打开。每当发送方客户端必须发送消息时,它只需打开到套接字的连接并发送消息。接收的行为方式完全不同。你有pullpush。推送服务器将在收到消息后立即将消息推送到实时接收者客户端。这也称为异步模式。在拉取模型中,客户端接收器向服务器发送请求以获取消息(同步模式)。

    如果没有可用消息,是否接收(通常)阻塞?

    正如我在前面提到的,这取决于您使用的模型。接收器将在拉模型中被阻塞(同步接收)。这也发生在会话线程中,而不是主线程中。

    如果是这样,阻塞是如何实现的?客户端是否不断轮询消息?

    是的,客户端会在拉模式的情况下不断轮询。通常有一个超时时间,在此之后客户端将被终止。

    如果不是,如何确保及时收到消息而不影响性能?

    使用异步模式。您只需注册一个 MessageListener,当服务器上有可用消息时,它会在覆盖的 onMessage(Message msg) 上接收消息。

    问题 3:JMS 如何扩展?

    这确实是供应商担心的问题。当您说所有订阅者都收到消息时,您指的是 PUBSUB 通信模型(其他是 PTP)。在 PUBSUB 中发送到某个主题的消息将被传递给订阅该主题的所有订阅者。

    问题 3b:JMS 实现如何确保在扩展环境中可靠交付?

    可靠性?不总是。同样,这取决于用例。您可以拥有持久性以及非持久性消息。在持久消息的情况下,消息存储在数据库(文件或其他)中,并确保其传递。在非持久消息的情况下,没有这样的保证。服务器故障可能会导致消息丢失。

    【讨论】:

    • 您的回答在很大程度上只是延续了我的一般问题(即挥手)。有一个接收消息的监听器描述/what/发生,但没有解释消息是如何以perfromant方式异步传递的。您提到了使用拉模型进行阻塞,但是异步提供程序是如何实现的?是的,可扩展性和可靠性显然是提供商必须担心的问题。但是它们通常是如何工作的呢?
    • 在异步模型接收器会注册一个MessageListener。这是在会话线程中完成的。注册 Session 线程后可以继续处理它。当消息在队列中可用或主题消息被推送到客户端时。 客户端库将调用 MessageListener 的回调函数 onMessage(),并在您拥有消息处理逻辑的 SessionThread 中接收到消息。
    • 我仍在寻找更多细节 - 例如,考虑您的客户端在一台服务器上,您的 JMS 提供程序是一个扩展系统(即,不止一台服务器)。从网络的角度来看,客户端连接到什么,如何以相反的方向传递响应。我认为您要说的是服务器发起与客户端的连接以传递消息。如果客户端离线会发生什么?同样,我关心的是可靠性(保证交付、持久消息)和性能(交付时间)。
    【解决方案4】:

    我认为应该提到队列和主题之间的区别,因为消息传递的方式存在重要差异。

    队列:只有一个客户端会收到一条消息。要向外扩展,您可以让 10 个客户端都连接到同一个队列 - 但只有其中一个会收到特定消息。如果没有客户端连接,消息将保留在队列中,直到有人连接或消息超时。

    主题:所有客户端都会收到每条消息的副本。通常用于许多端点可能对每条消息感兴趣的订阅者场景。一个持久的订阅者甚至可能会宕机一段时间;消息将被保留,直到订阅者再次启动或消息超时。如果没有客户端连接并且没有持久订阅者,则消息将被丢弃。

    【讨论】:

      【解决方案5】:

      JMS 支持使用同步方法(在有和没有超时阻塞线程的情况下接收)或使用事件驱动的回调(异步消息侦听器)进行消息消费。

      您可以决定哪种方法更适合您的需求,但您也可能需要查看实际的实现。例如,一些 JMS 实现为 receive() 进行网络往返,因此更适合与超时或侦听器一起使用。

      消息侦听器线程的行为和消息接收的暂停不像阻塞接收调用那样容易控制。通常,大多数控制是通过拥有自己的具有超时的阻塞接收()调用池来实现的,并分派给您的工作人员。

      【讨论】:

        猜你喜欢
        • 2012-02-05
        • 1970-01-01
        • 2019-01-13
        • 2010-10-14
        • 2013-09-28
        • 2012-08-01
        • 2011-12-10
        • 2018-02-10
        • 2014-09-29
        相关资源
        最近更新 更多