ActiveMQ消息的可靠性

我们在ActiveMQ消息持久化订阅中,介绍了对Topic模式下的消息进行持久化订阅,使其在暂无消费者消费或ActiveMQ服务重启的情况下,不会导致消息的丢失,这里其实就是保证了一定程度的消息可靠性。


那么还会在其他地方发送消息不可靠的情况么,首先我们从消息的生产及消费的流程中来看,消息有生产者发送到ActiveMQ消息队列中,这个过程发送消息会发生消息一般在Queue模式下,是不会存在问题的,而在Topic模式下我们也是可以进行持久化订阅的,见ActiveMQ消息持久化订阅


因为在生产者端,我们会使用send()方法向ActiveMQ发送消息,默认情况下,持久化消息以同步方式发送,send() 方法会被阻塞,直到 broker 发送一个确认消息给生产者,这个确认消息表示broker已经成功接收到消息,并且持久化消息已经把消息保存到存储中。
在这里插入图片描述

这里我们又会发现,上述我们一共发送了三次消息,每次只有在send()方法成功才会确定提交到我们的ActiveMQ,但是如果在业务中,这三条消息是关联的,这里我们希望要不一起成功,要不一起失败,那么该如何处理呢。


这里我们可以使用事务提交,事务中消息(无论是否持久化),会进行异步发送,send() 方法不会被阻塞。但是commit() 方法会被阻塞,直到收到确认消息,表示broker已经成功接收到消息,并且持久化消息已经把消息保存到存储中。
在这里插入图片描述

这里我们就会发现开启了事务消息之后,我们在send()方法之后,消息不会立即到达ActiveMQ中,而必须等待commit之后,这里我们可以通过ActiveMQ控制台,进行debug验证,其实这个事务消息和数据库事务非常的类似。




看完了消息的生产者,那么我们消息的消费者在消费消息时,会产生问题么?如消息发送成功后,接收端接收到了消息。然后进行处理,但是可能由于某种原因,高并发也好,IO阻塞也好,这条消息在接收端处理失败了。


但是如在Queue模式下的特性是一条消息,只会被一个接收端给接收,只要接收端A接收成功了,接收端B就不可能接收到这条消息,如果该消息是一些比较重要的消息,那么就必须要保证消息的可靠性。在消费者端对对消息的确认有4种机制,如下:

  • AUTO_ACKNOWLEDGE = 1   自动确认
  • CLIENT_ACKNOWLEDGE = 2   客户端手动确认
  • DUPS_OK_ACKNOWLEDGE = 3   自动批量确认
  • SESSION_TRANSACTED = 0   事务提交并确认

在这里插入图片描述


首先我们再看第一个 AUTO_ACKNOWLEDGE ,即自动确认应答,这里我们需要特别注意的是,需要使用异步的方式来消费消息,因为在同步接受消息时,在receive()方法接受到消息后(还未进行业务处理),这时消费者就会自动确认
在这里插入图片描述


而在异步接受消息的时候,即使用监听器去消费消息,这里会直到onMessage()方法执行完成后(包括了业务处理),才会去自动确认
在这里插入图片描述

其中如果发生了异常,那么ActiveMQ会对其进行重发,默认会重试6次,重发6次失败后,就会进入死信队列中,这里我们在上述给其手动抛出一个异常,结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:当我们使用messageListener方式消费消息时,可以在onMessage()方法中使用try-catch,这样可以在处理消息出错时记录一些信息,而不是让不断去重发消息;如果你没有使用try-catch,就有可能会因为异常而导致消息重复接收的问题,这时就必须需要注意onMessage()方法中逻辑是否能够兼容对重复消息的判断。




第二个 CLIENT_ACKNOWLEDGE ,表示客户端手动确认,这就意味着AcitveMQ将不会自动的为我们进行ACK任何消息,需要我们自己择机确认。
在这里插入图片描述
在这里插入图片描述

这里我们需要就会使用同步消费方法了,因为最终是由我们自己进行确认,但是如果忘记调用acknowledge()方法,将会导致当consumer重启后,会接受到重复消息,因为对于broker而言,那些尚未真正ACK的消息被视为“未消费”。


我们可以在当前消息处理成功之后,可以立即调用message.acknowledge()方法来"逐个"确认消息,这样可以尽可能的减少因网络故障而导致消息重发的个数;当然也可以处理多条消息之后,间歇性的调用acknowledge()方法来一次确认多条消息,减少ack的次数来提升consumer的效率,不过需要自行权衡。




DUPS_OK_ACKNOWLEDGE 该参数类似于AUTO_ACK确认机制,可以自动批量确认,而且具有“延迟”确认的特点,ActiveMQ会根据内部算法,在收到一定数量的消息自动进行确认。

在此模式下,可能会出现重复消息,因为当consumer故障重启后,那些尚未ACK的消息(但是实际上已经消费了),就会重新发送过来。




最后一个 SESSION_TRANSACTED ,当session使用事务时,就是使用此模式。当决定事务中的消息可以确认时,必须调用session.commit() 方法,commit() 方法将会导致当前 session 的事务中所有消息立即被确认。
在这里插入图片描述

其实获取session时,该方法的第一个参数表示是否支持事务,如果为true,则会忽略第二个参数,自动被jms服务器设置为SESSION_TRANSACTED


在事务开始之后的任何时机调用rollback() ,意味着当前事务的结束,事务中所有的消息都将被重发。当然在commit() 之前抛出异常,也会导致事务的rollback()


这里其实和我们上述在消息生成者中,进行设置true使用了事务,其作用是相同的,就是我们需要使用commit() 来进行事务的提交。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章