文档章节

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

霖vv
 霖vv
发布于 2016/10/01 20:37
字数 1486
阅读 225
收藏 0
点赞 0
评论 0

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

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

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

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

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

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

##尝试

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

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

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

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

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

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

image

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

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

与1)的发放相比,数据库换成响应更快的缓存。但是仍然不是原子操作。插入和读取缓存还是有时间间隔。在极致的情况下还是存在重复操作的情况。
此方法优化后,每周1笔重复操作。

image

####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进来则往表里面插入数据:

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

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

image

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

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

还是以订单退款为例子:

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

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

如果=1(获得锁): 可以操作。

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

link

image

##总结:

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

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

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

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

本文转载自:http://mogu.io/prevent-duplicate-requests-4

共有 人打赏支持
霖vv
粉丝 22
博文 92
码字总数 67859
作品 0
海淀
程序员
0到1再到100 蘑菇街搜索与推荐架构的探索之路

丁小明,花名小宝,蘑菇街搜索技术团队负责人。2011年底加入蘑菇街,2013年开始负责搜索团队,见证了蘑菇街一路蓬勃发展的历程,也和团队一起从零起步摸爬滚打,打造了蘑菇街的搜索推荐体系,...

雪夜凋零 ⋅ 2017/07/28 ⋅ 0

iOS应用架构谈 组件化方案

iOS应用架构谈 开篇 iOS应用架构谈 view层的组织和调用方案 iOS应用架构谈 网络层设计方案 iOS应用架构谈 本地持久化方案及动态部署 iOS应用架构谈 组件化方案 简述 前几天的一个晚上在infoQ...

hejunbinlan ⋅ 2016/07/18 ⋅ 0

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

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

十二缸帕萨特 ⋅ 2015/10/12 ⋅ 0

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

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

十二缸帕萨特 ⋅ 2015/09/24 ⋅ 0

[5.19 线下活动]Docker Meetup杭州站—拥抱Kubernetes,容器深度实践

对本次线下活动感兴趣的朋友,欢迎点击此处报名,领取免费票。 今年3月,Docker刚刚过完5岁生日,五年期间,Docker也逐渐在技术和实践方面趋于成熟,更是在去年年底主动拥抱Kubernetes。 5月...

wangyiyungw ⋅ 05/10 ⋅ 0

最前沿的容器技术有哪些?腾讯、华为、思科等 6 位顶尖专家为你解答!

点击上方“CSDN”,选择“置顶公众号” 关键时刻,第一时间送达! 容器革命已经来临,随着 Docker 拥抱 Kubernetes,容器领域风云变幻,Kubernetes 逐步走强,以 Docker 为代表的容器技术在国...

csdnnews ⋅ 2017/12/13 ⋅ 0

释放技术的想象:自主可控的电商平台构建之路

欢迎大家前往腾讯云社区 ,获取更多腾讯海量技术实践干货哦~ 过往,大多数依托于第三方平台的电商企业,经常遇到诸如恶性竞争、主导权被分割、平台假货影响厂商形象等问题,极度影响口碑和销...

腾讯云社区 ⋅ 2017/12/13 ⋅ 0

蘑菇街基于Docker的私有云实践

12月6日,由 【DBA+社群】中间件用户组 主办的“中间件走进云计算——企业级互联网架构技术沙龙”在上海成功举办。本次沙龙特邀蘑菇街平台技术部高级架构师郭嘉, 为大家分享过去一年时间里,...

郭嘉 ⋅ 2015/12/11 ⋅ 0

《iOS应用架构谈 组件化方案》和《蘑菇街 App 的组件化之路》

用户需求一览 申请者iOS撸道夫 项目大致代码行数500 项目 GitHub 地址 项目备注 如何理解iOS组件化? 围观神仙打架,反革命工程师《iOS应用架构谈 组件化方案》和蘑菇街Limboy的《蘑菇街 Ap...

hejunbinlan ⋅ 2016/07/18 ⋅ 0

移动端IM中大规模群消息的推送如何保证效率、实时性?

本文原题为“大规模群消息推送如何保证实时性?”,来自瓜子二手车IM负责人:封宇,本次内容有修订,感谢原作者(原文链接在文末)。 1、编者注 众所周之,群聊是移动端IM的服务端技术难点所...

JackJiang2011 ⋅ 2017/11/20 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

思路分析 如何通过反射 给 bean entity 对象 的List 集合属性赋值?

其实 这块 大家 去 看 springmvc 源码 肯定可以找到实现办法。 因为 spirngmvc 的方法 是可以 为 对象 参数里面的 list 属性赋值的。 我也没有看 具体的 mvc 源码实现,我这里只是 写一个 简...

之渊 ⋅ 38分钟前 ⋅ 0

vim使用手册--配对括号的查找

1、把光标放在标记有(、[或{处。 2、按%字符 3、此时光标的位置应当在配对的括号处 4、再次按%就可以跳回配对的第一个括号处。

dragon_tech ⋅ 42分钟前 ⋅ 0

c++ 、object-c printf,%02X和%x有什么区别 ?

%x即按十六进制输出,英文字母小写,右对齐。 %02X有以下变化:英文字母变大写,如果输出字符不足两位的,输出两位宽度,右对齐,空的一位补0。超过两位的,全部输出。 如果不用 %02x 会出现...

yizhichao ⋅ 47分钟前 ⋅ 0

Spring源码解析(七)——实例创建(中)

前言 上一节讲到了,Spring 会根据实例的作用域执行不同的创建逻辑,分别是 Singleton、Prototype、其他 Scope,其中 Singleton 会调用 getSingleton 从缓存中获取,缓存中没有才会创建实例;...

MarvelCode ⋅ 47分钟前 ⋅ 0

Thrift RPC实战(六) spring集成thrift

1.服务端设置 对泛型Thrift Service的支持, 通过采用spring配置以及反射的方式来实现.对于一个服务提供者来说,需要提供端口,接口以及接口实现类,因此在接口中spring配置文件中配置如下 <!...

lemonLove ⋅ 49分钟前 ⋅ 0

oracle11g自动分区使用

为什么使用自动分区? 在oracle11g之前,oracle是不支持自动分区功能的,这就可能导致我们系统在运行一段时间之后,就需要看看分区是否创建或者写触发器进行创建分区,否则就会导致数据无法入...

strict_nerd ⋅ 今天 ⋅ 0

Spring mvc ViewResolver视图解析器实现机制

概要 我们在controller里面经常这样return一个ModelAndView。 return new ModelAndView("userList", "users", userList); DispatcherServlet 靠 ViewResolver 把 userList 解析为 /WEB-INF......

轨迹_ ⋅ 今天 ⋅ 0

策略模式

1.策略模式 策略模式是同一个行为的不同处理办法。策略模式和简单工厂模式的区别:1.策略模式主要是方法的执行方式,工厂模式要获取的对象。两者的侧重点不同。 ...

Cobbage ⋅ 今天 ⋅ 0

行政区划代码转为字典形式

原数据为: http://www.mca.gov.cn/article/sj/xzqh/2018/201804-12/201804-06041553.html 手动替换了一下格式,并使用下面的代码处理. # 输入格式s = """110000:北京市110101:东城区1101...

漫步海边小路 ⋅ 今天 ⋅ 0

android apk 签名

创建key,需要用到keytool.exe (位于C:\Program Files\Java\jdk1.6.0_10\bin目录下),使用产生的key对apk签名用到的是jarsigner.exe (位于C:\Program Files\Java\jdk1.6.0_10\bin目录下),把...

国仔饼 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部