1. 场景
先看这么几个面试题:
- 如何保证消息的可靠性投递?即如何确定消息是否发送成功?
- 如果失败如何处理(补偿机制)?
- 如何保证消息不被重复消费?或者说,如何保证消息消费时的幂等性?
2.消息的可靠性投递
消息确认
消息确认包括主要 生产者发送确认 和 消费者接受确认 ,因为发送消息的过程中我们是无法确认消息是否能路由等,一旦消息丢失我们就无法处理,所以需要确认消息,避免消息丢失。
2.1 生产者确认
我们知道生产者与消费者是完全隔离的,不做任何配置的情况下,生产者是不知道消息是否真正到达 RabbitMQ,也就是说消息发布操作不返回任何消息给生产者。
那么怎么保证我们消息发布的 可靠性投递 ?有以下几种常用机制。
由于之前的文章对上面都有过介绍,所以这里不一一介绍,而一般采用的方式就是 发布者确认模式(生产者确认模式) 。
原理:生产者将信道设置成 confirm 模式,一旦信道进入 confirm 模式,所有在该信道上面发布的消息都将会被指派一个唯一的 ID(从 1 开始),由这个 id 在生产者和 RabbitMQ 之间进行消息的确认。
这里的 唯一 ID 能够唯一标识消息,在消息不可达的时候触发回调时可以获取该值,进行对应的错误处理,建立对应的消息补偿机制。(记住这个唯一 ID,且是全局唯一,分布式系统中可采用雪花算法等方式)
confirm 模式最大的好处在于他可以是异步的,一旦发布一条消息,生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果 RabbitMQ 因为自身内部错误导致消息丢失,就会发送一条 nack 消息,生产者应用程序同样可以在回调方法中处理该 nack 消息决定下一步的处理。
注:这里描述的场景都是那样 正确路由到队列中 的,也就是不考虑失败通知(ReturnCallback)的情况。
由于现在大家开发基本都是通过 Spring Boot 的方式进行开发,所以,这里直接提供其基本配置类参考,如下:
/**
* @description : 消息生产者
*/
@Component
@Slf4j
public class RabbitmqProducer {
@Autowired
private Ra