RabbitMQ主要有以下高级特性
-
可靠性投递(100%投递成功)
-
幂等性(解决重复消费)
-
confirm机制、return机制
-
自定义消费者
-
消息的Ack和重回队列
-
消息限流
-
TTL消息
-
死信队列
100%投递成功(可靠性投递)
生产端的可靠性投递
- 保证消息成功发送
- 保障MQ节点成功接收
- 发送端收到MQ的Ack
- 完善的消息进行补偿机制
解决方案
- 方法一: 消息入库、对消息状态标记
- 方法二: 消息的延迟投递、二次确认、回调检查
方法1:消息入库、定时任务补偿
biz/MsgDB -> sender -> mq broker -> confirm Listener -> MsgDB
schedule -> MsgDB -> retry sender -> retry count -> MsgDB
方法二:消息和数据库无关、延迟投递、二次确认
幂等性
消息端多次消费保障结果不会累计
数据表保障唯一性
- 使用业务唯一ID区分,保障操作的唯一性
- 好处:实现简单
- 坏处:高并发有数据库写入瓶颈
- 解决方案:分库分表查询、路由
- 利用redis原子性、分布式锁
- 使用数据库和缓存 保障原子性
- 不使用数据库,只使用缓存
confirm 确认消息
消息的确认:
broker给producer的confirm报文。
step1: 开启确认模式 channel.confirmSelect()
step2: 在channel添加监听 addConfirmListener
return 机制
return listener 用于处理不可路由的消息
生产者监听不可达的消息
在基础API有一个关键配置项:
Mandatory
如果为true,则监听器接收到路由不可达的消息,然后进行后续处理;如果为false则broker自动删除这些消息。
消费端自定义监听
consumer 继承 DefaultConsumer
实现 handleDelivery
消费端的限流
由于高并发或延迟,导致队列中堆积巨量的消息。
然后这巨量的消息全部推送给消费者,但是单一的消费客户端无法同时处理这巨量的消息。
auto ack 设为 false
basic qos
Rabbitmq提供了一种Qos(服务质量保证)的功能。即在非自动确认的前提下,如果一定数目的消息未被确认前,不进行消费。
basicQos(unit prefetchSize,ushort prefetchCount,bool global)
TODO
: 搞清楚这里的含义,怎么设置的
- prefetchSize: 一次拿多少条消息
- prefetchCount: 当有N条消息未ACK,consumer block ,自动应答时,该设置不生效。
- global: true基于channel false:基于consumer
消费端的ACK和重回队列
消费端的手工ACK和NACK
/ * nack
* @param deliveryTag 标签
* @param multiple true 批量处理
* @param requeue true 重回队列 扔到队尾
*/
channel.basicNack(envelope.getDeliveryTag(), false, true);
/**
* ack
*/
channel.basicAck(envelope.getDeliveryTag(),false);
复制代码
注意:重回队列(requeue)和死信队列(dead letter)区别
TTL 生存时间
消息的生存时间有2种
- 发送时指定消息本身指定的生存时间
- 队列中消息保持的时间:消息进入队列开始计算
队列参数
arguments
- Message TTL
- Max Lenth
死信队列
DLX、Dead-Letter-Exchange
定义:利用DLX 当消息在一个队列中变成死信后,它能重新push到另一个exchange,这个exchange称为DLX。
消息变成死信的情况
- 消息被拒绝(basic.reject\basic.nack),且requeue = false
- ttl过期,消息过期
- 队列达到最大长度
DLX是正常的exchange和其他没什么区别,能在任何队列上指定
当队列中有死信时,rabbitMq自动将这个消息重新发布到设置的exchange,被路由到另一个队列。
可以监听死信队列做相应的处理
Exchange:cdlx.exchange Queue:dlx.queue RoutingKey:#
x-dead-letter-exchange
dlx.exchange
死信队列使用流程图: