1、RabbitMQ的使用场景
消息中间件
使用场景?解耦 异步化 削峰 分布式柔性事务
2、RabbitMQ如何确保消息发送 ? 消息接收?
网络不可靠
解决方案:确认机制+补偿重发
- 发送方确认机制
信道需要设置为 confirm 模式,则所有在信道上发布的消息都会分配一个唯一 ID。
一旦消息被投递到queue(可持久化的消息需要写入磁盘),信道会发送一个确认给生产者(包含消息唯一ID)。
如果 RabbitMQ 发生内部错误从而导致消息丢失,会发送一条 nack(未确认)消息给生产者。
所有被发送的消息都将被 confirm(即 ack) 或者被nack一次。但是没有对消息被 confirm 的快慢做任何保证,并且同一条消息不会既被 confirm又被nack。
发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者,生产者的回调方法会被触发。
ConfirmCallback接口:只确认是否正确到达 Exchange 中,成功到达则回调。
ReturnCallback接口:消息失败返回时回调。
- 接收方确认机制:
消费者在声明队列时,可以指定noAck参数,当noAck=false时,RabbitMQ会等待消费者显式发回ack信号后才从内存(或者磁盘,持久化消息)中移去消息。否则,消息被消费后会被立即删除。
消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ 才能安全地把消息从队列中删除。
RabbitMQ不会为未ack的消息设置超时时间,它判断此消息是否需要重新投递给消费者的唯一依据是消费该消息的消费者连接是否已经断开。这么设计的原因是RabbitMQ允许消费者消费一条消息的时间可以很长。保证数据的最终一致性;
如果消费者返回ack之前断开了链接,RabbitMQ 会重新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,需要去重)
3、如何保证消息的幂等性,不被重复消费?
其实就是要方式消费者重复消费消息的问题。
所有MQ产品并没有提供主动解决幂等性的机制,需要由消费者自行控制。
RocketMQ: 给每个消息分配了个MessageID。这个MessageID就可以作为消费者判断幂等的依据。这种方式不太建议。
最好的方式就是自己带一个有业务标识的ID,来进行幂等判断。如OrderID。
统一ID分配。
4、死信队列、延时队列
满足以下条件的消息,会进入死信队列:
- 消息被消费方否定确认,使用 channel.basicNack 或 channel.basicReject ,并且此时requeue 属性被设置为 false 。
- 消息在队列的存活时间超过设置的TTL时间。
- 消息队列的消息数量已经超过最大队列长度。
那么该消息将成为“死信”。
“死信”消息会被RabbitMQ进行特殊处理,如果配置了死信队列信息,那么该消息将会被丢进死信队列中,如果没有配置,则该消息将会被丢弃为每个需要使用死信的业务队列配置一个死信交换机,这里同一个项目的死信交换机可以共用一个,然后为每个业务队列分配一个单独的路由key,死信队列只不过是绑定在死信交换机上的队列,死信交换机也不是什么特殊的交换机,只不过是用来接受死信的交换机,所以可以为任何类型【Direct、Fanout、Topic】。
TTL:一条消息或者该队列中的所有消息的最大存活时间
如果一条消息设置了TTL属性或者进入了设置TTL属性的队列,那么这条消息如果在TTL设置的时间内没有被消费,则会成为“死信”。如果同时配置了队列的TTL和消息的TTL,那么较小的那个值将会被使用,只需要消费者一直消费死信队列里的消息。
需要延迟处理的消息,交给延迟队列来完成。
如超时未支付,30分钟后取消订单,解锁库存。
方案:1、定时任务扫描 订单表 比较下单时间的差异和支付状态等,消耗cpu资源。调度。
2、消息队列的延迟队列 到时自动触发。