1、消息丢失

1.1、RabbitMQ流程

producer——》RabbitMQ——》consumer
SO:发生消息丢失的三种情况:

  1. producer端:发送消息过程中出现网络问题:producer以为发送成功,但RabbitMQ server没有收到;
  2. RabbitMQ server 端:接收到消息后由于服务器宕机或其他原因(消息默认存在内存中)导致消息丢失;
  3. Consumer端:Consumer端接收到消息后处理消息出错,没有完成消息的处理;
1.2、producer端

解决方式:

  1. 事务:在生产者发送数据之前开启rabbitmq事务(channel.txSelect),然后发送消息,如果消息没有成功被rabbitmq接收到,那么生产者会收到异常报错,此时就可以回滚事务(channel.txRollback),然后重试发送消息;如果收到了消息,那么可以提交事务(channel.txCommit)。
  • 缺点:耗费性能,效率低。
  1. 回执确认:开启confirm模式,在生产者那里设置开启confirm模式之后,你每次写的消息都会分配一个唯一的id,然后如果写入了rabbitmq中,rabbitmq会给你回传一个ack消息,告诉你说这个消息ok了。如果rabbitmq没能处理这个消息,会回调你一个nack接口,告诉你这个消息接收失败,你可以重试。而且你可以结合这个机制自己在内存里维护每个消息id的状态,如果超过一定时间还没接收到这个消息的回调,那么你可以重发。
    区别:
    事务是同步的,会发生阻塞;
    confirm是异步的,效率更高;
1.3、RabbitMQ Server端

解决方式:

  • 消息持久化
  • RabbitMQ 的消息默认存放在内存上面,如果不特别声明设置,消息不会持久化保存到硬盘上面的,如果节点重启或者意外crash掉,消息就会丢失。

要想做到消息持久化,必须满足以下三个条件,缺一不可。

  1. Exchange 设置持久化:durable:true
  2. Queue 设置持久化:durable:true
  3. Message持久化发送:发送消息设置发送模式deliveryMode=2,代表持久化消息
1.4、Consumer端

解决方法:

  • ACK确认机制:
  • 多个消费者同时收取消息,比如消息接收到一半的时候,一个消费者死掉了(逻辑复杂时间太长,超时了或者消费被停机或者网络断开链接),如何保证消息不丢?
    这个使用就要使用Message acknowledgment 机制,就是消费端消费完成要通知服务端,服务端才把消息从内存删除。
    这样就解决了,及时一个消费者出了问题,没有同步消息给服务端,还有其他的消费端去消费,保证了消息不丢的case。
    具体步骤:
  1. 交换机调用basicQos(1)方法:告诉RabbitMQ 不采用以前那种实现分配好的模式进行消息推送,而是每次只推送一条。
  2. 调用basicAck()方法手动回复ack消息
  3. 调用basicconsume()方法时将第二个参数写为false(开启手动ACK)
  4. mq收到ack消息会删除当前的消息。没收到会等待一段时间然后将重新发送该消息。
消息重复
原因
  1. 消费者端在消费完成后,手动ack发出,但是由于网络原因mqServer没有收到。so mq保留此条消息而后被重复消费。
  2. 生产者端发送消息,mqServer收到消息返回回执确认同样因为网络等原因生产者端并没有收到。再次发送同一条消息。
消息乱序

比如说生产者发送了两条消息:消息一:添加一条数据;消息二:修改这条数据;然而mq收到消息后发给消费者的顺序是不能保证的。有可能消费者先收到消息二;

  • so 如何解决呢?
  • 很简单:将这种带有先后顺序的消息发送到同一个队列中,这样它的顺序是肯定的。