目录
一、消息丢失的情况
1. 生产者——RabbitMQ:
当消息的生产者将消息发送出去之后,消息到底有没有正确地到达服务器呢?
如果不进行特殊配置,默认情况下发送消息的操作是不会返回任何信息给生产者的,也就是默认情况下生产者是不知道消息有没有正确地到达服务器。如果在消息到达服务器之前己经丢了。
或者由于消息到了RabbitMQ但是内部出错了没有保存下来;
2. RabbitMQ:
RabbitMQ接受到消息之后就先暂存在自己的内存里,结果消费者还没有来得消费,RabbitMQ自己就挂掉了,就导致内存里面的数据丢失了
3. RabbitMQ——消费者:
消费者消费到了这个消息,但是还没来得及处理,自己就挂了,但是RabbitMQ以为这个消费者处理完了。
二、如何保证消息的可靠性传输?
针对第一种情况有如下解决方法:
1.生产者角度
RabbitMQ针这个问题,提供了两种解决方式:
- 通过事务机制实现
- 通过发送方确认(publisher confirm)机制实现
a. 事务机制
RabbitMQ客户端中与事务机制相关的方法有三个:
- channel.txSelect用于将当前信道设置成事务模式
- channel.txCommit用于提交事务
- channel.txRollback用于事务回滚
在通过channel.txSelect方法开启事务之后,我们便可以发布消息给RabbitMQ(这里是指交换器)了,如果事务提交成功,则消息一定到达了RabbitMQ中,如果在事务提交执行之前由于RabbitMQ异常崩溃或者其他原因抛出异常,这个时候我们便可以将其捕获,进而通过执行channel.txRollback方法来实现事务回滚。注意这里的RabbitMQ中的事务机制与大多数数据库中的事务概念井不相同,需要注意区分。
try{
channel.txSelect();
channel.basicPublish("exchangeName","routeKey",props,"message".getBytes());
channel.txCommit();
}catch (Exception e){
e.printStackTrace();
channel.txRollback();
}
如果需要发送多条消息,可以通过如下方式提交:
channel.txSelect();
for (int i=0;i<100;i++){
try{
channel.basicPublish("exchangeName","routeKey",props,"message".getBytes());
channel.txCommit();
}catch (Exception e){
e.printStackTrace();
channel.txRollback();
}
}
事务确实能够解决消息发送方和RabbitMQ之间消息确认的问题,只有消息成功被RabbitMQ接收,事务才能提交成功,否则便可在捕获异常之后进行事务回滚,与此同时可以进行消息重发。
但是使用事务机制会"吸干"RabbitMQ的性能,那么有没有更好的方法既能保证消息发送方确认消息已经正确送达,又能基本上不带来性能上的损失呢?从AMQP协议层面来看并没有更好的办法,但是RabbitMQ提供了一个改进方案&#x