2019独角兽企业重金招聘Python工程师标准>>>

#防重复处理总结
##背景
在业务开发中,我们常会面对防止重复请求的问题。当服务端对于请求的响应涉及数据的修改,或状态的变更时,可能会造成极大的危害。重复请求的后果在交易系统、售后维权,以及支付系统中尤其严重。

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

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

但前端的限制仅能解决少部分问题,且不够彻底,后端自有的防重复处理措施必不可少,义不容辞。

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

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

##尝试

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

后端防重复处理的方式,我们先后尝试了三种:

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

这种方式简单直观,从DB查询出来的退款详情(包括状态)往往还可以用在后续逻辑中,没有花额外的工作专门应对重复请求的问题。

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

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

####2)基于缓存数据状态的验证
Redis存储查询轻量快速。在request进来的时候,可以先记录在缓存中。后续进来的request每次进行验证。整个流程处理完成,清除缓存。以退款为例子:

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

与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锁机制';

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

——成功,则可以继续操作(相当于获取锁);
——失败,则说明有操作在进行。

操作完成后,删除此条记录。(相当于释放锁)
目前已经上线,等待下周的数据统计。

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

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

还是以订单退款为例子:

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

如果>1(不能获得锁): 说明有操作在进行,删除。如果=1(获得锁): 可以操作。

操作结束(删除锁):删除这个计数器。
要了解计数器,可以参考:

link

##总结:

PHP语言自身没有提供进程互斥和锁定机制。因此才有了我们上面的尝试。

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

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

爱迪生尝试了1600多种材料选择了钨丝发明了灯泡,实践出真知。遇到问题,和问题斗争,最后解决问题是一个最大提升自我的过程,不但加宽自己的知识广度,更加深了自己的技能深度。达到目标之后的成就感更是不言而喻。

转载于:https://my.oschina.net/zhaolin/blog/754110

蘑菇街防重复请求处理的实践与总结相关推荐

  1. 防重复请求处理的实践与总结

    #防重复处理总结 ##背景 在业务开发中,我们常会面对防止重复请求的问题.当服务端对于请求的响应涉及数据的修改,或状态的变更时,可能会造成极大的危害.重复请求的后果在交易系统.售后维权,以及支付系统中 ...

  2. 蘑菇街支付金融Android单元测试实践

    蘑菇街支付金融Android单元测试实践 2016-04-26  邹勇  移动开发前线 本文为『移动前线』群在4月23日的分享总结整理而成,转载请注明来自『移动开发前线』公众号. 嘉宾介绍 邹勇(网名 ...

  3. springboot 主键重复导致数据重复_Springboot实现防重复提交和防重复点击(附源码)...

    背景# 同一条数据被用户点击了多次,导致数据冗余,需要防止弱网络等环境下的重复点击 目标# 通过在指定的接口处添加注解,实现根据指定的接口参数来防重复点击 说明# 这里的重复点击是指在指定的时间段内多 ...

  4. 【深度学习】深度学习安防的探索与实践

    [深度学习]深度学习安防的探索与实践 文章目录 1 概述 2 安防领域的深度学习应用 3 当深度学习遇到系统和网络安全3.1 前馈神经网络概述3.2 基于深度学习的日志数据异常检测3.3 MAD-GA ...

  5. redis+aop防重复提交

    文章目录 1.防重复提交注解 2.redis分布式锁 3.防止重复提交Aop 之前有记录一篇用redis+拦截器防重复提交的内容: redis+拦截器防重复提交 1.防重复提交注解 @Target(E ...

  6. vue防重复点击(指令实现)

    快速点击按钮会重复多次调用接口,防止出现这样的情况 全局定义,方便调用 新建plugins.js export default {install (Vue) {// 防重复点击(指令实现)Vue.di ...

  7. 由防重复点击引发的幂等性问题思考

    HTTP/1.1中对幂等性的定义是:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外).也就是说,用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而 ...

  8. vue --- 按钮的防重复点击事件

    按钮的防重复点击事件 :loading属性 当loading = true时:按钮会显示一个旋转的圆圈.此时的按钮是无法点击的 当loading = false时:按钮重新变为可点击的状态 可以通过使 ...

  9. 浅谈C#在网络波动时防重复提交

    前几天,公司数据库出现了两条相同的数据,而且时间相同(毫秒也相同).排查原因,发现是网络波动造成了重复提交. 由于网络波动而重复提交的例子也比较多: 网络上,防重复提交的方法也很多,使用redis锁, ...

最新文章

  1. MybatisPlus处理Mysql的json类型
  2. iOS应用开发入门(3)——点击button控制textview
  3. mysql中char,varchar,text
  4. java判断或_Java 条件判断
  5. Spring4有条件
  6. 昨天7月21号,笑笑又生病了
  7. lisp 设计盘形齿轮铣刀_用AutoLISP程序设计盘形齿轮铣刀渐开线齿形
  8. Interval(区间类问题)
  9. 创建student数据表_创建数据库、表和更改表
  10. python airflow_airflow python 包采坑指南
  11. c 语言翻译软件,分享一款 程序员秒懂的翻译软件
  12. 用python处理文本数据(5)
  13. 【Android】canScrollVertically和canScrollHorizontally
  14. Iterative Reweighted Least Squares
  15. TR单据自动生成TO单并确认
  16. 爬虫项目3 - 股票数据爬取
  17. 怎么做 HDFS 的原地平滑缩容?
  18. 计算机键盘分为哪几个键区,标准键盘一般分为哪四个键区
  19. 在visio里面插入带圆圈的数字字符。
  20. 360校园招聘笔试题

热门文章

  1. c语言100列作业,C语言经典例题100例——C语言练习实例72解答(链表)
  2. matplotlib:图形绘制常用增加修饰和设置参数
  3. 模具设计的四个步骤总结
  4. java采用Process.destroy无法停止子进程
  5. [Unity 代码写法整理]嵌套判断问题(一)
  6. 北华大学计算机程序设计算法提高训练营个人赛(无L)
  7. 云时代,最好用的MySQL客户端工具推荐
  8. vue-cli打包后,找不到css、js文件问题的解决
  9. 记录一款绿色便携的sqlist3数据库编辑工具SQLiteSpy
  10. 4个手机使用必备小常识,没几个人全知道,了解完绝对涨知识