架构设计:如何保证接口幂等性

引言

在分布式系统中,幂等性是一种十分重要的设计原则。它确保了系统在面对重复请求时能够产生相同的结果,而不会引发意外的行为或者数据不一致的问题。在本文中,我们将深入探讨幂等性设计的重要性,并结合 Java 代码以及不同场景下的实现方式进行说明。

1. 什么是幂等性?

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

比如,求绝对值的函数,abs(x) = abs(abs(x))。

为什么我们需要这样的操作?说白了,就是在我们把系统解耦隔离后,服务间的调用可能会有三个状态,一个是成功(Success),一个是失败(Failed),一个是超时(Timeout)。前两者都是明确的状态,而超时则是完全不知道是什么状态。

比如,超时原因是网络传输丢包的问题,可能是请求时就没有请求到,也有可能是请求到了,返回结果时没有正常返回等等情况。于是我们完全不知道下游系统是否收到了请求,而收到了请求是否处理了,成功 / 失败的状态在返回时是否遇到了网络问题。总之,请求方完全不知道是怎么回事。

举几个例子:

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

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

在这种情况下,一般有两种处理方式。

  • 一种是需要下游系统提供相应的查询接口。上游系统在 timeout 后去查询一下。如果查到了,就表明已经做了,成功了就不用做了,失败了就走失败流程。
  • 另一种是通过幂等性的方式。也就是说,把这个查询操作交给下游系统,我上游系统只管重试,下游系统保证一次和多次的请求结果是一样的。

对于第一种方式,需要对方提供一个查询接口来做配合。而第二种方式则需要下游的系统提供支持幂等性的交易接口。

a904cbbcef6e4e2e88133de4ee06b469.png

2. 幂等性的重要性

  1. 数据一致性: 幂等性设计能够保证系统的数据一致性,即使同样的请求被多次发送,系统也能够保持相同的状态。
  2. 避免副作用: 有些操作可能会对系统产生副作用,如扣款、发送消息等,如果没有幂等性保证,重复请求可能会导致意外的结果,比如多次扣款或重复发送消息。
  3. 提高可用性: 在分布式系统中,网络通信可能会因为各种原因失败,而幂等性设计能够保证即使请求被重复发送,系统也能够正确处理,提高了系统的可用性。

对于第一种方式,需要对方提供一个查询接口来做配合。而第二种方式则需要下游的系统提供支持幂等性的交易接口。 下面就说一下幂等性的集中实现方式。

3. 幂等性的实现方式

1. 唯一标识符(IDempotent Key)

在每次请求中添加一个唯一标识符,服务器端根据该标识符判断是否已经处理过该请求。一般使用 UUID 或者类似的全局唯一标识符来实现。

public class IdempotentKeyGenerator {public String generateKey() {// 生成唯一标识符,例如 UUIDreturn UUID.randomUUID().toString();}
}

2. Token 检查

客户端在发送请求时,带上一个 Token,服务器端根据 Token 判断是否已经处理过该请求。

public class IdempotentTokenManager {private Set<String> processedTokens = new HashSet<>();public synchronized boolean isTokenProcessed(String token) {if (processedTokens.contains(token)) {return true;} else {processedTokens.add(token);return false;}}
}

bdda7c2349624352bd72f54d3dae1207.png 

3. 幂等性操作

在具体的业务逻辑中,设计幂等性操作,确保即使同样的请求被多次执行,结果也是一致的。

public class IdempotentOperationService {private IdempotentTokenManager tokenManager;public IdempotentOperationService(IdempotentTokenManager tokenManager) {this.tokenManager = tokenManager;}public void processRequest(String token, Request request) {if (tokenManager.isTokenProcessed(token)) {// 请求已处理,直接返回结果return;}// 执行业务逻辑// ...// 标记 Token 为已处理tokenManager.markTokenAsProcessed(token);}
}

 

4. 不同场景下的实现方式

  • 支付场景: 对于支付请求,可以使用唯一订单号作为幂等性的标识符,确保同一订单只能被处理一次。
  • 消息发送场景: 对于消息发送,可以使用消息 ID 作为幂等性的标识符,确保同一消息只能被发送一次。
  • Web 表单提交场景: 通过表单 Token 或者防重放 Token 来实现。每次用户打开表单页面时,服务器端生成一个唯一的 Token 并返回给客户端,客户端在提交表单时携带该 Token,服务器端校验 Token 的有效性,确保表单只能被提交一次。
  • 缓存更新场景: 在缓存更新场景下,当多个请求同时修改同一个缓存数据时,需要确保缓存数据的一致性。一种常见的实现方式是使用版本号(Versioning)来实现幂等性。每次修改缓存数据时,都将版本号一并更新,并在更新时比较当前版本号与请求中携带的版本号是否一致,从而确保同一请求只能更新一次缓存数据。
  • 文件上传场景: 在文件上传场景下,用户可能会重复上传同一个文件,因此需要确保文件上传的幂等性。一种常见的实现方式是通过文件的哈希值来实现幂等性。服务器端在接收到文件上传请求后,首先计算文件的哈希值,并检查是否已经存在相同哈希值的文件,如果存在则直接返回已存在的文件信息,避免重复存储相同的文件。
  • 并发调用接口场景: 在并发调用接口场景下,多个客户端同时调用同一个接口,可能会导致接口被重复调用。一种常见的实现方式是通过接口调用日志或者消息队列来实现幂等性。每次接口被调用时,记录下接口调用的唯一标识符,并在处理接口请求时检查该标识符是否已经存在于系统中,如果存在则直接返回已处理的结果,避免重复处理同一请求。

结语

幂等性设计在分布式系统中具有重要的意义,能够保证系统的数据一致性、避免副作用以及提高系统的可用性。通过合理的设计和实现,可以有效地确保系统在面对重复请求时能够产生相同的结果,从而提升系统的稳定性和可靠性。

 

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

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

相关文章

【JVM】打破双亲委派机制

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;JVM ⛺️稳中求进&#xff0c;晒太阳 打破双亲委派机制 打破双亲委派机制三种方法 自定义类加载器 ClassLoader包含了四个核心方法 //由类加载器子类实现&#xff0c;获取二进制数据调用…

XML的写法

下面我将以如下代码来解释下XML的写法 <?xml version"1.0" encoding"UTF-8" ?> <Steam><steam id"1"><zhanghao>admin</zhanghao><mima>123</mima><num>120</num></steam><st…

Eureka注册中心(黑马学习笔记)

Eureka注册中心 假如我们的服务提供者user-service部署了多个实例&#xff0c;如图&#xff1a; 大家思考几个问题&#xff1a; order-service在发起远程调用的时候&#xff0c;该如何得知user-service实例的ip地址和端口&#xff1f; 有多个user-service实例地址&#xff0c…

从 Elasticsearch 到 Apache Doris,统一日志检索与报表分析,360 企业安全浏览器的数据架构升级实践

导读&#xff1a;随着 360 企业安全浏览器用户规模的不断扩张&#xff0c;浏览器短时间内会产生大量的日志数据。为了提供更好的日志数据服务&#xff0c;360 企业安全浏览器设计了统一运维管理平台&#xff0c;并引入 Apache Doris 替代了 Elasticsearch&#xff0c;实现日志检…

mysql和sql server 中如何创建和管理用户

阅读本文之前请参阅----MySQL 数据库安装教程详解&#xff08;linux系统和windows系统&#xff09; 在MySQL和SQL Server中创建和管理用户的过程有所不同。下面分别介绍这两种数据库系统中用户管理的常见步骤。 MySQL 创建用户 在MySQL中创建用户的语法…

【鸿蒙 HarmonyOS 4.0】网络请求

一、介绍 资料来自官网&#xff1a;文档中心 网络管理模块主要提供以下功能&#xff1a; HTTP数据请求&#xff1a;通过HTTP发起一个数据请求。WebSocket连接&#xff1a;使用WebSocket建立服务器与客户端的双向连接。Socket连接&#xff1a;通过Socket进行数据传输。 日常…

在UE5中制作UI环形进度条

在日常开发中&#xff0c;经常会有环形进度条UI的效果&#xff0c;例如技能CD时间、加载动画等&#xff0c;本文将通过材质球节点实现该效果&#xff0c;相较于准备美术素材&#xff0c;这样的做法更为方便&#xff0c;效果如下&#xff1a; 1.制作环状效果材质函数 在内容面…

【智能家居】7、主程序编写+实现语音、网络和串口功能

需要毕业论文私信有偿获取 截止目前mainPro.c代码 #include <stdio.h> #include <string.h>#include "controlDevices.h" #include "inputCmd.h"struct Devices *findDevicesName(char *name,struct Devices *phead){struct Devices *tmpphe…

设计模式----开题

简介&#xff1a; 本文主要介绍设计模式中的六大设计原则。开闭原则&#xff0c;里氏代换原则&#xff0c;依赖倒转原则&#xff0c;接口隔离原则&#xff0c;迪米特原则和合成复用原则。这几大原则是设计模式使用的基础&#xff0c;在使用设计模式时&#xff0c;应该牢记这六大…

【PX4-AutoPilot教程-TIPS】PX4控制无人机在Gazebo中飞行时由于视角跟随无人机在画面中心导致视角乱晃的解决方法

PX4控制无人机在Gazebo中飞行时由于视角跟随无人机在画面中心导致视角乱晃的解决方法 问题描述解决方法 问题描述 无人机在Gazebo中飞行时&#xff0c;无人机始终处于画面中央&#xff0c;会带着视角乱晃&#xff0c;在Gazebo中进行任何操作视角都无法固定。 观察Gazebo左侧Wo…

前端架构: 实现脚手架终端UI样式之ANSI escape code, Chalk, Ora介绍

在脚手架当中实现命令行的UI显示 1 &#xff09;概述 在命令行中&#xff0c;如果想实现除传统的常规文本以外的内容比如想对字体进行加粗斜体下划线&#xff0c;包括对它改变颜色改变前景色改变后景色等等需要借助一个叫做 ANSI escape code 这样的一个概念它其实是一个标准&…

手拉手Vite+Vue3+TinyVue+Echarts+TailwindCSS

技术栈springboot3hutool-alloshi-coreVue3viteTinyVueEchartsTailwindCSS软件版本IDEAIntelliJ IDEA 2022.2.1JDK17Spring Boot3.1hutool-all5.8.18oshi-core6.4.1Vue35.0.10vite5.0.10axios1.6.7echarts5.4.3 ECharts是一个使用 JavaScript 实现的开源可视化库&#xff0c;可…

ssm+springmvc基于springboot的宠物领养系统的设计与实现_j5fk4

宠物领养系统主要是为了提高管理员的工作效率&#xff0c;满足管理员对更方便、更快、更好地存储所有信息和数据检索功能的要求。通过对多个类似网站的合理分析&#xff0c;确定了宠物领养系统的各个模块。考虑到用户的可操作性&#xff0c;经过深入调查研究&#xff0c;遵循系…

Uniapp + VUE3.0 实现双向滑块视频裁剪效果

效果图 <template><view v-if"info" class"all"><video:src"info.videoUrl"class"video" id"video" :controls"true" object-fit"fill" :show-fullscreen-btn"false"play-btn…

SpringBoot源码分析

文章目录 SpringBoot 源码分析一、源码分析 - 自动装配1、SpringBootApplication2、EnableAutoConfiguration3、AutoConfigurationImportSelector4、SpringFactoriesLoader5、META-INF/spring.factories6、SpringMVC相关装配 二、源码分析 - 启动加载1、SpringApplication - 静…

2024-02-21 学习笔记(DETR)

自动多模态检测验证效果不佳&#xff08;过检太多&#xff09;后&#xff0c;节后开始尝试DETR路线。 基本梳理了下DETR发展和验证的脉络&#xff0c;先进行相应指定场景的效果验证。 关于DETR系列的介绍&#xff0c;B站上比较多&#xff0c;迪哥的都讲的比较细。 推荐大佬的…

AIoT网关 人工智能物联网网关

AIoT(人工智能物联网)作为新一代技术的代表&#xff0c;正以前所未有的速度改变着我们的生活方式。在这个智能时代&#xff0c;AIoT网关的重要性日益凸显。它不仅是连接智能设备和应用的关键&#xff0c;同时也是实现智能化家居、智慧城市和工业自动化的必备技术。      一…

nuxt项目搭建

1.先下载nuxt脚手架 yarn create nuxt-app <项目名>&#xff0c;记得安装完项目&#xff0c;npm i,下载node包 目录介绍 components 存放组件分别是头部&#xff08;包含导航&#xff09;和底部 layouts 页面布局&#xff0c;实现一个页面整体架构规则&#xff0c;头…

matlab|电动汽车充放电V2G模型

目录 1 主要内容 1.1 模型背景 1.2 目标函数 2 部分代码 3 效果图 4 下载链接 1 主要内容 本程序主要建立电动汽车充放电V2G模型&#xff0c;采用粒子群算法&#xff0c;在保证电动汽车用户出行需求的前提下&#xff0c;为了使工作区域电动汽车尽可能多的消纳供给商场基础…

使用redisMQ-spring-boot-starter实现消息队列和延时队列

简介 redisMQ-spring-boot-starter是一个轻量级的、基于Redis实现的消息队列中间件&#xff0c;它有如下优点&#xff1a; 开箱即用&#xff0c;你几乎不用添加额外的配置支持消息队列、延时队列&#xff0c;并提供精细化配置参数提供消息确认机制支持虚拟空间&#xff0c;不…