JMS

消息确认机制

  消息确认协议是保证消息传送的关键所在,同时,支持确认也是 JMS API 语义的要求。以下将分别从消息生产者、消息服务器、消息消费者的角度,来考察消息确认机制。

从消息生产者的角度考察

  在表象之下,TopicPublisher.publish() 或 QueueSender.send() 方法是同步的。这些方法负责发送消息,同时进行阻塞,直到从消息服务器接收到一个确认为止。一旦接收到一个确认,执行线程就会恢复并返回方法,并像正常情况那样继续处理。底层确认对客户端编程模型来说是不可见的。如果在这个操作期间发生了一个故障情况,就会抛出一个异常,同时认为该消息未被传送。

从消息服务器的角度考察

  从消息服务器的发送到生产者,意味着服务器已经接收到该消息,并已经承担了传送它的责任。

  在发布/订阅模型中,消息服务器向每个订阅者都传送了消息的一个副本。对于持久订阅者来说,一直到消息服务器接收到所有的消息预定接收者的确认时,消息服务器才会认为该消息已经完成传送。一旦消息服务器将消息传送给所有的已知订阅者,并已分别从这些订阅者那里接收到确认,就会将这些消息从持久存储器中删除。

  如果订阅是持久的,而且订阅者当前并未连接,那么,消息服务器就会将该消息保存起来,直到该订阅者变为可用状态或消息到期为止。甚至对于非持久性消息来说,也是如此。如果一条非持久性消息原本打算供未连接的持久订阅者使用,消息服务器会将该消息保存到磁盘中,就好像它是一条持久性消息一样。这时,持久性和非持久性这两种消息的差异虽然很细微,但是非常重要。对于非持久性消息来说,在消息服务器已经向发送者确认消息之后和消息服务器有机会代表未连接的持久订阅者将消息写人磁盘之前,这二者之间可能会有一个时间窗。如果 JMS 提供者在这个时间窗内出现故障,该消息就可能会丢失。不过,JMS 规范虽然暗示了可能会出现这种故障情况。但实际上 JMS 提供者可能不会允许这种情况出现。在使用持久性消息时,一个提供者可能会出现故障,并且优雅地恢复正常。由于消息保存在持久存储器中,它们并没有丢失。在提供者再次启动时,它们又会传送给消费者。

从消息消费者的角度考察

  从消费者的角度考虑,当每个消费者获得消息时,它需要向服务器发送确认信息。如果服务器没有收到这个确认信息,它就会认为该消息未被传送,并可能试图重新传送。
在将一条消息传送给非持久订阅的消费者时,如果提供者出现故障,这条消息就可能会丢失。如果一个持久订阅接收到一条消息,并在向提供者返回确认之前出现了故障,那么,JMS 提供者就会认为该消息未被传送,并试图对它进行重新传送。在这种情况下,“一次而且是仅仅一次”的要求就值得怀疑。消费者可能会再次接收到该消息,重新传送的消息会被设置 JMSRedelived 标记。为了预防消息重复,应用程序可以检查重新传送的消息是否已被处理。

消费者确认消息的方式

AUTO_ACKNOWLEDGE

  当消费者获取消息时,JMS 提供者的客户端运行时环境必须自动向服务器发送确认信息。

DUPS_OK_ACKNOWLEDGE

  AUTO_ACKNOWLEDGE 模式允许消费者在收到多个消息之后一次完成确认。

CLIENT_ACKNOWLEDGE

  CLIENT_ACKNOWLEDGE 模式中,接收消息的客户端可以通过 javax.jms.Message.acknowledge() 方法控制何时发送确认。

public void onMessage(Message message) {                    
    try {
        // 获取消息来执行相关的业务逻辑
        ...
        
        message.acknowledge();
        
        // 执行更多的 业务逻辑
        ...
    } catch (Exception e) {
        // 捕获抛出的异常,并取消局部处理结果
        ...
    }
}
原文地址:https://www.cnblogs.com/huey/p/4755803.html