当前位置:网站首页>什么是幂等
什么是幂等
2022-08-02 20:33:00 【帅大大的架构之路】
在微服务架构下,我们在完成一个订单流程时经常遇到下面的场景:
一个订单创建接口,第一次调用超时了,然后调用方重试了一次
在订单创建时,我们需要去扣减库存,这时接口发生了超时,调用方重试了一次
当这笔订单开始支付,在支付请求发出之后,在服务端发生了扣钱操作,接口响应超时了,调用方重试了一次
一个订单状态更新接口,调用方连续发送了两个消息,一个是已创建,一个是已付款。但是你先接收到已付款,然后又接收到了已创建
在支付完成订单之后,需要发送一条短信,当一台机器接收到短信发送的消息之后,处理较慢。消息中间件又把消息投递给另外一台机器处理
以上问题,就是在单体架构转成微服务架构之后,带来的问题。当然不是说单体架构下没有这些问题,在单体架构下同样要避免重复请求。但是出现的问题要比这少得多。
为了解决以上问题,就需要保证接口的幂等性,接口的幂等性实际上就是接口可重复调用,在调用方多次调用的情况下,接口最终得到的结果是一致的。有些接口可以天然的实现幂等性,比如查询接口,对于查询来说,你查询一次和两次,对于系统来说,没有任何影响,查出的结果也是一样。
除了查询功能具有天然的幂等性之外,增加、更新、删除都要保证幂等性。那么如何来保证幂等性呢?
全局唯一ID
如果使用全局唯一ID,就是根据业务的操作和内容生成一个全局ID,在执行操作前先根据这个全局唯一ID是否存在,来判断这个操作是否已经执行。如果不存在则把全局ID,存储到存储系统中,比如数据库、redis等。如果存在则表示该方法已经执行。
从工程的角度来说,使用全局ID做幂等可以作为一个业务的基础的微服务存在,在很多的微服务中都会用到这样的服务,在每个微服务中都完成这样的功能,会存在工作量重复。另外打造一个高可靠的幂等服务还需要考虑很多问题,比如一台机器虽然把全局ID先写入了存储,但是在写入之后挂了,这就需要引入全局ID的超时机制。
使用全局唯一ID是一个通用方案,可以支持插入、更新、删除业务操作。但是这个方案看起来很美但是实现起来比较麻烦,下面的方案适用于特定的场景,但是实现起来比较简单。
去重表
这种方法适用于在业务中有唯一标的插入场景中,比如在以上的支付场景中,如果一个订单只会支付一次,所以订单ID可以作为唯一标识。这时,我们就可以建一张去重表,并且把唯一标识作为唯一索引,在我们实现时,把创建支付单据和写入去去重表,放在一个事务中,如果重复创建,数据库会抛出唯一约束异常,操作就会回滚。
插入或更新
这种方法插入并且有唯一索引的情况,比如我们要关联商品品类,其中商品的ID和品类的ID可以构成唯一索引,并且在数据表中也增加了唯一索引。这时就可以使用InsertOrUpdate操作。在mysql数据库中如下:
insert into goods_category (goods_id,category_id,create_time,update_time)values(#{goodsId},#{categoryId}, now(), now())on DUPLICATE KEY UPDATEupdate_time= now()
多版本控制
这种方法适合在更新的场景中,比如我们要更新商品的名字,这时我们就可以在更新的接口中增加一个版本号,来做幂等
boolean updateGoodsName(int id,String newName,int version);
在实现时可以如下
update goods set name=#{newName}, version=#{ version} where id=#{ id} and version<${ version}
状态机控制
这种方法适合在有状态机流转的情况下,比如就会订单的创建和付款,订单的付款肯定是在之前,这时我们可以通过在设计状态字段时,使用int类型,并且通过值类型的大小来做幂等,比如订单的创建为0,付款成功为100。付款失败为99
在做状态机更新时,我们就这可以这样控制
update `order` set status=#{ status} where id=#{ id} and status<#{ status}
以上就是保证接口幂等性的一些方法。
边栏推荐
- 「每周译Go」这次我们来点不一样的!--《How to Code in Go》系列上线
- ICLR 2022最佳论文:基于对比消歧的偏标签学习
- 解道9-编程技术6
- Helm基础知识
- 性能测试 - 理论
- js how to get the browser zoom ratio
- 什么是 IDE
- 开关、电机、断路器、电热偶、电表接线图大全
- setup syntax sugar defineProps defineEmits defineExpose
- "A daily practice, happy water problem" 1374. Generate a string with an odd number of each character
猜你喜欢
Implement fashion_minst clothing image classification
vscode如何能将输出从OUTPUT改为TERMINAL或者DebugConsole
信息系统项目管理师必背核心考点(五十八)变更管理的主要角色
"A daily practice, happy water problem" 1374. Generate a string with an odd number of each character
【3D视觉】深度摄像头与3D重建
引用类型 ,值类型 ,小坑。
用户之声 | 我与GBase的缘分
callback prototype __proto__
9,共模抑制比一-不受输入信号中共模波动的影响。【如何分析共模CM抑制比。】
【实战 已完结】WPF开发自动化生产管理平台
随机推荐
EasyExcel dynamic parsing and save table columns
性能测试 - 理论
Informatics orsay a tong (1258: 【 9.2 】 digital pyramid)
二叉搜索树的实现
【SLAM】DM-VIO(ros版)安装和论文解读
js: 实现一个cached缓存函数计算结果
C语言中变量在内存中的保存与访问
信息系统项目管理师必背核心考点(五十八)变更管理的主要角色
JMeter的基本使用
The time series database has been developed for 5 years. What problem does it need to solve?
开关、电机、断路器、电热偶、电表接线图大全
postgresql autovaccum自动清理
ABAP grammar small review
广东省数字经济发展指引 1.0之建成数据安全保障体系
「每周译Go」这次我们来点不一样的!--《How to Code in Go》系列上线
2022年金九银十,Android面试中高频必问的问题汇总
Day12 接口和协议
js如何获取浏览器缩放比例
如何成为一名正义黑客?你应该学习什么?
The five classification of software testing