文章目录
RabbitMQ一般情况下消息不会发生丢失的问题,但是不能排除意外,为了保证我们自己的系统高可用,我们必须做出更好完善的措施,保证系统的稳定性。
1、消息持久化
RabbitMQ的消息默认放在内存上面,如果不特别声明设置,消息不会持久化到磁盘上,如果节点重启或者宕机,就会导致消息丢失。
(1)Exchange持久化:channel.exchangeDeclare(exchangeName, “direct/topic/header/fanout”, true);即在声明的时候讲durable字段设置为true即可。
(2)Quque持久化:queue的持久化是通过durable=true来实现的。
(3)Message消息持久化:发送消息设置发送模式deliveryMode=2,代表持久化消息。
2、ACK确认机制(异步)
多个消费者同时收消息,比如消息收到一半的时候,一个消费者死掉了(逻辑复杂事件太长,超时了或者消费被停机或者网络断开连接),如何保证消息不丢失?
使用Message acknowledgment机制,消费者消费完成要通知服务端,服务端才把消息从内存删除。
例如:生产者发生消息丢失
//设置消息发送确认--回调 开关
connectionFactory.setPublisherConfims(true);
//同时启动一个监听(生产者监听确认):监听生产者是否消息发送成功。
template.setConfirmCallback(confirmCallback());
例如:消费者消息丢失
消费者获取到消息之后,没有来得及处理完毕,自己直接宕机了,因为消息这默认采用自动ack,此时RabbitMQ的自动ack机制会通知MQ Server这条消息已经处理好了,此时消息就丢了,并不是预期的。
采用手动ACK机制来解决这个问题,消费端处理完逻辑之后在通知MQ Server,这样消费者没处理完消息不会发送ack,如果在消费者拿到消息,没来得及处理的情况下自己挂了,此时MQ集群会自动感知到,它会自觉的重发消息给其他的消费者服务实例。
# 需要两步操作
1、消费者监听设置手动ack
this.channel.basicConsume(queue, false, consumerTag, this);
2、业务完成后手动ack
context.getChannel().basicAck(deliveryTag, false);
3、设置集群镜像模式
RabbitMQ三种部署模式:
(1)单节点模式:最简单的情况,节点挂了,消息就不能用了。
(2)普通模式:默认的集群模式,某个节点挂了,该节点上的消息不能用,有影响的业务瘫痪,值能等待节点恢复重启可用(消息持久化的);
(3)镜像模式:把需要的队列做成镜像队列,存在于多个节点,输入RabbitMQ的HA方案,
三种HA策略模式:
- (1)同步所有的
- (2)同步最多的N个机器
- (3)只同步至符合指定名称的nodes
4、消息补偿机制
持久化的消息,保存到硬盘中,当前队列节点挂了,存储节点硬盘又坏了,消息丢失了,怎么办?
产线网络环境太复杂,所以不知数太多,消息补偿机制需要建立在消息要写入DB日志,发送日志,节后日志,两者的状态必须记录。
然后根据DB日志记录check消息发送消费是否成功,不成功,进行消息补偿措施,重新发送消息处理。
5、路由保障(解决交换机消息丢失的问题)
路由保障的出现就是为了解决路由信息不匹配的情况,当消息没有成功通过路由键路由到队列中时,那么消息就会发生丢失的情况,主要有两种方式失败通知和备用交换机。
(1)失败通知
这时候就需要有一个失败通知(mandatory+ReturnListener)。
//路由失败通知
template.setMandatory(true);
//回调
template.setReturnListener(returnCallback());
(2)备用交换机
在路由的时候,有可能是路由键路由的范围不够广。
所以在创建交换机的时候可以再创建一个其他路由键的交换机(比如Fanout广播式交换机),以此来确保消息可以路由到另一个队列中,从而保证消息不会丢失
6、生产者生产消息到RabbitMQ Server可靠性保证?
(1)AMQP协议提供的一个事务机制(用的比较少)
(2)发送方确认机制
首先生产者通过调用channel.confirmSelect方法将信道设置为confirm模式,一旦
信道进入confirm模式,所有在该信道上面发布的小都会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,RabbitMQ就会发送一个确认给生产者(包含消息的唯一deliveryTag和multiple参数),这就使得生产者知晓消息已经正确到达了目的地了。
其中Confirm模式有三种方式实现
串行confirm模式:生产者每发送一条消息后,调用waitForConfirms()方法,等待broker端confirm,如果服务器端返回false或者在超时时间内未返回,客户端进行消息重传。
批量confirm模式:生产者每发送一批消息后,调用waitForConfirms()方法,等待broker端confirm。
异步confirm模式:提供一个回调方法,broker confirm了一条或者多条消息后producer端会回调这个方法。
7、消息幂等性—防止消息的重复消费
产生原因:网络延迟传输中,消费者出现异常或者消费者延迟消费,会造成进行MQ重试补偿,在重试过程中,可能会造成重复消费。
面试题:MQ中消费者如何保证幂等性问题,不被重复消费