Rabbitmq消息补偿机制

消息补偿机制

1、SpringBoot 封装的补偿机制

在 SpringBoot 为 RabbitMQ 封装的依赖中,提供一种补偿机制,如果发出的消息在一段时间内没有响应(签收或者拒绝),那么该消息就会进行重发。默认情况下会隔5秒一直进行重发,直到消费者响应。

我们可以通过自定义配置参数来修改默认的补偿机制

spring: rabbitmq: listener: simple: retry: enabled: true # 自动触发补偿机制 max-attempts: 5 # 补偿机制尝试次数 max-interval: 10000 # 重试最大间隔时间 initial-interval: 2000 # 重试初始间隔时间 multiplier: 2 # 间隔时间乘子,间隔时间*乘子=下一次的间隔时间,最大不能超过设置的最大间隔时间

2、自定义补偿机制。对于封装的补偿机制存在一些不足,因为其是无差别补偿,也就是只要消费者没有响应就会重发,但是对于一些异常导致没有响应即使发几次都会导致没有响应(如数据计算异常,数据类型转换异常),这样的补偿机制就会消耗 CPU 资源。所以对于这些异常可以捕获然后直接处理。对于其他异常(如调用第三方接口失败)则可以进行补偿重试。

对于MQ 整个模块的补偿机制,可以参考下面的架构图

各步骤:

1、发生业务操作,业务数据写入数据库

2、生产者将消息发送给MQ的队列Q1

3、发送了一条与step2中一摸一样的延迟消息到对了Q3

4、消费者监听Q1,获取到了step2中发送的业务消息

5、消费者在收到生产者的业务消息后,发送了一条确认消息(记录收到的消息信息)到Q2

6、回调检查服务监听了Q2,获取到了消费者发送的确认消息

7、回调检查服务将这条确认消息写入数据库等待之后的比对

8、Q3中的延迟消息延迟时间已到,被回调检查服务接收到,之后就拿着这条延迟消息在数据库中比对,如果比对成功,证明消费者接收到了生产者的业务消息并处理成功(如果不处理成功谁会傻了吧唧发送确认消息呢);如果比对失败,证明消费者没有接收到生产者的业务消息,或者说消费者接收到了业务消息之后始终没有处理成功相关的业务并发送确认消息。这时回调检查服务就会调用生产者的相关业务接口,让生产者再次发送这条失败的消息

9、有一种最极端的情况,step2和step3的消息都发送失败了或者说在消息传递过程中发生意外丢失了!定时检查服务会一直轮询保存确认消息的数据库中的消息数据,并于生产者的业务数据库中的业务数据进行比对,如果两者比对数量一致,则代表业务执行没有问题;如果比对不一致,确认消息数据库的数据量小于生产者业务数据量的话,就证明消费者没有接收到生产者发送的消息。这时定时检查服务会通知生产者再次发送消息到MQ的队列Q1

消息幂等性

由于消息补偿机制的存在,可以更加有效保证消息可以被消费,但是带来的问题是可能某个消息执行的比较久,导致同一条消息再次被发送给了消费者,而前一条消息顺利执行完,这样一条消息就会被多次执行,所以消费者端的方法需要涉及成幂等性,也就是对于一条消息,无论被消费者消费几次,效果都是一样的。实现方案主要有两种。

1、唯一ID+指纹码。

唯一ID指的是使用 UUID、或者操作数据的主键,而指纹码是与业务相关的ID,比如雪花算法就是根据当前时间戳生成的,生成的ID就属于指纹码。

在生产者发送时创建 Messgae 对象,将业务数据以及唯一ID+指纹码保存到Meaasge对象中进行发送

Message message = MessageBuilder.withBody(msg.getBytes()).setContentType(MessageProperties.CONTENT_TYPE_JSON) .setContentEncoding("utf-8").setMessageId(UUID.randomUUID() + "").build(); amqpTemplate.convertAndSend(queueName, message);

然后在消费者端接收,获取ID,在消费者消费最后以其为主键添加到mysql中,在业务开始时检查是否存在,不存在继续执行。

缺点是高并发场景下会受到性能瓶颈限制。可以通过分库分表解决。

2、redis 操作。

在消费者方法开始使用 redis 的 setnx 方法来处理判断数据可以一步到位,是实现幂等性的最佳方案。

消息顺序执行

如果多个消费者监听同一个队列,那么默认下消息会依次顺序分配给消费者。

上面提到预取值概念,通过配置消费者端的 channel 的 basicQos 参数来修改,但是这会收到消费者执行快慢、生产者发送消息到队列的顺序等因素影响,所以并不可靠。

所以实现消息顺序执行的方式就是增加队列,拆分消费者,使每个消费者只监听一个队列。

相关推荐
Boilermaker19928 小时前
【MySQL 进阶】高性能优化
数据库·sql·mysql
CoderOnly9 小时前
SQL,CROSS JOIN速度优化
数据库·sql·mysql
Highcharts.js9 小时前
入门指南|从文件到图表:Highcharts对接数据库(CSV、Excel)实现数据同步绘制图表
数据库·excel·数据同步·highcharts·数据对接·文件导入
老衲提灯找美女11 小时前
MySQL的增删改查功能合集
数据库·mysql·增删改查·增删改查详细用法
小马爱打代码12 小时前
MyBatis:性能优化实战 - 从 SQL 优化到索引设计
sql·性能优化·mybatis
SelectDB12 小时前
Apache Doris 4.0.1 版本正式发布
数据库·apache
Doro再努力12 小时前
MySQL数据库07:分组查询与分类查询
数据库·mysql
Elastic 中国社区官方博客13 小时前
Elasticsearch:如何为 Elastic Stack 部署 E5 模型 - 下载及隔离环境
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
间彧13 小时前
SpringBoot + MyBatis-Plus + Dynamic-Datasource 读写分离完整指南
数据库·后端
静若繁花_jingjing14 小时前
NoSql数据库概念
数据库·nosql