史上最简单的RabbitMQ教程 | 第三篇: RabbitMQ高级特性之保证消息可靠性投递和消费
保证消息的可靠性投递和消费,将分为两部分来进行,第一部分来描述消息的可靠性投递,包含目前流行的两种可靠性投递架构,第二部分将描述消息的可靠性消费,包含消息幂等性介绍等。第三部分将结合RabbitMQ来讲述下怎么保证消息不丢失。通过本篇的学习,可以学习到消息可靠性的投递、消费以及怎样保证消息不丢失。
消息可靠性投递
执行步骤:
1. 保障消息成功发出
2. 保证MQ节点成功接收
3. 发送端收到消费端的确认应答
4. 完善的消息补偿机制
解决方案:
1. 业务和消息同时入库,对消息进行处理修改标记
2. 消息延迟投递,做二次确认,回调检查
可靠性投递方案一:消息入库,对消息打标
1. 流程图如下
2. 流程拆解
①:消息和业务记录入库
②:第一步正常执行完后,将消息发送个MQ
③:消息处理完,发送确认消息给MQ
④:更新消息的状态
⑤:定时任务读取消息的状态
⑥:如果消息处理工程,流程结束,否则读消息重发MQ
⑦:重试次数内,重复执行流程;超过重试次数,将数据库更新状态
⑧:补偿系统,解决超过重试次数消息,保障消息的100%投递
3. 方案问题
两次数据入库,不适合在高并发场景使用。
可靠性投递方案二:消息延迟发送,做二次检查,回调检查
1. 流程图如下
2. 流程拆解
①:业务记录入库,业务记录正常入库后向MQ发送消息
②:第二次消息延迟3-5分钟,向MQ发送消息
③:消费监听队列,消费消息
④:消费者消费完后,发送确认消息给MQ的一个队列
⑤:另外一个服务监听消费者发送的confirm消息,如果正常完成,消息入库。
⑥:另外服务,经停延迟发送的队列,那消息检查msg数据库,如果没有,将再msg上新插入一条消息,用来记录重试次数
⑦:延迟检查成功,不需要任何操作;如果检查不成功,将通知服务,重新发消息给MQ
⑧:补偿系统,解决超过重试次数消息,保障消息的100%投递
消息可靠性消费-不重复消费
消息保证不重复消费,就要保证消息的幂等性,什么是幂等性?
幂等性:指消息执行一次和执行多次的结果相同,就说明消息是幂等的。
保证消息幂等性:
1. 通过数据库主键形式(ID+指纹码)
2. 使用Redis原子性保证幂等性
保证幂等性方案一:通过数据库主键形式(ID+指纹码)
指纹码:是唯一的系统码,可以是内部规则(如时间戳)和外部返回(如银行流水号),通过指纹码和全局唯一ID做主键,利用数据库主键进行去重。
使用指纹码避免用户在一个唯一主键可能因为网络延迟等问题,对数据库进行多次写操作。
1. 实现
select * from table where id=唯一id+指纹码
实现简单,但在高并发情况下存在数据库写入性能的瓶颈。多余指纹码加大主键长度影响存储。
2. 解决方案
数据库采用分库分表,将id根据规则分布到不同的数据库表中,单一数据库分流降压。
保证幂等性方案二:利用Redis原子性操作保证幂等性
1. 实现
这种性能高,Redis是基于内存,不会造成数据库瓶颈。
2. 问题
①Redis数据库是否需要入库,怎样保证数据库和Redis中数据一致性(一般保证幂等是不需入库)
②如果不入库,怎样保证定时清理策略,缓存得可靠性保证(高可用-集群,定期清理策略)
RabbitMQ保障消息的可靠性传输
可靠性传输就是保证不丢失数据,丢失数据一般分为两部分,分别是MQ丢失数据,另外是我们生产消费消息时丢失数据。具体细分的包含生产者保证消息不丢失,MQ保证消息不丢失和消费者保证消息不丢失。
消息可靠性传递一:生产者保证消息不丢失
生产者保证数据不丢失可以采取两种方式:
1. 使用RabbitMQ事务,在发送消息之前开启事务(channel.txSelect),正常发送后提交事务(channel.txCommit),如果出现异常,需要回滚事务(channel.txRollback)做消息重发等操作
缺点:RabbitMQ事务采用同步的方式进行事务处理,提交一个事务后,事务阻塞在哪,只有等这个事务执行完才能执行下一个事务,严重影响RabbitMQ性能,在 实际生产中不使用。
2. 使用confirm模式,生产者开始confirm模式后,每次写数据会分配唯一id,当消息成功处理,将回传ack,消息处理失败,回传nack。
优点:采用异步模式,消费者发送一条消息后,不用等消息回传消息,就可以发送下一条消息,RabbitMQ将异步接受这条回传信息,如果是nack,将进行消息重试。实际生产中使用这种方式。
类型:普通Confirm模式 批量Confirm模式 异步Confirm模式,将再以后的博客中详细介绍3中不同的confirm类型
消息可靠性传递二:RabbitMQ保证消息不丢失
保证RabbitMQ消息不丢失,需要两步操作;
1. 创建queue时,将queue设置为持久化,
2. 发送消息的时,设置消息的deliveryMode=2。
即使这样操作,还可能存在,消息写到RabbitMQ中,但是消息没有持久化磁盘,这是服务器重启,这部分数据丢失。
消息可靠性传递三:消费者保证消息不丢失
消费端关闭自动应答,设置手动应答。
autoAck=false; 这样保证消费者消费消息后,删除RabbitMQ中数据。
小结
1. 两种可靠性投递,第一种执行简单,但是不适合高并发环境;第二种执行复杂,但是减少一次数据入库,性能会有提高,适合高并发环境。如果MQ所在的服务器宕机,MQ中没有及时消费的数据会丢失
2. 保证幂等性可以采用两种方式,第一种是主键方式,第二种采用Redis原子性,根据业务场景的不同来选择。
3. 详细讲解RabbitMQ的消息可靠性传递,并从生产者,消费者和RabbitMQ来保证消息不丢失。