第十三章 RabbitMQ之消息幂等性

目录

一、引言

二、消息幂等解决方案

[2.1. 方案一](#2.1. 方案一)

[2.2. 方案二](#2.2. 方案二)


一、引言

幂等是一个数学概念,用函数表达式来描述是这样的:f(x) = f(f(x)) 。在程序开发中,则是指同一个业务,执行一次或多次对业务状态的影响是一致的。有些业务天生就是幂等的,如查询和删除业务执行一次和多次的结果是一样的,而像用户下单、用户退款是非幂等业务。

实际项目开发中,我们在提交表单时,很多时候可能会重复提交表单,这个时候我们通过token令牌等唯一标识来解决,第一次提交页面将缓存中的唯一标识删除,后面再重新提交时缓存中的标识已经被删了因此重复提交失败。

我们在消息消费的过程中也会存在同样的问题,即如何来保障所有业务在接收RabbitMQ消息时保证业务的幂等性,避免消息重复消费呢?

二、消息幂等解决方案

2.1. 方案一

  1. 给每个消息都设置/生成一个唯一id,利用id区分是否是重复消息,与消息一起投递给消费者。

  2. 消费者接收到消息后处理自己的业务,业务处理成功后将消息ID保存到数据库

  3. 如果下次又收到相同消息,去数据库查询判断是否存在,存在则为重复消息放弃处理

核心代码:

我们可以在生产者和消费者两端分别声明消息转换器的Bean,本案例为了方便直接在启动类中声明消息转换器,并配置自动为消息创建id。

java 复制代码
package com.example.consumer;

import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

    @Bean
    public MessageConverter messageConverter(){
        // 1.定义消息转换器
        Jackson2JsonMessageConverter jjmc = new Jackson2JsonMessageConverter();
        // 配置自动创建消息id,用于识别不同消息,也可以在业务中基于ID判断是否是重复消息
        jjmc.setCreateMessageIds(true);
        return jjmc;
    }
}
java 复制代码
package com.example.publisher;

import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class PublisherApplication {

    public static void main(String[] args) {
        SpringApplication.run(PublisherApplication.class, args);
    }

    @Bean
    public MessageConverter messageConverter(){
        // 1.定义消息转换器
        Jackson2JsonMessageConverter jjmc = new Jackson2JsonMessageConverter();
        // 配置自动创建消息id,用于识别不同消息,也可以在业务中基于ID判断是否是重复消息
        jjmc.setCreateMessageIds(true);
        return jjmc;
    }
}

通过源码可以看到默认生成的是UUID:

通过RabbitMQ浏览器界面可以看到消息已经生成了一个唯一ID :

2.2. 方案二

结合业务逻辑,基于业务本身做判断。以余额支付业务为例,我们要在支付后修改订单状态为已支付,应该在修改订单状态前先查询订单状态,判断状态是否是未支付。只有未支付订单才需要修改,其他状态不做处理:

核心代码

上述代码可以通过乐观锁来实现,替换代码如下:

相关推荐
CodeGL1 天前
开源的分布式任务调度平台:XXL-Job
分布式·开源
一条泥憨鱼1 天前
【Kafka】零基础学习教程
java·分布式·学习·kafka
贾伟康1 天前
【共创稿事节】HarmonyOS 7.0 HiTraceChain分布式调用链:从接入到生产验证
分布式·harmonyos·可观测性·调用链·hitracechain
NiceZack2 天前
Hadoop 部署全流程教程:从新装 CentOS 到伪分布式与完全分布式
hadoop·分布式·centos
傻啦嘿哟2 天前
分布式爬虫架构:Redis+Scrapy打造企业级爬虫系统
分布式·爬虫·架构
starzy19902 天前
Kafka请求进门口:Processor是怎么把请求读上来的
分布式·kafka
骑着蜗牛撵大象3273 天前
558 万美元训出 671B 模型:DeepSeek-V3 算法与系统的协同拆解
分布式·算法·moe·deepseek-v3·mla·fp8训练
德迅云安全-上官3 天前
德迅游戏盾:面向 TCP 业务的分布式云安全防护方案
分布式·tcp/ip·游戏
未秃头的程序猿3 天前
@ConditionalOnMissingBean 把我配好的 RabbitMQ 手动 ack 吃掉了
后端·rabbitmq
麻瓜code3 天前
分布式锁演进:从一个用户下两单,到 Redisson,我改了四版
分布式·wpf