分布式接口幂等性设计实现

news2024/11/27 5:28:28

面对分布式架构和微服务复杂的系统架构和网络超时服务器异常等带来的系统稳定性问题,分布式接口的幂等性设计显得尤为重要。本文简要介绍了几种分布式接口幂等性设计实现,包括Token去重机制、乐观锁机制、数据库主键和状态机实现等,以加深理解。


1、分布式接口幂等性相关概念

1.1 什么是幂等性

幂等性来源自数学领域,数学上的幂等性是指对于某一元运算为幂等的操作,在任意元素上多次执行的结果是相同的。例如,函数f(x) = f(x)对于任意的x,在x上的第一次和第二次执行可以得到相同的结果。

在HTTP/1.1规范中幂等性的定义如下:

Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.

一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。

在HTTP协议中,HTTP GET是一个清晰的幂等操作,HTTP DELETE/POST是非幂等的,HTTP PUT也是幂等的,因为对同一个URI进行多次PUT的side-effetcs是一致的。

在这里插入图片描述

在分布式架构或者微服务架构中,由于分布式自身的时序问题以及系统网络的稳定性,接口具有成功、失败和无响应的三种状态,为了提供系统的可用性,重复提交是不可避免的,而重试就会引发幂等性的问题。

1.2 幂等性的使用场景

分布式接口的幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终得到的结果是一致的。幂等性适用于以下场景:

  1. 前端重复提交:在订单系统中用户在前端提交订单,快速重复点击多次,造成后端生成多个内容重复的订单,但是后台应该只产生一个订单。
  2. 接口超时重试:对于给第三方调用的接口,为了防止网络抖动或其他原因造成请求丢失,这样的接口一般都会设计成超时重试多次。防止外部多次调用对系统数据状态的发生多次改变,将服务接口设计成幂等,就是为了防止多次重试造成系统不一致的问题。比如账户扣款操作超时重试了多次,理应只扣款一次。
  3. 消息重复消费:MQ消息中间件,消息重复消费,相同请求条件下这次消费的结果与下一次应该保持一致。
1.3 分布式接口幂等性的实现方案

接口幂等性的解决方案可以在客户端和服务端实现,但是客户端控制效果不佳,比如按钮置灰、不可点击等,由于涉及到多设备兼容性以及接口调用的问题,并不能真正实现幂等。因此安全的措施还是从后端接口层进行控制,有以下几种方案:

  1. Token去重:根据业务的操作和内容生成一个Token值(全局唯一ID),在执行操作前先根据这个全局唯一ID进行校验,来判断这个操作是否已经执行。如果存在则表示该方法已经执行。
  2. 乐观锁机制:适用于更新操作。在查询和删除操作中使用乐观锁机制,保证一次处理结果,避免重复操作。设计表结构时使用乐观锁,通过version来做乐观锁,这样既能保证执行效率,又能保证幂等。
  3. 数据库主键:适用于插入时的幂等性。利用数据库中主键唯一约束的特性,保证一张表中只能存在一条带该唯一主键的记录。
  4. 状态机幂等:根据业务表的状态特性设计,只支持状态的单向改变,在执行的时候加上状态信息,实现幂等。

幂等性设计简化了客户端的处理逻辑,却增加了服务端逻辑处理和设计上的复杂性,增加额外控制幂等的业务逻辑的同时,将并行执行改为串行降低了执行效率。

2、几种接口幂等性方案介绍

2.1 Token去重

Token机制是通过在服务端生成一个唯一的Token,并将其存储在客户端中,来保证多个客户端之间对同一个服务的请求结果的一致性。Token机制的实现原理如下:

  1. 服务端生成Token:服务端需要生成一个唯一的Token,可以使用时间戳、随机数等信息来生成。生成Token后,将其存储在服务端的数据库中。
  2. 客户端获取Token:客户端在每次请求服务时,需要向服务端发送一个请求Token。请求Token是服务端根据Token生成的唯一标识,客户端通过该Token来识别自己的身份,并在服务端的数据库中查找对应的Token。
  3. 如果找到了对应的Token,则说明该请求是第一次请求,服务端将其存储在数据库中,并返回一个唯一的标识符;如果在数据库中找不到该Token,则说明该请求是重复请求,服务端不返回任何结果,并提示用户重新操作。
  4. 如果在数据库中也找不到该Token,则说明该请求是幂等请求,服务端可以直接返回结果,不做任何操作。

在这里插入图片描述

Token机制的优点是实现简单、易于部署和维护,能够保证分布式系统的幂等性。但是,它也存在一些局限性,例如需要在服务端和客户端之间传递Token,可能会导致性能问题;另外,如果Token被滥用,也可能会带来安全问题。因此,在使用Token机制时,需要根据具体情况进行权衡和选择。

2.2 乐观锁机制

数据库乐观锁方案一般适用于更新操作的幂等性,实现逻辑是在对应的数据表中添加一个version字段,作为当前数据的的版本标识。这样每次对这条数据执行更新时,都会将该版本标识作为一个条件,值需要为上次待更新数据中的版本标识的值。

1)先根据条件查询数据,得到对应的版本号version

select version from tablename where xxx

2)更新数据时带上版本号version,只有版本号匹配才会更新数据,如果不匹配则不更新

update tablename set count=count+1, version=version+1 where version=#{version}

3)更新数据的时候,同时需要更新数据对应的版本号version,这样可以解决ABA问题。

如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个问题被称为CAS操作的 "ABA"问题。

乐观锁机制实际上是牺牲了并发性来实现更新操作的幂等性,在并发场景下会导致大量的锁冲突等待和性能问题。

2.3 数据库主键

数据库唯一主键机制是利用主键的唯一性约束,适用于插入操作的幂等性,当插入主键重复的数据时会抛出异常,保证数据的一致性。表结构设计如下所示:

CREATE TABLE `t_check` (
  `id` int(11) NOT NULL COMMENT 'ID',
  `serial_no` varchar(255)  NOT NULL COMMENT '唯一序列号',
  `source_type` varchar(255)  NOT NULL COMMENT '资源类型',
  `status` int(4) DEFAULT NULL COMMENT '状态',
  PRIMARY KEY (`id`)
  UNIQUE KEY `key_s` (`serial_no`,`source_type`)  COMMENT '保证业务唯一性'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='幂等性校验表';

唯一主键UNIQUE KEY的关键性字段如下:

  • serial_no:唯一序列号的值,在分布式架构下是全局唯一的ID
  • source_type:业务类型,区分不同的业务,订单,支付等。

具体处理逻辑如下图所示:

在这里插入图片描述

2.4 状态机实现幂等

对于很多业务是有业务流转状态的,如订单的待提交,待支付,已支付,取消等,在业务逻辑处理的时候只支持状态的单向改变。业务表在设计的时候增加状态字段status,这样在更新的时候加上“status=期望的status”,多次调用的话实际也只会执行一次。

update xx where id=1 and status=1

在这里插入图片描述

3、总结

分布式架构下幂等性是保证接口能够重复执行的重要机制,幂等性和防重又有所不同,防重是在第一次请求已经成功的情况下人为多次重复操作导致的状态改变,幂等性是在不确定第一次请求结果的情况下,发起多次请求不会出现状态的变化。实际使用中,通过数据库主键的唯一性可以实现幂等性和防重,乐观锁的version机制能够实现并发更新下的幂等性,也可以通过数据库悲观锁机制在业务操作前获取锁资源实现唯一性操作。总而言之,分布式接口的幂等性是在牺牲一定的并发和性能的前提下,以实现系统的稳定性和容错性。


参考资料:

  1. https://blog.csdn.net/tengxvincent/article/details/81773745
  2. https://www.cnblogs.com/jajian/p/10926681.html
  3. https://blog.csdn.net/qq_41863849/article/details/123973348
  4. https://zhuanlan.zhihu.com/p/70748661

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/529137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面板安全增强,网站支持反向代理设置,1Panel开源面板v1.2.0发布

2023年5月15日,现代化、开源的Linux服务器运维管理面板1Panel正式发布v1.2.0版本。 在这一版本中,1Panel着重增强了安全方面的功能,包括安全入口访问、面板SSL设置、网站密码访问等,同时网站新增支持反向代理设置,并带…

JVM学习(三)

1. JAVA 四中引用类型 1.1. 强引用 在 Java 中最常见的就是强引用, 把一个对象赋给一个引用变量,这个引用变量就是一个强引 用。当一个对象被强引用变量引用时 ,它处于可达状态,它是不可能被垃圾回收机制回收的,即…

Java阶段二Day21

Java阶段二Day21 文章目录 Java阶段二Day21整合Lombok基础组件1 Lombok简介2 安装和配置 Lombok3 Lombok 注解及其用法3.1 Getter 和 Setter3.2 ToString3.3 AllArgsConstructor 和 NoArgsConstructor3.4 Data 4. 总结5 微博项目优化 Knife4j1 Knife4j的优点2 Knife4j快速上手2…

使用Docker构建的MySQL主从架构:高可用性数据库解决方案

前言 MySQL主从架构,我们已经在vmware虚拟机上实践过了,接下来我们一起探讨在docker中如何使用MySQL主从架构。 🏠个人主页:我是沐风晓月 🧑个人简介:大家好,我是沐风晓月,阿里云社…

《论文阅读》基于提示的知识生成解决对话情感推理难题

《论文阅读》基于提示的知识生成解决对话情感推理难题 前言摘要作者新观点问题定义模型框架Global ModelLocal ModelPrompt Based Knowledge Generation分类器实验结果问题前言 你是否也对于理解论文存在困惑? 你是否也像我之前搜索论文解读,得到只是中文翻译的解读后感到失…

openEuler 成功适配 LeapFive InFive Poros 开发板

近日,openEuler RISC-V 23.03 创新版本在跃昉科技的 Poros 开发板上成功运行。 openEuler 在 Poros 上适配成功,XFCE 桌面启动正常,文件系统、终端模拟器和输入法等相关 GUI 应用也运行流畅,Chromium 浏览器和 LibreOffice 等应用…

【Pm4py第三讲】关于Output

本节用于介绍pm4py中的输出函数,包括日志输出、模型输出、面向对象日志输出等。 1.函数概述 本次主要介绍Pm4py中一些常见的输入函数,总览如下表: 函数名说明write_bpmn()用于写入bpmn模型write_dfg()用于写入dfg模型write_pnml() 用于写入p…

面试之高手回答

1.int与Integer的区别 int与Integer的区别有很多,我简单罗列三个方面 第一个作为成员变量来说Integer的初始值是null,int的初始值是0; 第二个Integer存储在堆内存,int类型是在直接存储在栈空间; 第三个integer是个对象…

项目管理6大避坑技巧

1、拒绝错位战略目标 明确目标方向 做项目,首先需要明确项目目标。项目中有很多目标都很重要,但只有一两个目标是最重要的。在任何时刻,我们主要精力都应该集中在一到两个最重要的目标上。 一般最重要的目标具有以下特点:能够给组…

CSS--空间转换及动画

01-空间转换 空间转换简介 空间:是从坐标轴角度定义的 X 、Y 和 Z 三条坐标轴构成了一个立体空间,Z 轴位置与视线方向相同。空间转换也叫 3D转换属性:transform 平移 transform: translate3d(x, y, z); transform: translateX(); transfor…

能源硕士为何受热捧?社科院与杜兰大学能源管理硕士项目为你解惑

能源行业可谓是全球最具发展前景的行业之一,能源管理硕士更是近几年被争相推荐的“大热门”。广泛的就业选择、较高且稳定的收入,是该专业的特点之一,毕业后可选择在政府相关机构、能源监管部门、全国节能减排领域的各类研究机构工作&#xf…

Linux学习 Day3

目录 1. 时间相关的指令 2. cal指令 3. find指令:(灰常重要) -name 4. grep指令 5. zip/unzip指令 6. tar指令(重要):打包/解包,不打开它,直接看内容 7. bc指令 8. uname –…

Shell基础学习---1、Shell概述、脚本入门、变量

1、Shell 概述 Shell是一个命令解释器,它接收应用程序/用户命令,然后调用操作系统内核。 说明:Shell是一个功能相当强大的编程语言,易编写,易调试、灵活性强。 1、 提供的Shell解释器 2、bash和sh的关系 3、CentOS…

简述-关于Kmeans轮廓系数随着聚类个数的增加后减少的问题

当我们在做Kmeans聚类的准备工作时,通常会用到手肘法(elbow method)或者轮廓系数(silhouette score)去找到最佳簇类个数。 对于轮廓系数寻找法,理论上来说,轮廓系数会随着聚类个数的增加而增加…

云渲染是什么?云渲染和传统渲染农场有什么区别?

云渲染是什么?云渲染和传统渲染农场有什么区别? 今天云渲染小编就来和大家说一说云渲染以及它和传统渲染农场的区别。 一、什么是云渲染?云渲染什么意思? 首先云渲染云渲染是一种依托于云计算的云端服务,用户将本地…

UVM 验证方法学之interface学习系列文章(七)高级 《bind 操作》(3)

在之前的文章,我们就bind 机制,进行了用法分析。其实,对于一些大型的复杂SOC设计,bind的操作,可以说是非常实用的。它不仅能够完成各种UVC的驱动激励操作,而且一定程度能够简便验证平台的搭建和后期维护。下面,我们举个例子说明bind在当今复杂环境下的妙用。 一 TB 思…

聊一聊API 测试有哪些不同类型?

用户希望能够跨设备和浏览器使用应用程序。因此,您必须进行全面的不同 API 测试类型,以了解它的工作情况以及它是否可以执行其主要功能。一些测试人员需要更多地关注这方面,因此,我们看到许多质量较差的应用程序。今天&#xff0c…

23. Unity - 3D游戏开发小计02 --- 动画结束UI、导航网格代理

1. 动画结束UI 一个游戏在通过后,都是需要一个界面显示当前游戏已经结束,即需要给游戏添加一个结束的界面,可以做一个简单的游戏结束界面,用一个图片展示: 首先在层级窗口添加两层UI中的Image,其中第一层的Image仅作背景,可将其填充颜色设置为纯黑色,第二层的Image添加…

消化道炎症 | 细菌蛋白酶失调的作用

谷禾健康 肠道蛋白酶 蛋白水解平衡失调通常与疾病有关。例如丝氨酸蛋白酶和基质金属蛋白酶参与多种生物过程,尤其是炎症反应。 胃肠道拥有数以万亿计的微生物,并暴露于高水平的蛋白酶。研究表明蛋白酶在维胃肠道稳态中的关键作用,它们的上调…

代搭建开发chatgpt

ChatGPT是由OpenAI开发的一款自然语言处理模型,而且它已经预训练好了。基于它开发ChatGPT应用程序需要以下步骤: 准备环境:安装Python3和相关的库,如TensorFlow、Keras等,并下载预训练的ChatGPT模型。 数据准备…