93. 通用防重幂等设计

文章目录

  • 一、防重与幂等的区别
  • 二、幂等性的应用场景
  • 三、幂等性与防重关系
  • 四、处理流程

一、防重与幂等的区别

防重与幂等是在 Web 应用程序和分布式系统中重要而又非常常见的问题。

防重
防重是指在多次提交同样的请求过程中,系统会检测和消除重复的数据,确保相同的数据只会被处理一次,从而避免不必要的重复操作或产生错误的结果。防重通常指人为多次提交请求、系统超时等原因数据重复处理,防止重复处理产生错误。

幂等
幂等是指对同一操作进行多次执行所产生的结果和执行一次的结果是相同的。换句话说,无论进行多少次相同的操作,最终的结果都是一致的。在计算中,幂等操作不会因为重复执行而导致状态的变化。幂等性通常在设计和实现API、网络通信等场景中具有重要意义,因为它保证了对同一资源或操作的多次请求不会产生意外的副作用。

举例:HTTP的幂等性
HTTP GET 方法用于获取资源,不应有副作用,所以是幂等的。比如:GET http://www.bank.com/account/123456,不会改变资源的状态,不论调用一次还是 N 次都没有副作用。请注意,这里强调的是一次和 N 次具有相同的副作用,而不是每次 GET 的结果相同 GET http://www.news.com/latest-news这个 HTTP 请求可能会每次得到不同的结果,但它本身并没有产生任何副作用,因而是满足幂等性的。

HTTP POST 方法用于创建资源,所对应的 URI 并非创建的资源本身,而是去执行创建动作的操作者,有副作用,不满足幂等性。比如:POST http://www.forum.com/articles的语义是在http://www.forum.com/articles下创建一篇帖子,HTTP 响应中应包含帖子的创建状态以及帖子的 URI。两次相同的 POST 请求会在服务器端创建两份资源,它们具有不同的 URI;所以,POST 方法不具备幂等性。

二、幂等性的应用场景

幂等性在分布式系统和网络通信中广泛应用。以下是一些常见的应用场景:

  1. 交易处理: 在金融系统中,交易处理通常需要保证幂等性,以防止重复执行交易或产生不一致的结果。

  2. 支付系统: 支付操作需要保证幂等性,确保多次支付请求不会导致用户重复支付或多次扣款。

  3. 订单处理: 在电商平台中,订单处理需要具有幂等性,以避免订单重复创建或多次处理。

  4. 消息处理: 消息队列系统中,消费者需要确保处理消息的幂等性,防止消息重复处理或丢失。

  5. API设计: 在设计RESTful API时,应该考虑接口的幂等性,以防止客户端多次提交相同的请求。

  6. 数据库更新: 数据库操作中,更新操作需要具有幂等性,确保多次更新不会产生重复结果或破坏数据一致性。

三、幂等性与防重关系

总结起来,防止重复处理是为了避免相同请求或操作的重复执行,而幂等性是一种特性,保证相同的操作在多次执行时会得到相同的结果,并且不会对系统状态产生副作用,从而能够帮助实现防止重复处理的目标。

举例来说,一个更新用户信息的操作,如果是幂等的,那么多次执行相同的更新操作不会产生副作用,用户信息也不会发生额外的改变。因此,防止重复处理的一个常见策略是将更新用户信息的操作设计成幂等的,这样即使多次收到相同的更新请求,也不会对用户信息产生重复的更新。

看起来,防重与幂等似乎在说同一件事情,但其实又有不同的区分。 幂等性强调一个操作的重复执行不会改变最终结果,而防重则关注于避免在处理过程中重复处理相同的数据或操作,防重对接口处理结果没有要求。虽然它们是不同的概念,但在分布式场景下,组合使用防重与幂等设计可以更好地保证系统的可靠性和正确性。特别是在面对高并发请求的场景下,合理有效的设计对于系统的正常运行非常重要。

下面我们看下如何设计通用的防重幂等系统。

四、处理流程

常见web请求包含客户端接口请求、服务调用请求、MQ消费等场景,我们把这些请求方统称为客户端,对应的处理方称为服务端。

对于幂等性的处理流程来说,这样来看防重主要分三步:

  • 确定唯一请求标识,通过唯一标识,服务端根据标识判断是否重复请求。

  • 客户端控制避免重复请求

  • 服务端幂等性处理,说白了就是要过滤一下已经收到的请求。要做到这个事,我们需要一个存储来记录收到的请求(唯一标识)。当收到交易请求的时候,我们就会到这个存储中去查询。如果查找到了,那么就不再做查询了,并把上次做的结果返回。如果没有查到,那么我们就记录下来。

大概流程如下:

在这里插入图片描述

上面流程有个问题如果让 100% 的请求都到这个存储里去查一下,这会导致处理流程变得很慢。所以,最好是当这个存储出现冲突的时候会报错。也就是说,我们收到交易请求后,直接去存储里记录这个 ID(相对于数据的 Insert 操作),如果出现 ID 冲突了的异常,那么我们就知道这个之前已经有人发过来了,所以就不用再做了。比如,数据库中你可以使用 insert into … values … on DUPLICATE KEY UPDATE … 这样的操作。对于更新的场景来说,如果只是状态更新,可以使用如下的方式。如果出错,要么是非法操作,要么是已被更新,要么是状态不对,总之多次调用是不会有副作用的。

update table set status = “paid” where id = xxx and status = “unpaid”;

网上还有 乐观锁、版本号等其他方式,这些都不标准,我们希望我们有一个标准的方式来做这个事,所以,最好还是用一个 ID。因为我们的幂等性服务也是分布式的,所以,需要这个存储也是共享的。这样每个服务就变成没有状态的了。但是,这个存储就成了一个非常关键的依赖,其扩展性和可用性也成了非常关键的指标。

对此,一般的幂等性的设计如下。

1. 确定唯一请求标识

  • 有唯一标识的需要把唯一标识带上

    • 唯一标识通常是业务的唯一ID,这种情况通常用于状态变更操作。比如取消订单场景,订单ID就是唯一标识;

    • 无业务唯一ID,但是有操作记录的,操作记录可以充当唯一标识。这种情况通常是调用下游时先生成本地操作记录,然后调用下游,将操作记录ID充当唯一标识。

  • 没有唯一标识的,我们创造唯一标识

    • 在表单中添加一个隐藏的字段或在请求头中添加一个特定的标识token(分布式ID)。服务端在处理请求时,根据请求标识来判断是否为重复请求,如果请求标识已经存在或已被使用,则拒绝处理该请求。

    • 通过其他字段串行化处理,服务端生成唯一标识。比如商品购买,可以通过userId+productId加锁,以用户、商品维度加锁串行化处理,服务端接收请求时先加锁,然后生成订单ID,进行业务处理,业务处理完成后释放锁。

2.客户端防止重复提交

  • 前端页面可以在提交后页面控制按钮禁止点击,防止多次点击;

  • 上游服务接口避免重复调用下游;对于超时场景,可以让下游提供查询接口,判断处理状态避免重复调用。

  • MQ尽量符合exactly once 语义;

3.服务端幂等处理
为了实现幂等性,可以采用以下处理流程:
图片

虚线非必须

  1. 获取唯一标识: 在每个请求中添加唯一标识,例如通过隐藏字段或请求头。

  2. 客户端向服务端请求,带上唯一标识

  3. 并发控制(分布式锁): 服务端收到请求后,根据标识判断是否为重复请求。同时,记录已处理的请求标识。

    • 通过分布式锁: 通过分布式锁(Redis)防止重复请求,如果并发请求可以拒绝重复请求。

    • 乐观锁和版本号: 在数据库中使用乐观锁机制来实现幂等性。在每次请求之前,先读取数据的版本信息,并在更新数据时检查版本号是否匹配。如果版本号不匹配,说明数据已被其他请求修改,可以拒绝重复请求。

  4. 业务数据处理:

    • 我们先根据唯一标识去存储中去查询。如果查找到了,那么就不再做查询了,并把上次做的结果返回。如果没有查到,那么我们就进行业务处理,并把唯一标识记录下来。

    • 如果有操作流水,建议基于操作流水做幂等,并将幂等号作为唯一性约束,确保唯一性。如果没有流水,那么基于状态机也是可以的。

    • 不管怎么样,数据库的唯一性约束都要加好,这是系统的最后一道防线。万一前面的锁失效了,这里也能控制得住不会产生脏数据。

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

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

相关文章

HTTP有什么缺陷,HTTPS是怎么解决的

缺陷 HTTP是明文的,谁都能看得懂,HTTPS是加了TLS/SSL加密的,这样就不容易被拦截和攻击了。 SSL是TLS的前身,他俩都是加密安全协议。前者大部分浏览器都不支持了,后者现在用的多。 对称加密 通信双方握有加密解密算法…

python自学3

第一节第六章 数据的列表 列表也是支持嵌套的 列表的下标索引 反向也可以 嵌套也可以 列表的常用操作 什么是列表的方法 学习到的第一个方法,index,查询元素在列表中的下标索引值 index查询方法 修改表功能的方法 插入方法 追加元素 单个元素追加 多…

YOLO v9训练自己数据集

原以为RT-DETR可以真的干翻YOLO家族,结果,!!!! 究竟能否让卷积神经网络重获新生? 1.数据准备 代码地址:https://github.com/WongKinYiu/yolov9 不能科学上网的评论区留言 数据集…

教育知识与能力保分卷一(中学)

2.在教育学的发展过程中,代表马克思主义的教育学著作是(A )。 A.凯洛夫的《教育学》 B.赞可夫的《教学与发展》 C.杜威的《民主主义与教育》 D.昆体良的《论演说家的教育》 8.小贺在一次期…

电脑不小心格式化了,怎么恢复?

在这个数字化时代,电脑已经成为我们日常生活和工作中不可或缺的工具。然而,有时我们可能会不小心格式化电脑硬盘,导致重要数据的丢失。那么,电脑不小心格式化了,怎么恢复? 别着急,在本篇攻略中&…

掌握PDF全面指南:Python开发者的高效编程技巧

掌握PDF全面指南:Python开发者的高效编程技巧 简介PDF基础知识PDF的结构常见用途PDF在开发中的挑战 PDF处理库介绍PyPDF2ReportLabPDFMiner辅助库 读取和分析PDF文件使用PyPDF2读取PDF文件提取PDF中的文本和元数据分析PDF结构和内容 编辑和修改PDF文件合并多个PDF文…

如何制作一个分销商城小程序_揭秘分销商城小程序的制作秘籍

打造赚钱神器!揭秘分销商城小程序的制作秘籍 在这个数字化高速发展的时代,拥有一个属于自己的分销商城小程序,已成为众多商家和创业者的必备利器。它不仅能够快速搭建起自己的在线销售渠道,还能够利用分销模式,迅速裂…

安全特性 悬垂指针

英文名称 Dangling point,它还有一个兄弟叫 wild point - 野指针。 简单的对Dangling point做一个类比:我换手机号码了,但是没有通知老板,老板通讯录存的是我的旧号码。然后老板打电话有两种可能:打不通电话或者电话打…

Linux常用命令(超详细)

一、基本命令 1.1 关机和重启 关机 shutdown -h now 立刻关机 shutdown -h 5 5分钟后关机 poweroff 立刻关机 重启 shutdown -r now 立刻重启 shutdown -r 5 5分钟后重启 reboot 立刻重启 1.2 帮助命令 –help命令 shutdown --help: ifconfig --help:查看…

AWS ECR(AWS云里面的docker镜像私库)

问题 上一篇文章,在AWS云上面部署了k8s集群,这次接下来,需要在一个docker镜像私库。 步骤 创建docker镜像私库 打开AWS ECR主页,创建一个docker镜像私库,如下图: 设置私有镜像库名称,直接创…

AI短视频矩阵运营软件|抖音视频矩阵控制工具

【罐头鱼AI传单功能介绍】 罐头鱼AI传单是一款专为短视频矩阵运营而设计的智能软件,旨在帮助用户高效管理和运营多个抖音账号,并提供一系列强大的功能来优化视频内容创作和发布流程。QQ:290615413以下是软件框架,详细介绍其功能和特点&#…

第一弹:Flutter安装和配置

目标: 1)配置Flutter开发环境 2)创建第一个Flutter Demo项目 Flutter中文开发者网站: https://flutter.cn/ 一、配置Flutter开发环境 Flutter开发环境已经提供集成IDE开发环境,因此需要配置开发环境的时候&#xf…

【项目管理】CMMI-质量保证过程

质量保证过程(PQA):通过质量保证活动,确保过程与产品满足过程、规程及相应的要求,确保问题得到关注与解决,使工作人员和管理者能够客观地了解过程与相关的工作产品。QA工程师应实施质量保证策划活动,客观地…

【云呐】固定资产管理系统选型有哪些

固定资产管理是企业经营管理过程中非常重要的任务。它涉及到公司的核心资产,包括土地、建筑、设备、车辆等。许多企业选择引入固定资产管理系统,以确保这些资产的高效管理和使用。但是,面对市场上众多的固定资产管理系统,如何选择…

【自然语言处理六-最重要的模型-transformer-上】

自然语言处理六-最重要的模型-transformer-上 什么是transformer模型transformer 模型在自然语言处理领域的应用transformer 架构encoderinput处理部分(词嵌入和postional encoding)attention部分addNorm Feedforward & add && NormFeedforw…

固定资产管理系统包括哪些

固定资产管理是企业经营过程中一项非常重要的任务。它涉及到公司的核心资产,包括土地、建筑物、设备、车辆等。为了有效地管理这些资产,许多企业选择使用固定资产管理系统。那么,固定资产管理系统的内容是什么呢?本文将为您进行全…

代码随想录day13(2)栈与队列:用队列实现栈(leetcode225)

题目要求:使用队列实现栈的push、pop、top(取栈顶元素)、empty操作。 思路:首先的思路就是使用两个队列,入栈的操作不变,如果想弹出一个元素,先将队列1元素出队,只保留一个元素&…

力扣hot100:1.两数之和(哈希表)

输入中可能存在重复值 。 分析&#xff1a; 本题需要返回的是数组下标&#xff0c;因此如果需要使用排序然后双指针的话&#xff0c;需要用到哈希表&#xff0c;但是由于输入中可能存在重复值&#xff0c;因此哈希表的value值必须是vector<int>。 使用双指针求目标值targ…

第十七天-反爬与反反爬-验证码识别

目录 反爬虫介绍 基于身份识别反爬和解决思路 Headers反爬-使用User-agent Headers反爬-使用coookie字段 Headers反爬-使用Referer字段 基于参数反爬 验证码反爬 1.验证码介绍 2.验证码分类&#xff1a; 3.验证码作用 4.处理方案 5.图片识别引擎:ocr 6.使用打码平…

基于springboot+vue的周边游平台个人管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…