【Spring Cloud系列】- 分布式系统中实现幂等性的几种方式

news2025/1/23 21:25:01

【Spring Cloud系列】- 分布式系统中实现幂等性的几种方式

文章目录

  • 【Spring Cloud系列】- 分布式系统中实现幂等性的几种方式
    • 一、概述
    • 二、什么是幂等性
    • 三、幂等性需关注几个重点
    • 四、幂等性有什么用
    • 五、常见用来保证幂等的手段
      • 5.1 MVCC方案
      • 5.2 去重表
      • 5.3 去重表
      • 5.4 select + insert
      • 5.5 状态机幂等
      • 5.6 token机制,防止页面重复提交
      • 5.7 对外提供接口的api如何保证幂等
      • 5.7 全局唯一ID
    • 5.8 分布式锁
    • 六、总结

在这里插入图片描述

一、概述

在开发订单系统时,我们常遇见支付问题,既用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条。在以前的单应用系统中,我们只需要把数据操作放入事务中即可,发生错误立即回滚,但是再响应客户端的时候也有可能出现网络中断或者异常问题。如果保证一个订单从创建到支付成功整个订单生命周期中,数据是一致,不因异常而改变。这种机制就需要用到幂等性。

二、什么是幂等性

幂等是一个数学与计算机的概念,常见于常见于抽象代数中。

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

幂等性:任意多次执行对资源本身所产生的影响均与一次执行的影响相同

接口的幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终得到的结果是一致的,有些接口可以天然的幂等性,比如查询接口,调用一次和调用多次,对系统得到的结果,是一样的。并不会因为调用的次数改变查询的结果。

插入(INSERT)和修改(UPDATE)方法是非幂等性的,需要通过机制在需要的场景处理以确保多次执行无副作用。

删除(delete)执行一次或多次都是结果为空(即结果一致),并且无副作用,所以在根据主键ID删除可以认为是(伪)幂等性的,根据非主键删除的如果多次执行无副作用(都是把数据删除),也可以认为是(伪)幂等性。

三、幂等性需关注几个重点

  1. 幂等不仅仅只是一次(或多次)请求对资源没有副作用(比如查询数据库操作,没有增删改,因此没有对数据库有任何影响)
  2. 幂等还包括第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用。
  3. 幂等关注的是以后的多次请求是否对资源产生的副作用,而不关注结果。
  4. 网络超时等问题,不是幂等性的讨论范围。

幂等性是系统服务对外一种承诺(而不是实现),承诺只要调用接口成功,外部多次调用对系统的影响是一致的。声明为幂等的服务会认为外部调用失败是常态,并且失败之后必然会有重试。

四、幂等性有什么用

业务开发中,经常会遇到重复提交的情况,无论是由于网络问题无法收到请求结果而重新发起请求,或是前端的操作抖动而造成重复提交情况。 在交易系统,支付系统这种重复提交造成的问题有尤其明显,比如:

  1. 用户在APP上连续点击了多次提交订单,后台应该只产生一个订单;
  2. 向支付宝发起支付请求,由于网络问题或系统BUG重发,支付宝应该只扣一次钱。 很显然,声明幂等的服务认为,外部调用者会存在多次调用的情况,为了防止外部多次调用对系统数据状态的发生多次改变,将服务设计成幂等。
  3. 出库单反复请求产生多个出库单信息。

五、常见用来保证幂等的手段

5.1 MVCC方案

多版本并发控制,该策略主要使用update with condition(更新带条件来防止)来保证多次外部请求调用对系统的影响是一致的。在系统设计的过程中,合理的使用乐观锁,通过version或者updateTime(timestamp)等其他条件,来做乐观锁的判断条件,这样保证更新操作即使在并发的情况下,也不会有太大的问题。例如

select * from tablename where condition=#condition# //取出要跟新的对象,带有版本versoin
update tableName set name=#name#,version=version+1 where version=#version#

在更新的过程中利用version来防止,其他操作对对象的并发更新,导致更新丢失。为了避免失败,通常需要一定的重试机制。

5.2 去重表

在插入数据的时候,插入去重表,利用数据库的唯一索引特性,保证唯一的逻辑。

这种方法适用于在业务中有唯一标的插入场景中,比如在以上的支付场景中,如果一个订单只会支付一次,所以订单ID可以作为唯一标识。这时,我们就可以建一张去重表,并且把唯一标识作为唯一索引,在我们实现时,把创建支付单据和写入去去重表,放在一个事务中,如果重复创建,数据库会抛出唯一约束异常,操作就会回滚。

5.3 去重表

select for update,整个执行过程中锁定该订单对应的记录。注意:这种在DB读大于写的情况下尽量少用。

5.4 select + insert

并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了。注意:核心高并发流程不要用这种方法。

5.5 状态机幂等

在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机,就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。

这种方法适合在有状态机流转的情况下,比如就会订单的创建和付款,订单的付款肯定是在之前,这时我们可以通过在设计状态字段时,使用int类型,并且通过值类型的大小来做幂等,比如订单的创建为1000,付款成功为1。付款失败为999。

5.6 token机制,防止页面重复提交

业务要求:页面的数据只能被点击提交一次,

发生原因:由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交

解决办法

  • 集群环境:采用token加redis(redis单线程的,处理需要排队)
  • 单JVM环境:采用token加redis或token加jvm内存

处理流程

  • 数据提交前要向服务的申请token,token放到redis或jvm内存,token有效时间
  • 提交后后台校验token,同时删除token,生成新的token返回
  • token特点:要申请,一次有效性,可以限流

5.7 对外提供接口的api如何保证幂等

如微信提供的付款接口:需要接入商户提交付款请求时附带:source来源,seq序列号。source+seq在数据库里面做唯一索引,防止多次付款,(并发时,只能处理一个请求)

**总结:**幂等性应该是合格程序员的一个基因,在设计系统时,是首要考虑的问题,尤其是在像支付宝,银行,互联网金融公司等涉及的都是钱的系统,既要高效,数据也要准确,所以不能出现多扣款,多打款等问题,这样会很难处理,用户体验也不好 。

5.7 全局唯一ID

如果使用全局唯一ID,就是根据业务的操作和内容生成一个全局ID,在执行操作前先根据这个全局唯一ID是否存在,来判断这个操作是否已经执行。如果不存在则把全局ID,存储到存储系统中,比如数据库、redis等。如果存在则表示该方法已经执行。

从工程的角度来说,使用全局ID做幂等可以作为一个业务的基础的微服务存在,在很多的微服务中都会用到这样的服务,在每个微服务中都完成这样的功能,会存在工作量重复。另外打造一个高可靠的幂等服务还需要考虑很多问题,比如一台机器虽然把全局ID先写入了存储,但是在写入之后挂了,这就需要引入全局ID的超时机制。

使用全局唯一ID是一个通用方案,可以支持插入、更新、删除业务操作。但是这个方案看起来很美但是实现起来比较麻烦,下面的方案适用于特定的场景,但是实现起来比较简单。

5.8 分布式锁

在进入方法时,先去获取锁,假如获取到锁,就继续后面的流程。假如没有获取到锁,就等待锁的释放直到获取到锁。当执行完方法时,释放锁。当然,锁要设个超时时间,防止意外没有释放到锁。它用来解决分布式系统的幂等性,常用的实现方案是 redis 和 zookeeper 等工具。

六、总结

幂等性增加了额外控制幂等的业务逻辑,复杂化了业务功能,把并行执行的功能改为串行执行,降低了执行效率。

幂等性虽然复杂化了业务功能和降低了执行效率,但为了保证系统的正确性,是必要的。就上面更新 X 的例子,在单台服务器上,给那段代码加上锁,并给 X 设为 volatile,就保证来数据的正确性了。在分布式环境下并且 X 是从数据库或者文件里查询出来的,用上面加锁的方式实现就不能保证数据的正确性了,这时候就需要用到分布式锁了。所以,保证方法或接口的幂等性是非常有必要的,因为数据是不能出现任何问题的。

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

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

相关文章

5G 数字乡村数字农业农村大数据中心项目农业大数据建设方案PPT

导读:原文《5G 数字乡村数字农业农村大数据中心项目农业大数据建设方案PPT》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。以下是部分内容, 喜…

市级数字政府电子政务大数据中心项目建设和运营方案WORD

导读:原文《市级数字政府电子政务大数据中心项目建设和运营方案WORD》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。以下是部分内容, 目 录 …

5、监测数据采集物联网应用开发步骤(5.1)

监测数据采集物联网应用开发步骤(4) Sqlite3数据库读写操作开发、异常信息统一处理类开发 本章节需要调用sqlite3及mysql-connector 安装sqlite3 Pip3 install sqlite3 安装mysql-connector pip3 install mysql-connector 验证是否安装成功,python中运行下列…

Unity网格编程笔记[十]一些网格基础操作的封装(Mesh合并,UV映射,正反面反转,顶点合并,法线求切线计算等)

这里的代码是在 Unity网格编程笔记[五]网格切割 中整合出来的。 这里的mesh可以直接接入到使用mesh的unity组件 一些基础的属性还是要参考 Unity网格编程笔记[零]网格编程基础知识点 Mesh合并 网格的合并,其实底层也没那么复杂。对于三角面,只是顺序…

LiveGBS伴侣

【1】LiveGBS 简介 LiveGBS是一套支持国标(GB28181)流媒体服务软件。 国标无插件;提供用户管理及Web可视化页面管理; 提供设备状态管理,可实时查看设备是否掉线等信息; 实时流媒体处理,PS(TS)转ES&…

python的安装(推荐)

torch安装与卸载推荐链接1推荐链接2 推荐链接3 安装pytorch步骤推荐链接 python关键字:

19.CSS雨云动画特效

效果 源码 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Cloud & Rain Animation</title><link rel="stylesheet" href="style.css"> </head> <bo…

SpringCluod深入教程

1.Nacos配置管理 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#…

Jmeter+ServerAgent

一、Jmeter 下载 https://jmeter.apache.org/download_jmeter.cgi选择Binaries二进制下载 apache-jmeter-5.6.2.tgz 修改配置文件 jmeter下的bin目录&#xff0c;打开jmeter.properties 文件 languagezh_CN启动命令 cd apache-jmeter-5.6/bin sh jmeter二、ServerAgent 监…

Mysql--技术文档--MVCC(Multi-Version Concurrency Control | 多版本并发控制)

MVCC到底是什么 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;是一种并发控制机制&#xff0c;用于解决并发访问数据库时的数据一致性和隔离性问题。MVCC允许多个事务同时读取数据库的同一数据&#xff0c;而不会相互干扰或导致冲突。 在传统的并发控制机制中…

CTFhub-文件上传-无验证

怎样判断一个网站是 php asp jsp 网站 首先&#xff0c;上传用哥斯拉生成 .php 文件 然后&#xff0c;用蚁剑测试连接 找到 flag_1043521020.php 文件&#xff0c;进去&#xff0c;即可发现 flag ctfhub{ee09842c786c113fb76c5542}

「Vue|网页开发|前端开发」02 从单页面到多页面网站:使用路由实现网站多个页面的展示和跳转

本文主要介绍如何使用路由控制来实现将一个单页面网站扩展成多页面网站&#xff0c;包括页面扩展的逻辑&#xff0c;vue的官方路由vue-router的基本用法以及扩展用法 文章目录 一、场景说明二、基本的页面扩展页面扩展是在扩什么创建新页面的代码&#xff0c;让页面内容变化起…

windows系统配置tcp最大连接数

打开注册表 运行->regedit HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters目录下 增加一个MaxUserPort&#xff08;默认值是5000&#xff0c;端口范围是1025至5000&#xff09;MaxUserPort设置为65534&#xff08;需重启服务器&#xff09; 执行dos命令&…

登高不系安全带自动识别

登高不系安全带自动识别采用yolov8深度学习算法框架模型&#xff0c;登高不系安全带自动识别能够自动检测和识别登高作业人员是否佩戴安全带&#xff0c;过滤其他类似物体的干扰。登高不系安全带自动识别发现有人员未佩戴安全带&#xff0c;将立即触发预警。根据YOLO的设计&…

使用PXE启动无系统盘的客户机并运行Ubuntu系统

准备 机器说明server安装pxe相关软件&#xff0c;nfs-kernel-server&#xff0c;ip192.168.1.2client1带有硬盘&#xff0c;使用iso安装ubuntu系统&#xff0c;并安装日常工作需要用到的软件&#xff0c;做好相应配置&#xff0c;安装nfs客户端&#xff1a;nfs-commonclient2没…

javacv基础03-调用本机摄像头并截图保存到本地磁盘

基于基础02 的基础上对视频进行取帧保存 代码如下&#xff1a; package com.example.javacvstudy;/*** 本地摄像头截图*/import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.javacv.OpenCVFrameConverter; import org.b…

避免常见面试错误:程序员应该注意的陷阱

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

《Flink学习笔记》——第九章 多流转换

无论是基本的简单转换和聚合&#xff0c;还是基于窗口的计算&#xff0c;我们都是针对一条流上的数据进行处理的。而在实际应用中&#xff0c;可能需要将不同来源的数据连接合并在一起处理&#xff0c;也有可能需要将一条流拆分开&#xff0c;所以经常会有对多条流进行处理的场…

​LeetCode解法汇总57. 插入区间

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给你一个 …

python web GUI框架-NiceGUI 教程(一)

python web GUI框架-NiceGUI 教程&#xff08;一&#xff09; streamlit可以在一些简单的场景下仍然推荐使用&#xff0c;但是streamlit实在不灵活&#xff0c;受限于它的核心机制&#xff0c;NiceGUI是一个灵活的web框架&#xff0c;可以做web网站也可以打包成独立的exe。 基…