幂等问题

article/2025/9/25 10:17:06

点击↑上方↑蓝色“编了个程”关注我~

每周至少一篇原创文章

这是本公众号的第 34 篇原创文章

最近比较懒,好几周没写文章了。还是没能坚持每周更新,愧对关注我的读者和自己的flag。。。

不过还好调整了过来,还是会继续坚持周更的。毕竟学习是一件永无止境的事,用输出倒逼自己输入,才能有所沉淀和成长,欢迎大家监督和共勉~

这篇文章是介绍幂等的。幂等在分布式和高并发场景下是必须要考虑的一件事。如果不做幂等,轻则产生脏数据,重则产生业务异常,造成资产损失。

什么是幂等?

幂等原本是一个数学上的概念,表达的是N次变换与1次变换的结果相同。即公式:f(x)=f(f(x)) 成立。

用在编程领域,表达的是对于同一个系统,使用同样的条件,「一次请求和重复的多次请求对系统资源的影响是一致的」

一般来说,读操作天然都是幂等的(除非你的读操作有副作用),而写操作是不幂等的。但是有些业务场景我们需要做到写操作幂等,所以需要做一些额外的工作。

比如提交订单请求,有时候可能是同样一个订单,如果不做幂等,重复处理,就有可能会造成用户或者公司的资产损失。

幂等在并发量较高的项目中是一个经常会遇到的问题。主要有以下两种场景会遇到幂等问题:

  1. 请求重复提交/消息重复提交

  2. 失败重试

下面分别谈谈这两种场景的具体的解决方案。

重复提交下的幂等

重复提交,很大的概率是前端设计不合理或者客户端网络问题,导致用户连续提交多次相同的内容。对于这种场景,可以在前端改善用户交互,在后端也可以简单地判重和拒绝。这种场景比较适合在外围做幂等,直接把请求拒绝或者pass,不用把请求放到业务内部。应该做成一种较为通用的能力。

从前端防止用户重复提交

前端交互很重要,因为用户其实并不管幂等不幂等,有时候客户端可能由于手机卡死或者网速较慢,提交了迟迟得不到反馈,可能会疯狂点击提交按钮,导致产生大量的重复请求。

常用的解决方案有:跳转到其它页面,如订单提交后跳转到提交成功页面;点击提交按钮后「清空内容」,适用于评论、回复等业务场景。还有「按钮置灰」等设计。

我的个人网站上可以找到类似的例子,比如评论组件,评论提交后,会将提交按钮置灰60秒。

评论前端按钮置灰

比如点赞组件,对一篇点赞后也会有一段时间的防重限制,防止用户疯狂点击。

前端限制

使用缓存实现重复提交幂等

要解决重复提交幂等的方案很简单,用缓存来做就行了。我们把请求参数(JSON序列化为字符串)或者请求参数中的业务唯一ID作为key,存进缓存里。后续如果有其它一样的请求过来,就先去缓存里面查,如果存在,就直接跳过或者返回。

重复提交幂等

这里有一个问题,如果写操作有返回值怎么办?比如我们经常会有这样的设计:数据库的主键是自增的,往数据库插入一条新的记录,持久层会返回我们新插入记录的ID,而我们后续的程序会需要用到这个ID。

如果要实现幂等,肯定是第一时间写进缓存key,DB生成ID返回后,再把它插入到缓存的value里。中间有个时间差,如果这个时间差内,其它的请求过来了怎么办?

对于这个问题,如果业务上允许后续的请求直接报错,那可以直接抛异常出去,比如提示用户:订单提交失败。但这样通常对用户来说并不友好。另一种解决方案是,「提前生成ID,ID通过参数传进去」,而不是用DB生成,这样写操作就不会存在这个问题了。「而生成ID的是一个很快的读操作,对这个读操作也可以做一个幂等,保证短时间内,同样的请求参数,只生成同一个ID」

单机幂等还是分布式幂等,取决于我们用的是单机缓存还是分布式缓存。大多数时候,如果我们的业务是分布式的系统,更建议用redis等分布式缓存来实现分布式幂等。

我们也可以实现一个很方便的幂等注解。其实原理很简单,自定义一个注解,用spring AOP加上缓存来实现幂等。也有现成的轮子:idempotent-spring-boot-starter,可以参考一下。

失败重试下的幂等

失败重试幂等其实也是会重复提交,但处理方式不同,不应该简单地拒绝掉,可能会只是某些步骤做幂等,但是请求会继续往后走,进入业务流程内部。比如提交订单,提交后会进行很多写操作,如优惠券状态修改、库存扣减、创建物流信息等。如果中途因为某种意外原因失败(比如网络原因等),可以进行重试。

而失败重试的时候,如果不做幂等,会产生问题。比如库存扣减操作,如果因为超时原因重试,可能会扣减两次库存,造成数据错误。但如果直接拒绝后面的请求也不妥,可能第一次请求确实是因为网络原因,处理失败了,第二次重试说不定就成功了,所以还是应该让后续的请求进来,采取其它措施来保证幂等。

失败重试幂等

对于失败重试场景下的幂等,下面也有一些解决方案。

唯一ID/token

为每一次操作都生成一个单独的唯一ID或者token(以下简称token)。一个token在操作的每一个阶段只有一次执行权,一旦执行成功则保存执行结果。对重复的请求,返回同一个结果。

在订单提交的场景,订单ID就可以作为一个token。每一个环节执行时都先检测一下该订单ID是否已经执行过这一步骤,对未执行的请求,执行操作并缓存结果,而对已经执行过的ID,则直接返回之前的执行结果,不做任何操作。

在写操作之前,还可以用这个token进行上锁,保证同一个token只进行一次写操作。

开源轮子可以参考:redis-auto-idempotent-spring-boot-starter

乐观锁

可以乐观锁的思想,利用版本号去做幂等,这个比较适用于更新操作。

每条数据都有一个版本号,数据更新的时候,传入获取到的版本号,且版本号+1。在实际进行写操作的时候,会去比较请求参数里面的版本号,每个version只有一次执行成功的机会,一旦失败必须重新获取。

UPDATE demo
SET count = count + 1, version = version + 1
WHERE id = 123 and version = 5;

防重表

利用数据库主键或者唯一索引的特性,保证相同的数据只会被写入一次。

比如在评论场景,我们可以把文章ID + 用户ID + 评论内容作为一个唯一键,那对于同一个文章,同一个用户,就不能提交多条相同的评论了。

但是个人「不推荐这种方式」。因为性能较差,而且DB的主键冲突,一般归于系统异常,如果用它来做去重,异常类型和日志不太好定义。

任务幂等

任务幂等,指的是对于同一段数据,触发一次任务和多次任务是相同的结果。

任务基本上都会涉及到写操作。如果同一段数据,被多次任务触发,进行了多次写操作,可能会造成脏数据。

其实也很好解决,我们在抽象任务模型的时候,给「任务设计好不同的状态」就行了。比如任务初始化、启动后、成功、失败、取消等都有不同的状态。后续的任务触发请求,如果监测到这段数据的状态已经做了修改,就根据这个任务的状态和用户定义

的策略,来决定是跳过还是重新执行。

可以参考Spring Batch的设计,Spring Batch抽象了Job这个概念,提供了BatchStatus枚举来作为任务的状态:

public enum BatchStatus {STARTING, STARTED, STOPPING, STOPPED, FAILED, COMPLETED, ABANDONED }

相应的,比Job粒度更小的Step也有自己的状态。同时Spring Batch可以允许用户自定义地配置skip策略和失败处理策略。

消息幂等

消息幂等也是经常要考虑的问题。还是之前电商系统中订单提交的例子,比如库存扣减这种操作,为了保证吞吐量,可能会使用消息来实现。

消息幂等的概念可以总结如下:

如果消息重试多次,消费者端对该重复消息消费多次与消费一次的结果是相同的,并且多次消费没有对系统产生副作用,那么我们就称这个过程是消息幂等的。

对于消息来说,发送端可能产生重复消息,消费端也可能会重复消费同一条消息(大多数都是因为网络问题)。如果靠消息中间件去实现幂等,是一件比较困难的事情,增加幂等的处理会导致消息中间件的「吞吐量」下降。所以绝大多数消息「消息中间件本身不处理幂等问题」,而是交给了业务端自己去处理。

而不论是发送端重复还是消费端重复,我们「只需要保证消费端幂等」就可以了,不需要在发送端做什么事情。而消费端做幂等,其实本质上也是上面提到的“「重复提交下的幂等」”,比较适合在消费端的入口处就做幂等处理。

关于作者

我是Yasin,一个在不断精进的菜鸡

微信公众号:编了个程(blgcheng)

个人网站:https://yasinshaw.com

这里很多技术干货,关注肯定不后悔

加个星标可以第一时间看到最新文章

听说,转发和在看的人都升职加薪了

原创不易,四连走起,

关注在看,评论转发,

感谢支持!

DDD之代码架构


Spring Cache,从入门到真香



http://chatgpt.dhexx.cn/article/OMfu4mK3.shtml

相关文章

常见的幂等性解决方案

背景 我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。 get请求一般没有幂等性需求、delete请求一般也没有幂等性需求,post、update视情况而定例如: 前端重复提交选中的数据,应该后…

彻底理解接口幂等性

目录 背景 1. 幂等性的概念 2.什么情况需要处理接口幂等性问题? 2.1 select 天然自带幂等性。 2.2 insert 当我们重复插入数据的时候,会出现什么情况 ? 2.3 delete 是否具有幂等性? 2.4 update 猜一猜是否具有天热幂等性&a…

【实战】聊聊幂等设计

前言 大家好,今天我们一起来聊聊幂等设计。 什么是幂等为什么需要幂等接口超时,如何处理呢?如何设计幂等?实现幂等的8种方案HTTP的幂等1. 什么是幂等? 幂等是一个数学与计算机科学概念。 在数学中,幂等用函数表达式就是:f(x) = f(f(x))。比如求绝对值的函数,就是幂等…

幂等性 详解

目录 一、幂等概念 1、幂等的数学概念 2. 幂等的业务概念 二、幂等概述 三、幂等场景 四、解决方案 1、token redis机制 2、乐观锁机制 3、唯一主键机制 4、去重表机制 5、门票机制 一、幂等概念 1、幂等的数学概念 如果在一元运算中,x 为某集合中的任…

幂等 (idempotence) 的概念

幂等 (idempotence) 的概念 幂等的数学概念 幂等是源于一种数学概念。其主要有两个定义 如果在一元运算中,x 为某集合中的任意数,如果满足 f(x) f(f(x)) ,那么该 f 运算具有幂等性,比如绝对值运算 abs(a) abs(abs(a)) 就是幂…

偏度

偏度公式如下: 现在想解决如何从图像上解决为正为负的问题,如图所示: 个人理解:偏度中的偏是针对变量相对于中心点(期望值)距离的一种描述;如果厚尾的话,就说明有很多点距离中心点比…

偏度(skewness)

偏度 偏度(skewness),是统计数据分布偏斜方向和程度的度量,是统计数据分布非对称程度的数字特征。定义上偏度是样本的三阶标准化矩。 偏度定义中包括正态分布(偏度0) 算术平均值 中位数 众数,…

策略梯度

Policy Gradient Methods for Reinforcement Learning with Function Approximation(PG) 在强化学习的算法中存在两种算法,一个是基于价值函数的算法,另一个是基于策略梯度的算法。为什么要提出策略梯度算法呢? 基于策略的学习可能会具有更好…

推荐系统中的偏差

推荐系统消偏 推荐系统中的偏差IPW ——逆概率加权DICE ——区分兴趣和偏差建模因果推断 推荐系统中的偏差 预估问题 我们一般会注重两种误差,偏差和方差, 方差与模型泛化能力有关:通常关注模型的复杂度与是否过拟合;偏差则表现为…

特征偏度和异常值处理

(一)机器学习基础 - 偏度、正态化以及 Box-Cox 变换 https://my.oschina.net/mathinside/blog/4942126 对于数据挖掘、机器学习中的很多算法,往往会假设变量服从正态分布。例如,在许多统计技术中,假定误差是正态分布…

推荐系统去偏(Debiased Recommendation)研究进展概述

©作者 | 张景森 学校 | 中国人民大学信息学院硕士 文章来源 | RUC AI Box 引言 推荐系统作为解决信息过载的一种重要手段,已经在不同的应用场景下取得了不错的效果。近些年来关于推荐系统的研究主要集中在如何设计更好的模型来适应用户行为数据,进而…

【综述】推荐系统偏差问题 去偏最新研究进展(Bias and Debias in Recommender System)

文章目录 1. 推荐系统的反馈回路1.1 User -> Data1.2 Data -> Model1.3 Model -> User 2. 推荐系统中的Bias2.1 数据偏差(data bias)2.1.1 选择偏差(Selection Bias)2.1.2 曝光偏差(Exposure Bias)2.1.3 一致性偏差(Conformity Bias)2.1.4 位置偏差(Position Bias) 2.…

数据偏度介绍和处理方法

偏度(skewness)是用来衡量概率分布或数据集中不对称程度的统计量。它描述了数据分布的尾部(tail)在平均值的哪一侧更重或更长。偏度可以帮助我们了解数据的偏斜性质,即数据相对于平均值的分布情况。 有时,正…

【期权系列】基于偏度指数的择时分析

【期权衍生指标系列】基于偏度指数的择时分析 本篇文章是基于研究报告的复现作品,旨在记录个人的学习过程和复现过程中的一些思路。 感谢中信期货研究员前辈的宝贵思路。 一、偏度指数 1.偏度指数简介 偏度是描述数据分布形态的统计量,其描述的是统…

对于偏度的理解

偏度公式如下: 现在想解决如何从图像上解决为正为负的问题,如图所示:? 个人理解:偏度中的偏是针对变量相对于中心点(期望值)距离的一种描述;如果厚尾的话,就说明有很多点…

量化策略研究:股票中的偏度效应

2022年4月份以来,加密货币市场的暴跌强调了市场中性策略的重要性;基于此,有部分Quanter提出了基于加密货币的偏度策略:“Skewness/Lottery Trading Strategy in Cryptocurrencies”。 为此,小编不禁好奇:偏…

Maven安装和配置(详细版)

Maven安装和配置 Maven安装1、安装链接:2、配置环境变量: Maven配置1、修改Maven仓库下载镜像及修改仓库位置:2、在Idea上配置Maven: 测试Maven安装能否安装jar包 Maven安装 1、安装链接: Maven – Download Apache …

Maven 安装/学习入门详解!

Maven安装: Maven 软件的下载 为了使用 Maven 管理工具,我们首先要到官网去下载它的安装软件。通过百度搜索“Maven 点击 Download 链接,就可以直接进入到 Maven 软件的下载页面: 我们当时使用的是 apache-maven-3.5.2 版本&a…

Maven安装(超详解)

2.4.1 下载 下载地址:Maven – Download Apache Maven 在提供的资料中,已经提供了下载好的安装包。如下 : 2.4.2 安装步骤 Maven安装配置步骤: 解压安装 配置仓库 配置Maven环境变量 1、解压 apache-maven-3.6.1-bin.zip&a…

Maven安装教程详解

一、准备工作 1、确定电脑上已经成功安装jdk7.0以上版本 2、win10操作系统 3、maven安装包 下载地址:http://maven.apache.org/download.cgi 二、解压Maven安装包 在上述地址中下载最新的Maven版本,解压到指定目录(此处根据自己的…