https://blog.csdn.net/xichenguan/article/details/78085801

指导思想

应用分层、工作流分阶段幂等;

接口幂等

分布式系统中,接口幂等性是系统可行性论证的第一个步骤。
一个软件系统中,所有的接口都可以归结为增删改查四大类;下面我们对这四大类接口进行分析;

查询和删除

查询和删除业务,天然的具有幂等的特性;
1. 查询操作
在数据不变的情况下,查询一次和查询多次,查询结果是一样的;
2. 删除操作
删除一次和多次删除的结果都是把数据删除;

新增和更新

带有新增和更新的业务接口,如果不做幂等性处理,很可能没调用一次,都会对系统的存储产生影响;

新增业务

新增业务类接口,我们要解决如下两个问题
1. 同一个用户用同样的数据多次请求同一个接口(不管是什么原因多次提交,他应该只请求一次)
2. 不同用户的提交同样的数据请求同一个接口;
第一个问题可以通过防重复提交来解决;业务数据连同Token,一起提交给接口,同一个Token,只能被处理一次(这里要注意,只能被处理一次,应该改成只能被正确的处理一次,也就是说,我们应该缓存某次新增业务处理的结果,如果上一次请求时出现某些异常,比如数据库连接失败,用户再次提交的时候,我们应该放行用户的这次请求,当然有些异常就不需要放行了,比如提交的业务数据不对等);
第二个问题是无法解决的,一个开放的系统,不能杜绝两个不同的客户端(用户)同时请求;但是可以交给数据的最后防线,存储层;通过唯一索引或唯一组合索引可以防止新增数据存在脏数据 (当表存在唯一索引,并发时新增报错时,再查询一次就可以了,数据应该已经存在了,返回结果即可) ;

注意:
Token防重复提交,只需要网关这层控制即可;Token的处理机制,还需要缓存调用的处理结果,以判断是否需要放行后续的重试请求;

更新业务

系统中的大部分业务都可以归属到更新业务,比如禁用用户、电商秒杀等等,只要是有更新操作的,不管是不是还有其他的操作,都归结到更新业务;
更新业务接口,不仅需要有表单防重复提交的验证,还需要有下面这些更精细的控制,以防止高并发环境中出现脏读,幻读等引起错误的数据更新结果;
更新业务接口幂等性解决方案一般是通过各种层面的锁和CAS机制;

悲观锁
悲观锁,select for update,整个执行过程中锁定要操作的记录;

乐观锁
更新业务的接口,比如订单付款等,需要综合使用尽可能多的信息来逐步验证逐步减少直至杜绝重复消息重复处理的概率;基本思路是CAS(Compare And Set);
可以参考下面的两篇文章体会一下:
1. 《架构师之路-库存扣多了,到底怎么整》
2. 订单操作,利用订单编号和订单的状态机(序列号)

测试用例

通过下面的方法可以初步验证接口幂等性的健壮性:
1. 同一个请求,多次提交到同一台节点,多次提交到不同的节点
2. 同一个请求,同时到达同一个节点,同时到达到不同的节点
3. 有逻辑先后顺序的消息、请求乱序的处理,比如创建订单的请求和支付订单的请求,不能保证第一个请求先于第二个请求到达服务器;

参考

架构师之路-库存扣多了,到底怎么整 https://blog.csdn.net/xichenguan/article/details/78085801
高并发的核心技术-幂等的实现方案 http://825635381.iteye.com/blog/2276077
分布式系统互斥性与幂等性问题的分析与解决 https://tech.meituan.com/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html
基础篇(一)幂等性 http://blog.csdn.net/tjgamejx2/article/details/51011425
分布式系统—幂等性设计 http://blog.csdn.net/mine_song/article/details/74725990
分布式系统的接口幂等性设计 http://blog.csdn.net/rickiyeat/article/details/71087747
后端接口的幂等性 http://blog.csdn.net/jks456/article/details/71453053
API接口非幂等性问题及使用redis实现简单的分布式锁 http://blog.csdn.net/rariki/article/details/50783819
GitHub Idempotent https://github.com/johncook59/Idempotent
GitHub Ddripping https://github.com/lrwinx/Ddripping