幂等性设计与实现

news2024/11/24 16:30:07

文章目录

  • 前言
  • 1.全局唯一ID
    • 1.1 前端防止重复提交
    • 1.2 token机制
    • 1.3 数据库表加唯一约束
  • 2.幂等下 ABA问题 与乐观锁
    • 2.1 乐观锁
    • 2.2 如何解决ABA问题?
  • 3.分布式锁和事务
    • 3.1 分布式锁:
    • 3.2. 分布式事务

前言

幂等性(Idempotence)是一个在计算机科学中使用的术语。当某个操作无论进行一次或多次都产生相同的结果,我们就说这个操作是幂等的。

例如,删除文件的操作就是幂等的,因为无论你尝试删除一次还是两次,结果都是文件被删除。相对地,计数器增加操作就不是幂等的,因为每次操作,计数器的值都会改变。

在分布式系统和网络协议中,幂等性是非常重要的特性。由于网络延迟,服务端可能会接收到同一条消息的多个副本,如果此类操作是幂等的,那么就不会出现任何问题。

解决方案:

    1. 全局唯一ID :为每个请求分配一个唯一的任务 ID,并确保服务器对每个任务只执行一次。如果服务器接收到相同的任务 ID,它将忽略这个任务或返回之前任务的结果。
    1. Token 机制: 根据业务的操作和内容生成一个Token值(全局唯一ID,执行之前判断方法是否执行过。
    1. 发送确认消息:客户端在发送完请求后并不立即进行下一步操作,而是等待服务器的确认消息。如果客户端没有收到确认消息,那么它会重新发送请求。
    1. 使用分布式锁或事务:通过这种方式,可以确保一次只有一个任务在执行,避免因重复执行同一个任务而产生的问题。
    1. 使用乐观锁:乐观锁对数据进行更新时,会检查数据在此期间是否被别人修改过,如果被修改过,则拒绝更新。
    1. 使用“compare-and-swap”等原子操作:原子操作可以在不使用锁的情况下完成复杂的更新操作,这也可以保证幂等性。

幂等可以用来解决什么问题?
幂等性可以用于解决在分布式系统中的重复请求问题。在分布式系统中,由于网络等原因,可能会导致同一个请求被多次执行,从而可能会造成脏数据或资源浪费等问题。通过实现幂等性,可以确保相同的请求只被执行一次,从而防止出现重复请求的情况。这样可以提高系统的稳定性、可靠性和性能。另外,幂等性也可以用于实现事务的原子性,确保事务只被执行一次,从而防止出现数据不一致的情况。

1.全局唯一ID

全局唯一ID的生成,需要根据实际的业务需要进行生成,单机的部署一般使用UUID或者数据库自增ID就ok,分布式下现在比较流行的雪花算法生成全局唯一ID。单机也需要考虑后期业务的扩展进行使用全局唯一ID,根据阿里规范:单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表

1.1 前端防止重复提交

一般开发中,前端也会做一些简单防止重复提交操作,一般的操作就是提交请求后禁用操作。此处就不在赘述,比较简单,此做法不能解决问题,只能简单解决人为的操作。
解决不了由于网络波动,网络重试机制导致数据不一致问题。

1.2 token机制

Token的机制通过进行业务操作之前进行根据业务生成一个token,token可以使用雪花算法进行生成,进行业务操作之前先获取token,获取成功请求业务携带token,请求,后台会根据逻辑进行有效操作的判断。后端判断该 token 是否存在,如存在,则为第一次提交,放行并删除token,如无token,第二次提交,阻拦该请求。

时序图
高并发环境下还需要考虑操作的原子性。
此处使用redis来存生成的token。
安装和具体的操作参考:
centos7下安装redis以及本地连接注意事项
Springboot整合redis

简单token服务代码

/**
 * token服务
 */
@Service
public class TokenService {

    @Autowired
    RedisService redisService;

    /**
     * 获取token
     * @param bizType
     * @return
     */
    public String getToken(String bizType){
        ///业务的key
        String key = bizType+":"+UUID.randomUUID().toString();
        redisService.saveKeyValue(key,1,10);
        return key;
    }
    /**
     * 校验token
     * @param token
     * @return
     */
    public boolean verifyToken(String token){
        ///token
        String value = redisService.getValueByKey(token);
        //判断值是否存在
        if(!StringUtils.isEmpty(value)){
            //存在删除
            redisService.delete(token);
            return true;
        }
        return false;
    }

controller:

@RestController
public class TokenController {

    @Autowired
    TokenService tokenService;

    @GetMapping("/getToken/{bizType}")
    public String getToken(@PathVariable("bizType") String bizType){
      return tokenService.getToken(bizType);
    }
}

请求乱码

1.3 数据库表加唯一约束

比如用户表加上身份证号作为唯一的约束,也可以防止重复提交用户注册。对于一些业务唯一不明确的也能导致不幂等性。

2.幂等下 ABA问题 与乐观锁

ABA问题:是在并发环境中经常会遇到的问题,最典型的例子就是CAS(Compare And Swap)操作。CAS操作是一种乐观加锁机制,它执行时首先把某个内存值A读入到未提交缓冤区,在此期间可能其他线程也修改了这个内存场所的值变成了B,若这个时候重来执行CAS操作,尽管它能检测到这个内存值已经被修改过,但修改过后的这个值B又被其他线程改变成了A,这样CAS操作就可能错误地成功。这就是ABA问题。

2.1 乐观锁

乐观锁一种并发控制技术。在写入数据时,并不加锁,而是假定没有其他线程与其同时修改数据。当操作系统执行写入操作时,它会检查没有线程已经修改从开头到现在的数据。如果检测到其他线程已经修改了该数据,那么操作系统就会拒绝写入,并通知失败。需要重试直到没有其他线程修改需要写入的数据。
乐观锁主要解决了悲观锁长期占据锁而导致其他线程长时间等待锁的问题。

2.2 如何解决ABA问题?

  1. 使用版本号:在每个变量后面追加上版本号,每次修改该变量都对版本号加一,这就能解决ABA问题了。
  2. 使用原子类:Java从1.5开始提供了一个原子包(java.util.concurrent.atomic),在这个包中提供了一些原子类,其中ABA问题可以使用类AtomicStampedReference进行解决,它通过控制变量的版本解决了ABA问题。

3.分布式锁和事务

3.1 分布式锁:

其主要目的是在系统内提供一种机制,来确保在任何时刻只有一个节点可以执行某个程序区块,所以分布式锁主要目的是为了防止并发操作引发的数据不一致问题。
分布式锁通过一种协议来决定哪一个请求可以获得锁,以执行相应的操作。例如,一个典型的应用程序可能需要对数据库中的一个数据进行更新,程序在进行更新操作的时候会先尝试获取分布式锁,如果获取成功则进行操作,如果获取失败则等待或者抛出错误。

3.2. 分布式事务

事务的核心是:ACID原则(原子性、一致性、隔离性、持久性)。

在一个分布式系统中,为了保证跨多个节点的数据一致性和操作可靠性,通常需要引入一种机制——分布式事务。该机制可以确保分布式系统中多个操作要么全都成功执行,要么全都不执行(如果某处失败,其他所有成功的操作也需要回滚)。

分布式锁主要用于保证在多节点环境下,某一时刻只有一个节点能够操作某资源,用于解决并发问题;而分布式事务,主要用于确保在多节点环境下,一个业务流程中包含的多个操作要么全部成功,要么全部失败,从而保证数据的一致性。

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

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

相关文章

导航、开源镜像、Prompt ( AI 提示词 )、AI工具集、chatgpt镜像

1、导航 网站 众多网址导航中,哪个最好?理由是什么? :https://www.zhihu.com/question/19899559 除了百度,其他搜索引擎: 综合类搜索导航(Anywhere Anything):http://lackar.com/aa/ 渗透师 导…

开源QianWei搭建音乐网站,并实现公网连接

开源QianWei搭建音乐网站,并实现公网连接 1、前言2、本地网页搭建2.1环境使用2.2 支持组建选择2.3 网页安装 3、本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4、公网访问测试5、结语 1、前言 音乐是我们生活和工作中不可或缺的调剂,它能让我们心…

二,jmeter的简介还有一些参数的说明

文章目录 一、jmeter简介及安装1. 简介2. 安装 二、jmeter设置语言三、jmeter文件路径说明四、编写jmeter脚本五、乱码的处理:1. 请求内容出现乱码处理方法2. 响应内容出现乱码处理方法 一、jmeter简介及安装 1. 简介 Apache 托管的开源java工具接口测试、自动化测…

Sublime Text 设置中文

文章目录 1. Subime Text 官网2. 中文设置 1. Subime Text 官网 https://www.sublimetext.com/ 2. 中文设置 打开 sublime,ctrl shift p,在对话框搜索 Install Package Control,点击 会弹出一个消息框,表示插件列表加载完成…

【每日一题】42. 接雨水

【每日一题】42. 接雨水 42. 接雨水题目描述解题思路 42. 接雨水 题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输…

【STM32CubeMX】HC_SR04模块测距

前言 本文章介绍了基于STM32F103的HAL库,完成对HC_SR04超声波模块测距的基本思路和工程案例。 环境 STM32F103C6T6系统板,72MHz主频基于STM32CubeMX生成的HAL库代码硬件连接: PB12 — Echo(HC_SR04),PB13 — Trig(HC_SR04)PB9 —…

第二十二章:Non-local Neural Networks ——非局部神经网络

0.摘要 卷积和循环操作都是一次处理一个局部邻域的基本构建模块。在本文中,我们提出了非局部操作作为捕捉长程依赖关系的通用构建模块族。受计算机视觉领域经典的非局部均值方法[4]的启发,我们的非局部操作将一个位置的响应计算为所有位置特征的加权和。…

LiveNVR监控流媒体Onvif/RTSP功能-拉转Onvif/RTSP/RTMP/FLV/HLS直播流流媒体服务视频广场页面集成视频播放集成说明

LiveNVR拉转Onvif/RTSP/RTMP/FLV/HLS直播流流媒体服务视频广场页面集成视频播放集成说明 1、视频页面集成1.1、关闭接口鉴权1.2、视频广场页面集成1.2.1、隐藏菜单栏1.2.2、隐藏播放页面分享连接 1.3、其它页面集成 2、播放分享页面集成2.1、获取 iframe 代码2.2、html 集成ifr…

ext4 mballoc之buddy算法

buddy bitmap 根据《Ext4文件系统介绍 - 理论篇_nginux的博客-CSDN博客》我们知道磁盘上有1block 大小(默认4K)data block bitmap,每bit位代表一个block的使用情况,1代表占用,0代表空闲。data block bitmap 可以表示4 * 1024 * …

代码随想录| 图论02●695岛屿最大面积 ●1020飞地的数量 ●130被围绕的区域 ●417太平洋大西洋水流问题

#695岛屿最大面积 模板题&#xff0c;很快.以下两种dfs&#xff0c;区别是看第一个点放不放到dfs函数中处理&#xff0c;那么初始化的area一个是1一个是0 int dir[4][2]{0,1,0,-1,1,0,-1,0};void dfs(int x, int y,int n, int m, int &area,vector<vector<bool>…

HTML入门教程||HTML 属性||HTML 元素

HTML 元素 HTML 元素 HTML 文档由 HTML 元素定义&#xff0c;HTML 元素指的是从开始标签&#xff08;start tag&#xff09;到结束标签&#xff08;end tag&#xff09;的所有代码。 HTML 元素 开始标签 *元素内容结束标签 *<p>这是一个段落</p><a href"…

《Docker和服务器无状态化:容器化应用的优势,构建高可伸缩性和灵活性》

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

【MATLAB第58期】基于MATLAB的PCA-Kmeans、PCA-LVQ与BP神经网络分类预测模型对比

【MATLAB第58期】基于MATLAB的PCA-Kmeans、PCA-LVQ与BP神经网络分类预测模型对比 一、数据介绍 基于UCI葡萄酒数据集进行葡萄酒分类及产地预测 共包含178组样本数据&#xff0c;来源于三个葡萄酒产地&#xff0c;每组数据包含产地标签及13种化学元素含量&#xff0c;即已知类…

c++高性能264/265实时流媒体服务器/h5客户端整体解决方案源码

文章目录 c高性能264/265实时流媒体服务器/h5客户端整体解决方案源码缘由目前的前端技术栈&#xff0c;已经能够支撑常规的安防桌面客户端软件开发我的方案一套c后端,两套前端H5 UI方案一&#xff1a;多屏h265/h264混合显示H5 UI方案二&#xff1a;H5监控大屏,提供视图切换功能…

基于SRS后端开发的前端页面

SRS(Simple Realtime Server)是简单高效的实时视频服务器&#xff0c;支持RTMP、WebRTC、HLS、HTTP-FLV、SRT等多种实时流媒体协议。 框架 https://www.thinkphp.cn 官网 https://ossrs.net/lts/zh-cn 播放器1 https://www.cdnbye.com 播放器2 https://www.artplayer.org …

苹果的Apple GPT要来了?

据外媒消息&#xff0c;苹果正在内部开发类 ChatGPT 的产品&#xff0c;与微软、OpenAI、谷歌、Meta 等科技巨头在生成式 AI 赛道展开竞争。该消息使得苹果股价上涨了 2%。据苹果工程师透露&#xff0c;苹果在内部构建了代号为“Ajax”的大语言模型开发框架&#xff0c;并构建了…

【C语言】表达式求值相关问题汇总—>隐式类型转换(整型提升)、算数转换与操作符优先级汇总(收藏查阅)

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负。 目录 前言&#xff1a; 一、隐式类型转换 &#xff08;一&#xff09;整型提升的意义…

【六天】高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测技术应用

最初的互补发电系统&#xff0c;就是将不同发点组件进行简单的组合&#xff0c;因为缺乏详细的数学计算模型&#xff0c;同时系统只用于保证率低的用户&#xff0c;导致使用寿命不长。随着新能源系统应用范围的不断扩大&#xff0c;保证率和经济性要求的提高&#xff0c;需要高…

Rust vs Go:常用语法对比(四)

题图来自 Go vs. Rust performance comparison: The basics 61. Get current date 获取当前时间 package mainimport ( "fmt" "time")func main() { d : time.Now() fmt.Println("Now is", d) // The Playground has a special sandbox, so you …

【力扣周赛】第 354 场双周赛

文章目录 Q1&#xff1a;2784. 检查数组是否是好的解法1——排序模拟判断解法2——哈希表计数模拟判断 Q2&#xff1a;6926. 将字符串中的元音字母排序Q3&#xff1a;6931. 访问数组中的位置使分数最大&#xff08;线性DP&#xff09;Q4&#xff1a;6922. 将一个数字表示成幂的…