第十三章 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. 方案二

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

核心代码

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

相关推荐
道一云黑板报2 小时前
Flink集群批作业实践:七析BI批作业执行
大数据·分布式·数据分析·flink·kubernetes
飞来又飞去4 小时前
kafka sasl和acl之间的关系
分布式·kafka
MZWeiei5 小时前
Zookeeper的监听机制
分布式·zookeeper
莹雨潇潇5 小时前
Hadoop完全分布式环境部署
大数据·hadoop·分布式
浩哲Zhe6 小时前
RabbitMQ
java·分布式·rabbitmq
明达技术6 小时前
分布式 IO 模块:赋能造纸业,革新高速纸机主传动
分布式
Allen Bright7 小时前
RabbitMQ中的Topic模式
分布式·rabbitmq
李洋-蛟龙腾飞公司8 小时前
HarmonyOS Next 应用元服务开发-分布式数据对象迁移数据权限与基础数据
分布式·华为·harmonyos
rainoway9 小时前
CRDT宝典 - Multi-Value-Register
前端·分布式·算法
Allen Bright10 小时前
Spring Boot 整合 RabbitMQ:手动 ACK 与 QoS 配置详解
spring boot·rabbitmq·java-rabbitmq