##背景

在业务开拓中,我们常会面对防止重复要求的问题。
当做事端对付要求的相应涉及数据的修正,或状态的变更时,可能会造成极大的危害。
重复要求的后果在交易系统、售后维权,以及支付系统中尤其严重。

前台操作的抖动,快速操作,网络通信或者后端相应慢,都会增加后端重复处理的概率。

php判断重复请求防前端反复要求处置办法的总结 Angular

前台操作去抖动和防快速操作的方法,我们首先会想到在前端做一层掌握。
当前端触发操作时,或弹出确认界面,或disable入口并倒计时等等,此处不细表。

但前真个限定仅能办理少部分问题,且不足彻底,后端自有的防重复处理方法必不可少,义不容辞。

在接口实现中,我们常哀求接口要知足幂等性,来担保多次重复要求时只有一次有效。

查询类的接口险些总是幂等的,但在包含诸如数据插入,多模块数据更新时,达到幂等性会比较难,尤其是高并发时的幂等性哀求。
比如第三方支付前台回调和后台回调,第三方支付批量回调,慢性能业务逻辑(如用户提交退款申请,商家赞许退货/退款等)或慢网络环境时,是重复处理的高发场景。

##考试测验

这里针对“用户提交退款申请”的例子,解释一下考试测验过的防重复处理方法的效果。

后端防重复处理的办法,我们先后考试测验了三种:

####1)基于DB中退款订单状态的验证

这种办法大略直不雅观,从DB查询出来的退款详情(包括状态)每每还可以用在后续逻辑中,没有花额外的事情专门应对重复要求的问题。

这种查询状态后进行验证的逻辑,从代码上线后就一贯存在于所有含状态的业务逻辑处理中,必不可少。
但对付防重复处理效果并不好:在前端添加防重复提交前,每周均匀在25笔;前端优化后,每周降到7笔。
这个数量占总退款申请数的3%%,一个仍旧无法接管的比例。

理论上,任意次要求只要在数据状态更新之前都完成了查询操作,则业务逻辑的重复处理就会发生。
如下图所示。
优化的方向是减少查询到更新之间业务处理韶光,可降落空档期的并发影响。
极致情形下如果查询和更新变成了原子操作,则就不存在我们当前的问题。

####2)基于缓存数据状态的验证

Redis存储查询轻量快速。
在request进来的时候,可以先记录在缓存中。
后续进来的request每次进行验证。
全体流程处理完成,打消缓存。
以退款为例子:

I. 每次退款发起申请,读取缓存中是否有以orderId为key的值 II. 没有,则往缓存中写入以orderId为key的value III.有,则解释有该订单的退款正在进行。
IV. 操作完清缓存,或者缓存存值的时候设置生命周期12345

与1)的发放比较,数据库换成相应更快的缓存。
但是仍旧不是原子操作。
插入和读取缓存还是有韶光间隔。
在极致的情形下还是存在重复操作的情形。

此方法优化后,每周1笔重复操作。

####3)利用唯一索引机制的验证

须要原子性操作,想到了数据库的唯一索引。

新建一个TradeLock表:

CREATE TABLE `TradeLock` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`type` int(11) NOT NULL COMMENT '锁类型',`lockId` int(11) NOT NULL DEFAULT '0' COMMENT '业务ID',`status` int(11) NOT NULL DEFAULT '0' COMMENT '锁状态',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Trade锁机制';12345678912345678

每次request进来则往表里面插入数据:

——成功,则可以连续操作(相称于获取锁);——失落败,则解释有操作在进行。
123

操作完成后,删除此条记录。
(相称于开释锁)

目前已经上线,等待下周的数据统计。

####4)基于缓存的计数器验证:

由于数据库的操作比较花费性能,理解到redis的计数器也是原子性操作。
果断采取计数器。
既可以提高性能,还不用存储,而且能提升qps的峰值。

还是以订单退款为例子:

每次request进来则新建一个以orderId为key的计数器,然后+1。

如果>1(不能得到锁): 解释有操作在进行,删除。
如果=1(得到锁): 可以操作。
1234

操作结束(删除锁):删除这个计数器。

要理解计数器,可以参考:

link

##总结:

PHP措辞自身没有供应进程互斥和锁定机制。
因此才有了我们上面的考试测验。

网上也有文件锁机制,但是考虑到我们的分布式支配,建议还是用缓存。

在大并发的情形下,程序各种情形的发生。
特殊是涉及到金额操作,不能有一分一毫的差距。
以是在大并发要互斥的情形下可以考虑3、4两种方案。