创建订单实现幂等的一点思考

标签: IT技术 分布式 架构设计 | 发表时间:2018-04-10 11:20 | 作者:Sam哥哥
出处:http://blog.jobbole.com

幂等的概念

大部分文章都会说,同一个操作,进行多次操作后,结果是一样的,就可以说这个操作是支持幂等的。感觉不太准确,比如一个http get操作,可能每次的结果都不一样,但是其实是幂等的。看了很多文章,感觉下面的定义比较准确:

一个操作如果多次任意执行所产生的影响(或者叫副作用),都是相同的。

创建订单的幂等

如果一个用户分两次下单,购买的商品都是一样的。

第一次请求:user1:购买一个商品product1;
第二次请求:user1:还是购买一个商品product1;

这种场景也很常见,是需要生成两个订单的。这样子看起来貌似创建订单的接口做不了幂等,因为业务数据一样的情况下,还是需要生成多个订单。但是这样子设计还是有个坑,万一创建订单的接口超时了呢?并且调用方进行了重试的话,那就可能变成用户其实想下一个单,但是订单系统其实生成了多个订单。比如说:

调用方发起创建订单的请求,订单系统收到了,并成功创建订单了。但是由于系统原因或者网络原因等,没有及时告知调用方订单已经创建成功,调用方一直等待回复,直到超时了。调用方再次发起了创建订单的请求,这个时候就可能会生成多个订单。

如果订单接口不支持幂等的情况下,如何应付这种情况呢?有两种方法

第一种:

当调用方调用订单接口超时了,是会收到异常的,这个时候调用方捕获到这个异常后, 不要进行重试操作了,调用订单的一个回滚接口,将订单取消掉。虽然看起来很low,但是还是有人这么做的。

第二种:

让订单系统提供一个订单是否创建成功的查询接口,根据一些关键业务字段去查询,如果查询到已经创建成功了,则调用方不要重试了。

上面两种方案都有人用过,但是都没实现幂等。其实针对上面的场景,用幂等来设计也不是很难。可以使用一个唯一的流水号ID,用来标识是不是同一个请求或者交易。这种ID通常都需要具备 全局唯一性。假设让客户端来生成这个ID,每个创建订单的请求生成一个唯一的ID。那么订单系统如何根据来实现幂等呢?通常有两种。

第一种:

先将这个ID保存到一个流水表里面,并且流水表中将这个ID设置为 UNIQUE KEY,如果插入出现冲突了,则说明这个创建订单的请求已经处理过了,直接返回之前的操作结果。

第二种:

根据ID读取流水表,如果没有读取到,则创建订单和插入流水表。如果读取到了,则返回之前的操作结果。

不建议使用第二种方式,因为大部分情况下的请求都不是重试来的,让100%的请求都要去读取流水表,实在是不应该。另外,读取流水表的操作也是有潜在风险的,因为用数据库的读检查来确保数据存在性可能因为竞争而不生效,存在竞态条件。

建议用第一种方案,因为本来流水表就是要插入,顺便利用 UNIQUE KEY的冲突特性来判断。

现在我们用第一种方案完整描述一下整个处理过程。

当调用方携带流水号ID调用创建订单的接口,如果出现超时了,调用方不知道订单到底创建成功还是失败,这个时候,用 同一个流水号进行重试,订单系统虽然收到了两个请求,但是由于流水号ID是同一个,可以根据流水表来做幂等操作。并告知对方订单创建成功与否。

这里又有一个坑,万一调用方进行重试的时候,重新生成一个流水号,那就没得救了,会生成多个订单了。这个只能让客户端来保证了。

关于多重幂等

假设创建订单的接口在创建订单的时候,还需要依赖一些外部系统,如果订单创建接口实现了幂等,但是外部接口没有实现幂等的话,还是可能出现 幂等漏洞。属于整个链路幂等的问题了。好复杂。目前还没想好如何处理这种情况呢。

思考题

调用方创建唯一ID,服务端用流水表这种方式实现幂等,非常依赖这个唯一ID。万一这个ID丢失了呢?咋破?目前我也在思考这个问题。

创建订单实现幂等的一点思考,首发于 文章 - 伯乐在线

相关 [幂等 思考] 推荐:

创建订单实现幂等的一点思考

- - 文章 – 伯乐在线
大部分文章都会说,同一个操作,进行多次操作后,结果是一样的,就可以说这个操作是支持幂等的. 感觉不太准确,比如一个http get操作,可能每次的结果都不一样,但是其实是幂等的. 看了很多文章,感觉下面的定义比较准确:. 一个操作如果多次任意执行所产生的影响(或者叫副作用),都是相同的. 如果一个用户分两次下单,购买的商品都是一样的.

电商课题:幂等性

- - 博客园_旁观者
幂等性的数学表达:f(f(x)) = f(x). 幂等性是系统接口对外的一种承诺. 幂等性指的是,使用相同参数对同一资源重复调用某个接口的结果与调用一次的结果相同. 幂等性的一个实现是,使你的接口必须返回 0(成功),即使这时资源或动作已经停止并且无工作要完成. 防范 POST 重复提交. HTTP POST 操作既不是安全的,也不是幂等的(至少在HTTP规范里没有保证).

HTTP幂等性概念和应用

- rockmaple - 酷壳 - CoolShell.cn
[ 感谢 Todd 同学投递本文 ]. 基于HTTP协议的Web API是时下最为流行的一种分布式服务提供方式. 无论是在大型互联网应用还是企业级架构中,我们都见到了越来越多的SOA或RESTful的Web API. 为什么Web API如此流行呢. 我认为很大程度上应归功于简单有效的HTTP协议.

实战!聊聊幂等设计

- - 掘金 架构
大家好,我是捡田螺的小男孩. 公众号: 捡田螺的小男孩. 幂等是一个数学与计算机科学概念. 在数学中,幂等用函数表达式就是: f(x) = f(f(x)). 比如求绝对值的函数,就是幂等的, abs(x) = abs(abs(x)). 计算机科学中,幂等表示一次和多次请求某一个资源应该具有同样的副作用,或者说,多次请求所产生的影响与一次请求执行的影响效果相同.

终极思考

- wei - 牛博国际
我的海淀剧院演讲门票放出后,八小时卖了四百多张,同事们说,日. 我淡淡地说,别这样,也许正是因为便宜才这么好卖嘛. 一转身我马上就打电话给老婆,操. 早知道就他妈把票价定高一点啦,真倒霉......干. 很大程度上,这可以解释两件事:1.为什么已婚事业男性的健康状况会相对好一些. 2.为什么在社会上受到尊重和认可的事业男性在老婆的眼里都是傻逼.

分布式幂等问题解决方案三部曲

- - SegmentFault 最新的文章
文章目的:本文旨在提炼一套分布式幂等问题的思考框架,而非解决某个具体的分布式幂等问题. 在这个框架体系内,会有一些方案举例说明. 文章目标:希望读者能通过这套思考框架设计出符合自己业务的完备的幂等解决方案. (1)背景介绍,为什么会有幂等. (2)什么是幂等,这个定义非常重要,决定了整个思考框架. (3)解决幂等问题的三部曲,也是作者的思考框架.

Kafka笔记—可靠性、幂等性和事务 - luozhiyun - 博客园

- -
这几天很忙,但是我现在给我的要求是一周至少要出一篇文章,所以先拿这篇笔记来做开胃菜,源码分析估计明后两天应该能写一篇. Kafka只对“已提交”的消息(committed message)做有限度的持久化保证. 当Kafka的若干个Broker成功地接收到一条消息并写入到日志文件后,它们会告诉生产者程序这条消息已成功提交.

高并发下如何保证接口的幂等性?

- -
接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题. 本文分享了一些解决这类问题非常实用的办法,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考. 不知道你有没有遇到过这些场景:. form表单时,保存按钮不小心快速点了两次,表中竟然产生了两条重复的数据,只是id不一样. 接口超时问题,通常会引入了.

一文理解如何实现接口的幂等性

- -
幂等性衍生到软件工程中,它的语义是指:函数/接口可以使用相同的参数重复执行, 不应该影响系统状态,也不会对系统造成改变. 举一个简单的例子:正常设计的查询接口,不管调用多少次,都不会破坏当前的系统或数据,这就是一个幂等操作. 在分布式系统中, 由于分布式天然特性的时序问题以及网络的不可靠性(机器、机架、机房故障、电缆被挖断等等), 重复请求很常见,接口幂等性设计就显得尤为重要.

消息幂等(去重)通用解决方案,RocketMQ

- - 薛定谔的风口猪
消息中间件是分布式系统常用的组件,无论是异步化、解耦、削峰等都有广泛的应用价值. 我们通常会认为,消息中间件是一个可靠的组件——这里所谓的可靠是指,只要我把消息成功投递到了消息中间件,消息就不会丢失,即消息肯定会至少保证消息能被消费者成功消费一次,这是消息中间件最基本的特性之一,也就是我们常说的“AT LEAST ONCE”,即消息至少会被“成功消费一遍”.