浅谈网络中接口幂等性设计问题

2023-05-16

所谓幂等性设计,就是说,一次和多次请求某一个资源应该具有同样的副作用。用数学的语言来表达就是:f(x) = f(f(x))。

在数学里,幂等有两种主要的定义。 在某二元运算下,幂等元素是指被自己重复运算(或对于函数是为复合)的结果等于它自己的元素。

某一元运算为幂等的时,其作用在任一元素两次后会和其作用一次的结果相同。


文章目录

    • 一、关于幂等性
        • 1、幂等的定义
        • 2、幂等的必要性
        • 3、幂等性
    • 二、对于幂等性的实现
        • 1、源头上--控制重复请求(前端防重)
        • 2、过程上--过滤重复动作
        • 3、结果上--解决重复写风险


一、关于幂等性

1、幂等的定义

所谓幂等性设计,就是说,一次和多次请求某一个资源应该具有同样的副作用。用数学的语言来表达就是:f(x) = f(f(x))。

下面是维基百科中对于幂等的定义:

在数学里,幂等有两种主要的定义。 在某二元运算下,幂等元素是指被自己重复运算(或对于函数是为复合)的结果等于它自己的元素。

某一元运算为幂等的时,其作用在任一元素两次后会和其作用一次的结果相同。

百度百科上是这么说的:

在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。

幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。

简而言之,幂等是指:多次调用方法或者接口不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致。

2、幂等的必要性

根据上面对幂等性的定义我们得知:产生重复数据或数据不一致,这个绝大部分是由于发生了重复请求。

这里的重复请求是指同一个请求在一些情况下被多次发起。

在接口调用时一般情况下都能正常返回信息不会重复提交,不过在遇见以下情况时可能就会出现问题,如:

  • 微服务架构下,不同微服务间会有大量的基于 http,rpc 或者 mq 消息的网络通信。如果超时了,微服务框架会进行重试;
  • 用户交互的时候多次点击,无意地触发多笔交易;
  • MQ消息中间件,消息重复消费;
  • 第三方平台的接口(如:支付成功回调接口),因为异常也会导致多次异步回调;
  • 其他中间件/应用服务根据自身的特性,也有可能进行重试。

举几个支付时的例子:

  • 订单创建接口,第一次调用超时了,然后调用方重试了一次。是否会多创建一笔订单?
  • 订单创建时,我们需要去扣减库存,这时接口发生了超时,调用方重试了一次。是否会多扣一次库存?
  • 当这笔订单开始支付,在支付请求发出之后,在服务端发生了扣钱操作,接口响应超时了,调用方重试了一次。是否会多扣一次钱?

因为系统超时,而调用户方重试一下,会给我们的系统带来不一致的副作用。

3、幂等性

幂等性主要保证多次调用对资源的影响是一致的。其本质是通过唯一标识,标记同一操作的方式,来消除多次执行的副作用。

下一用 SQL DML 命令来理解幂等性操作:

  • 查询(SELECT):查询语句不会对数据产生任何变化,天然具备幂等性;
  • 新增(INSERT):带有唯一索引,重复插入会导致后续执行失败,具有幂等性;不带有唯一索引,多次插入会导致数据重复,不具有幂等性;
  • 修改(UPDATE):直接赋值(score = 1),不管执行多少次 score 都一样,具备幂等性;计算赋值(score = score + 1),每次操作 score 数据都不一样,不具备幂等性;
  • 删除(DELETE):绝对值删除(DELETE FROM … WHERE …),重复多次结果一样,具备幂等性;相对值删除(DELETE top(3) FROM …),重复多次结果不一致,不具备幂等性。

二、对于幂等性的实现

总的来说,我们解决幂等性问题就是要控制对资源的写操作,因此我们可以通过控制重复请求、过滤重复动作、解决重复写风险三种方式分别在源头、过程以及结果上对幂等性问题进行分析解决。

1、源头上–控制重复请求(前端防重)

通过前端防重保证幂等是最简单的实现方式,前端相关属性和JS代码即可完成设置。可靠性并不好,有经验的人员可以通过工具跳过页面仍能重复提交。主要适用于表单重复提交或按钮重复点击。

主要解决方案**:**

  • 控制操作次数,例如:提交按钮仅可操作一次(提交动作后按钮置灰)
  • 及时重定向,例如:下单/支付成功后跳转到成功提示页面,这样消除了浏览器前进或后退造成的重复提交问题。

2、过程上–过滤重复动作

# PRG 模式(前端)

PRG 模式即 POST-REDIRECT-GET。当用户进行表单提交时,会重定向到另外一个提交成功页面,而不是停留在原先的表单页面。这样就避免了用户刷新导致重复提交。同时防止了通过浏览器按钮前进/后退导致表单重复提交。 是一种比较常见的前端防重策略。

# 分布式锁

利用 Redis 记录当前处理的业务标识,当检测到没有此任务在处理中,就进入处理,否则判为重复请求,可做过滤处理。

订单发起支付时,支付系统先去 Redis 中查询是否存在该订单号的 Key。若不存在,则在 Redis 中新增这个Key。

接着查询订单是否已支付,若未支付,则支付完成后删除该订单的Key。

通过Redis做分布式锁,只有当一个请求执行完成后,才能执行下个请求。

# Token 机制实现

通过 Token 机制实现接口的幂等性,这是一种比较通用性的实现方法。

具体流程步骤:

  1. 客户端先发送一个请求去获取 Token,服务端会生成一个全局唯一的 ID 作为 Token 保存在 Redis 中,同时把这个 ID 返回给客户端;
  2. 客户端第二次调用业务请求的时候必须携带这个 Token;
  3. 服务端校验这个 Token,如果校验成功,则执行业务,并删除 Redis 中的 Token;
  4. 如果校验失败,说明 Redis 中已经没有对应的 Token,表示重复操作,直接返回指定的结果给客户端。

# 防重表

对于防止数据重复提交,还有一种解决方案就是通过防重表实现。防重表的实现思路也非常简单。首先创建一张表 作为防重表,同时在该表中建立一个或多个字段的唯一索引作为防重字段,用于保证并发情况下,数据只有一条。 在向业务表中插入数据之前先向防重表插入,如果插入失败则表示是重复数据。

  • 对于防重表的解决方案,可能有人会说为什么不使用悲观锁。悲观锁在使用的过程中也是会发生死锁的。悲观锁是 通过锁表的方式实现的。 假设现在一个用户 A 访问表 A(锁住了表 A),然后试图访问表 B;
  • 另一个用户 B 访问表 B(锁住了表 B),然后试图访问表 A。 这时对于用户 A 来说,由于表 B 已经被用户 B 锁住了,所以用户 A 必须等到用户 B 释放表 B 才能访问。 同时对于用户 B 来说,由于表 A 已经被用户 A 锁住了,所以用户 B 必须等到用户 A 释放表 A 才 能访问。此时死锁就已经产生了。

3、结果上–解决重复写风险

常见的方式有:悲观锁(for update)、乐观锁、唯一约束。

# 悲观锁

假设每一次拿数据,都有认为会被修改,所以给数据库的行或表上锁。

当数据库执行 select for update 时会获取被 select 中的数据行的行锁,因此其他并发执行的 select for update 如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。

# 乐观锁

就是很乐观,每次去拿数据的时候都认为别人不会修改。更新时如果 version 变化了,更新不会成功。

缺点:就是在操作业务前,需要先查询出当前的 version 版本。

另外,还存在一种:状态机控制

例如:支付状态流转流程:待支付 -> 支付中 -> 已支付

具有一定要的前置要求的,严格来讲,也属于乐观锁的一种。

# 唯一约束

这种实现方式是利用 mysql 唯一索引的特性。

  • 因为表中某个字段带有唯一索引,如果插入成功,证明表中没有这次请求的信息,则执行后续的业务逻辑;
  • 如果插入失败,则代表已经执行过当前请求,直接返回。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

浅谈网络中接口幂等性设计问题 的相关文章

随机推荐

  • RabbitMQ:订阅模型-匹配模式

    阅模型 匹配模式 xff0c 相比于前两种订阅模型 xff0c 是更细致的分组 xff0c 允许 在RoutingKey 中使用匹配符 xff1a 匹配一个单词 xff1a 匹配0个或多个单词 RabbitMQ 订阅模型 匹配 xff08
  • 分布式理论协议与算法 第一弹 CAP理论

    CAP 理论 xff0c 也被称为 CAP 协议 xff0c 指的是在一个分布式系统中 xff0c 最多只能同时满足 一致性 xff08 Consistency xff09 可用性 xff08 Availability xff09 和 分区
  • MongoDB:基础概述

    MongoDB 是一个开源的 跨平台的 面向文档的 基于分布式文件存储的数据库系统 xff0c MongoDB 是由 C 43 43 语言开发 xff0c 旨在为 Web 应用提供可扩展的高性能数据存储解决方案 在高负载的情况下 xff0c
  • MongoDB:安装配置

    MongoDB有两个服务器版本 xff1a MongoDB 社区版 和 MongoDB 企业版 此篇主要介绍 MacOS 下 MongoDB 社区版的安装 xff0c 在 版本 下拉列表中 xff0c 选择要下载的 MongoDB 版本 x
  • 我的三周年创作纪念日

    文章目录 一 CSDN 心路历程1 关于第一篇文章2 初拾 CSDN3 重逢 CSDN 二 CSDN 收获1 关于粉丝2 关于文章 三 文章创作工具分享1 Typora2 PicGo3 作图工具 四 憧憬 一 CSDN 心路历程 1 关于第
  • 购买公司股票 = 变相降薪?

    一些公司会扣除你部分薪金 xff0c 美名其曰购买公司股份 xff0c 为了让你放心 xff0c 也会在合同中写明退出机制 xff0c 例如 xff1a 离职是可原额退回 但当你真的要离职的时候 xff0c 这事情就变得很扯皮了 其实让你入
  • MongoDB:常用命令

    本篇内容主要介绍 xff1a MongoDB 数据库命令 MongoDB 集合命令 MongoDB 文档命令 MongoDB 文档查询拓展 文章目录 一 MongoDB 数据库命令1 启动 MongoDB2 连接 MongoDB3 获取帮助
  • 分布式理论协议与算法 第二弹 ACID原则

    ACID 原则是在 1970年 被 Jim Gray 定义 xff0c 用以表示事务操作 xff1a 一个事务是指对数据库状态进行改变的一系列操作变成一个单个序列逻辑元操作 xff0c 数据库一般在启动时会提供事务机制 xff0c 包括事务
  • MongoDB:在 Java 中使用 MongoDB

    除了通过启动 mongo 进程进如 Shell 环境访问数据库外 xff0c MongoDB 还提供了其他基于编程语言的访问数据库方法 MongoDB 官方提供了 Java 语言的驱动包 xff0c 利用这些驱动包可使用多种编程方法来连接并
  • 分布式理论协议与算法 第三弹 BASE理论

    大部分人解释这 CAP 定律时 xff0c 常常简单的表述为 xff1a 一致性 可用性 分区容错性三者你只能同时达到其中两个 xff0c 不可能同时达到 实际上这是一个非常具有误导性质的说法 xff0c 而且在 CAP 理论诞生 12 年
  • Docker:独具魅力的开源容器引擎

    Docker 是一个开源的应用容器引擎 xff0c 让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中 xff0c 然后发布到任何流行的 Linux 或 Windows操作系统的机器上 xff0c 也可以实现虚拟化 容器是完全使用沙箱
  • 在不同环境下 Docker 的安装部署

    本篇内容主要介绍了 xff1a Docker xff1a 不同环境下的安装部署 xff0c 包括 xff0c Docker 在 Centos7 下的安装 Docker 在 MacOS 下的安装 Docker 在 Windows 下的安装 以
  • Docker 应用实践-镜像篇

    一个 Docker 镜像往往是由多个镜像层 xff08 可读层 xff09 叠加而成 xff0c 每个层仅包含了前一层的差异部分 xff0c 单个镜像层也往往可以看作镜像使用 xff0c 当我们启动一个容器的时候 xff0c Docker
  • 如何通过限流算法防止系统过载

    限流算法 xff0c 顾名思义 xff0c 就是指对流量进行控制的算法 xff0c 因此也常被称为流控算法 我们在日常生活中 xff0c 就有很多限流的例子 xff0c 比如地铁站在早高峰的时候 xff0c 会利用围栏让乘客们有序排队 xf
  • Docker 应用实践-容器篇

    在 Docker 镜像篇中 xff0c 我们了解到 Docker 镜像类似于模板 xff0c 那么 Docker 容器就相当于从模板复制过来运行时的实例 xff0c Docker 容器可以被创建 复制 暂停和删除等 每一个 Docker 容
  • Java中Json字符串和Java对象的互转

    JSON xff08 JavaScript Object Notation xff09 是一种轻量级的数据交换格式 诞生于 2002 年 易于人阅读和编写 同时也易于机器解析和生成 JSON 是目前主流的前后端数据传输方式 JSON 采用完
  • 老板必看:1.初创业团队没有激情,咋办? 2.小股东的选择

    内容摘要 xff1a 本文有两个来自真实情况的案例 xff0c 因为涉及到 私隐 xff0c 部分内容经过处理 两个案例分别是 xff1a 1 xff09 新创业团队员工积极性差的问题 xff1b 2 xff09 小股东在两大股东的斗法中的
  • 持续事务管理过程中的事件驱动

    比较官方的定义 xff1a 事件驱动是指在持续事务管理过程中 xff0c 进行决策的一种策略 xff0c 即跟随当前时间点上出现的事件 xff0c 调动可用资源 xff0c 执行相关任务 xff0c 使不断出现的问题得以解决 xff0c 防
  • Docker 应用实践-仓库篇

    目前 Docker 官方维护了一个公共仓库 Docker Hub xff0c 用于查找和与团队共享容器镜像 xff0c 界上最大的容器镜像存储库 xff0c 拥有一系列内容源 xff0c 包括容器社区开发人员 开放源代码项目和独立软件供应商
  • 浅谈网络中接口幂等性设计问题

    所谓幂等性设计 xff0c 就是说 xff0c 一次和多次请求某一个资源应该具有同样的副作用 用数学的语言来表达就是 xff1a f x 61 f f x 在数学里 xff0c 幂等有两种主要的定义 在某二元运算下 xff0c 幂等元素是指