对资金类服务幂等设计与测试的思考

news2025/1/22 15:40:20

之前写过一篇《系统设计的幂等性》科普文章。

幂等性原本是数学上的概念,用在接口上就可以理解为:同一个接口,多次发出同一个请求,必须保证操作只执行一次。调用接口发生异常并且重复尝试时,总是会造成系统所无法承受的损失,所以必须阻止这种现象的发生。

对于本文讨论的资金类服务类,如果幂等设计不合理,则会出现一笔交易重复打款的情况,这就出现了资损。

01/为什么会产生接口幂等性问题?

其实可以分两类:

一类是受不可抗且非常规操作导致的重复请求,例如网络波动引起的重复请求;用户重复操作,用户在操作时候可能会无意触发多次下单交易,甚至没有响应而有意触发多次交易应用。

另一类则是请求失败需要重复发起请求的场景,例如用户请求受理成功,需要异步通过定时任务重复执行的情况。

02/如何保证接口幂等性?

幂等的核心是确保唯一性。常规的方法有:

唯一索引:在数据库中建立唯一索引,用作幂等键,可以防止插入重复的数据。

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

Token机制:其实本质和唯一索引类似。

摆了这么多,下面引出本文讨论的重点:资金类服务如何做幂等设计与测试

当然回答问题前,还是要聊一下创作来源,这个话题的来源同样来源于对线上问题的思考。下面我娓娓道来。

03/问题背景

图片

退款服务的场景如下:第一次请求:如果用户首次请求应用B失败,则应用A落失败的单据A-1,状态=FAIL;应用B则落受理成功的单据B-1,状态=INIT。初次请求报文如下:

{
"requestId": String,
"amount":Moeny,
"refundDetialList":[
refundDetial-1,
refundDetial-2
]
}

第二次幂等请求:后台重试发起幂等请求应用B失败,则应用A落失败的单据A-2,状态=FAIL;应用B则不对单据B-1做更新,状态=INIT。此时请求报文如下:

{
"requestId": String,
"amount":Moeny,
"refundDetialList":[
refundDetial-1,
refundDetial-2
]
}

第三次幂等请求:后台重试发起发起幂等请求应用B成功,则应用A落成功的单据A-3,状态=SUCCESS;应用B更新单据B-1状态=SUCCESS。(但是应用A与应用B之间的核对不一致。)

  • 但是此时应用A调用应用B的请求报文里refundDetialList的size数量已经包含了A-1、A-2的单据(其实这时候报文是错误的)。

此时请求报文如下:

{
"requestId": String,
"amount":Moeny,
"refundDetialList":[
refundDetial-1,
refundDetial-2,
refundDetial-3,
refundDetial-4
]
}

应用A和B针对幂等请求的处理逻辑:

应用A:幂等字段为requestId,同时校验amount的一致性。捞起DB里根据requestId+status=FAIL关联到的refundDetial组装 对应用B调用的报文。

应用B:幂等字段为requestId,同时校验amount的一致性。捞起DB里根据requestId关联到refundDetial组装报文对下游发起调用。

背景应该描述清楚了,那么下面分析一下问题:

1. 应用A为什么组装报文错误?原因:如果幂等重试在2次以上,组装请求报文由于DB里已经有两条FAIL出现重复组装refundDetialList的情况,导致传给下游错误的报文信息。

2. 应用B面对错误的报文,为什么能处理成功?原因:应用B会将首次请求失败的数据落DB,幂等请求时候,如果requestId不变,且amount不变,则会捞起首次请求落DB的refundDetial,组装对下游的请求报文,因此不会报错。

分析问题与原因后,乍一看感觉应用A和B都有问题,应用A组装refundDetialList的逻辑错误,忽略了2次幂等以上的场景,如果出现这种场景,则组装refundDetialList时候最起码要getFirst()才行。

应用B没有感知到应用A的错误报文,最起码应该拦截到,而不是向下调用才行。

当然,本文的目的不是争个谁对谁错,而是讨论针对这种资金类服务应该如何设计幂等?

04/幂等检验的范围有哪些?

资金类服务的特点就是很容易发生资损。因此在设计幂等逻辑的时候,需要分析请求报文中哪些字段需要严格“幂等”(就是重复请求中哪些字段需要严格保持一致)。

如上文说到的服务,是以requestId作为幂等字段,且对amount做了金额一致性校验,通过后才能继续向下调用。那么refundDetialList是否应该纳入幂等校验的范畴之内的,我觉得这个需要By业务分析,单纯从平台角度无法给出特定的结论。因为平台要提供的是通用能力,理论上是不吃业务的,但是如果针对业务诉求强,那就需要做业务定制的处理逻辑,这显然违背平台设计的初衷。但有时候确实是这样,平台建设没法完全脱离业务。

05/幂等测试场景分析

对于测试来说,通常情况下,我们分析幂等场景一般幂等字段(也可能是多个字段联合作为幂等条件)、关键资金字段如金额作为场景因子设计幂等测试用例:

CASE001:同号发起(幂等条件不变)+不换金额,预期幂等REPEAT_REQUEST;

CASE002:同号发起(幂等条件不变)+换金额,预期幂等校验不通过报错;

CASE003:换号发起(幂等条件变化)+不换金额,预期作为新请求处理;

此外,幂等发起的次数也应该引起关注,作为一个场景因子来对待:

幂等请求次数建议考虑2次以上的场景。

当然,我们设计幂等场景的时候,最好要review下开发的实现思路,不要完全采取黑盒方法,结合白盒方法设计的测试用例才更有效。

- END -


下方扫码关注 软件质量保障,与质量君一起学习成长、共同进步,做一个职场最贵Tester!

新年送福

关注「软件质量保障」微信公众号

菜单栏对话框回复:2024

点击「抽奖」小程序,即可参与新年抽奖活动

我们将从中抽取25位幸运读者,分别为大家送上新年礼物。

图片

温馨提醒:

1. 以上两个活动的截止日期均为:2024年1月22日23:59。

2. 中奖的同学,请填写好邮寄地址,我们会核实后邮寄礼品。如果两周内没有收到礼品,请在后台留言或者私信我们。

图片

好文推荐

往期推荐

聊聊工作中的自我管理和向上管理

经验分享|测试工程师转型测试开发历程

聊聊UI自动化的PageObject设计模式

细读《阿里测试之道》

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

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

相关文章

lenovo联想笔记本电脑拯救者Legion Y7000 2019 PG0(81T0)原装出厂Windows10系统

链接:https://pan.baidu.com/s/1fn0aStc4sfAfgyOKtMiCCA?pwdas1l 提取码:as1l 联想拯救者原厂Win10系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软件、联想电脑管家等预装程序 所需要工具:…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-1 表单

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>表单</title> </head><body> <!--<form action"URL地址" method"提交方式" name"表单名称" /*编码“多部…

数据在AI图像修复任务中的核心作用

在人工智能&#xff08;AI&#xff09;领域&#xff0c;数据的重要性不言而喻。尤其在图像修复任务中&#xff0c;数据的精度和质量直接影响着AI模型的性能。图像修复是指利用AI技术自动识别图像中的缺陷或遮挡物&#xff0c;并对其进行修复或还原的过程。这项技术广泛应用于各…

持续赋能波卡生态创新,OneBlock+ 社区 2023 年度回顾

OneBlock 开发者社区成立于 2018 年&#xff0c;历经五年的积累与沉淀&#xff0c;已经成长为行业内领先的 Substrate 开发者社区。我们以成熟的社区生态&#xff0c;通过 Substrate 技术与波卡生态的相关优质文章、项目方与开发者专访、线上线下技术热点对谈、多阶段开发者课程…

【设计模式】什么场景可以考虑使用简单工厂模式

1.概述 工厂模式是一种创建型模式&#xff0c;主要作用就是创建对象&#xff0c;将对象的创建过程和使用的过程进行解耦。我们平时说的工厂模式实际上是对三种不同类型的工厂模式的统称&#xff0c;简单工厂、工厂方法、抽象工厂&#xff0c;而在23种设计模式中&#xff0c;只…

AI绘画风格化实战

在社交软件和短视频平台上&#xff0c;我们时常能看到各种特色鲜明的视觉效果&#xff0c;比如卡通化的图片和中国风的视频剪辑。这些有趣的风格化效果其实都是图像风格化技术的应用成果。 风格化效果举例 MidLibrary 这个网站提供了不同的图像风格&#xff0c;每一种都带有鲜…

Linux的DHCP工作原理和dns服务器

目录 一、DHCP原理 1.DHCP的好处 2.DHCP的分配方式 3.实验 二、dns服务器 1.什么是dns 2.dns域名解析 3、在内网搭建dns 一、DHCP原理 DCHP工作原理使用C/S架构 &#xff08;1&#xff09;第一步&#xff0c;客户端广播发送一个discover报文寻找DHCP服务器。 &#…

使用CentOS搭建高性能静态HTTP服务器

在互联网应用中&#xff0c;静态内容是广泛存在的&#xff0c;例如HTML页面、图片、视频等。为了提供高效、稳定和安全的静态内容服务&#xff0c;我们可以使用CentOS来搭建高性能的静态HTTP服务器。 1. 选择合适的软件 Nginx和Apache是两个流行的HTTP服务器软件。Nginx以其高…

探索二维码:让信息传递更便捷

二维码是一种用于储存信息的方形图形编码&#xff0c;它可以在多种场景中实现信息的快速传递和识别。本文将从多个方面介绍二维码的原理、类型、优势及应用场景&#xff0c;帮助您深入了解这一重要的物联网技术。 二维码生成器 | 一个覆盖广泛主题工具的高效在线平台(amd794.c…

以太网抓包软件Wireshake应用介绍( SMART PLC MODBUSTCP通信)

首先介绍下常看到的字符ACK,ACK是确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符,表示发来的数据已确认接收无误。在TCP/IP协议中,如果接收方成功的接收到数据,会回复一个ACK数据。通常ACK信号有自己固定的格式,长度大小,由接收方回复给发送方。ACK在TCP的…

C# 静态代码织入AOP组件之肉夹馍

写在前面 关于肉夹馍组件的官方介绍说明&#xff1a; Rougamo是一个静态代码织入的AOP组件&#xff0c;同为AOP组件较为常用的有Castle、Autofac、AspectCore等&#xff0c;与这些组件不同的是&#xff0c;这些组件基本都是通过动态代理IoC的方式实现AOP&#xff0c;是运行时…

C语言数据结构(1)复杂度(大o阶)

欢迎来到博主的专栏——C语言与数据结构 博主ID——代码小豪 文章目录 如何判断代码的好坏时间复杂度什么是时间复杂度如何计算时间复杂度 空间复杂度 如何判断代码的好坏 实现相同作用的不同代码&#xff0c;如何分辨这些代码的优劣之处呢&#xff1f; 有人说了&#xff0c…

GPT实战系列-简单聊聊LangChain搭建本地知识库准备

GPT实战系列-简单聊聊LangChain搭建本地知识库准备 LangChain 是一个开发由语言模型驱动的应用程序的框架&#xff0c;除了和应用程序通过 API 调用&#xff0c; 还会&#xff1a; 数据感知 : 将语言模型连接到其他数据源 具有代理性质 : 允许语言模型与其环境交互 LLM大模型…

6、C语言:输入与输出

输入输出 标准输入输出getchar&putchar函数printf函数sprintf函数格式化输入——scanf函数 文件访问文件读写 错误处理&#xff1a;stderr和exit行输入和行输出常用函数字符串操作函数字符类别测试和转换函数存储管理函数数学函数随机数发生器函数其他 标准输入输出 getch…

vue文件在<template>中使用多个<el-main>报错(已解决)

目录 1.原理 2. 根据你的需求&#xff0c;自定义每个 组件的内容。你可以在 标签内部插入文本、其他组件、样式等。 3. 根据需要添加样式或其他属性到每个 组件。你可以使用 class、style 或其他属性来自定义每个组件的外观和行为。 4.一个可以运行的总代码如下 5.我的一…

VQE音频处理流程

VQE 上行VQE&#xff0c;主要针对MIC采集部分的音频增强 下行VQE&#xff0c;主要针对SPK播放部分的音频增强 附关键词解释 RES RES 模块为重采样&#xff08;Resampler&#xff09;模块。当AI上行或AO下行通路中开启VQE 各功能 模块时&#xff0c;在处理前后各存在一次重采样…

COBOL语言 :一种主要专注于解决业务问题的编程语言

译文&#xff1a; 什么是COBOL? COBOL是一种主要专注于解决业务问题的编程语言。COBOL的完整形式是面向业务的通用语言。它主要用于公司和政府的商业、金融和行政系统。这种语言也被用来解决许多数据处理问题。 它是由CODASYL(数据系统语言会议)开发的。它被用作大型机中的一…

DSL查询文档--查询结果处理

排序 elasticsearch默认是根据相关度算分&#xff08;_score&#xff09;来排序&#xff0c;但是也支持自定义方式对搜索结果排序。可以排序字段类型有&#xff1a;keyword类型、数值类型、地理坐标类型、日期类型等。 普通字段排序 keyword、数值、日期类型排序的语法基本一…

【JAVA】在 Queue 中 poll()和 remove()有什么区别

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 poll() 方法&#xff1a; remove() 方法&#xff1a; 区别总结&#xff1a; 结语 我的其他博客 前言 在Java的Queue接口中&…

初识C语言·内存函数

目录 1 memcpy的使用和模拟实现 2 memmove的使用和模拟实现 3 memset的使用和模拟实现 4 memcmp的使用和模拟实现 1 memcpy的使用和模拟实现 紧接字符串函数&#xff0c;出场的是第一个内存函数memcpy。前面讲的字符串函数是专门干关于字符串的事的&#xff0c;而这个函数…