原文地址:http://blog.csdn.net/array7/article/details/46477423

吕毅,百度公司资深研发工程师,传统的LAMP人。 
2012年从新浪平台架构部加入百度移动服务事业群组(MSG)某业务线(以下简称“A”)。在百度期间,随着产品线发展和业务上QPS增长,架构设计方面略有所获,对移动端业务、优化有独特的理解和方法。

分享内容抢先看

本次分享介绍了A对抢购业务的设计实践,主要包含如下主题: 
1. 抢购业务介绍 
2. 具体抢购项目中的设计 
2.1. 如何解耦前后端压力 
2.2. 如何保证商品库存可靠 
2.3. 如何在业务中多放对账 
3. 项目总结 
4. Q & A

抢购、闪购,从国外风靡后,国内各类网站都开始做相似的业务,我们耳熟能详的唯品会、淘宝、京东都有这类业务。抢购,更多出现在电商网站。那么,今天和大家一起学习下抢购业务形态的业务架构设计。

1.抢购业务介绍


我们常见的抢购业务分两种: 限时抢购、限量抢购,我简单分了下这些case,如下图: 
 

想必小米的抢购运营的最火爆了,每发一款新品,都限量发售,每次搞的大家心里痒痒的。记得之前还因为抢购太火爆,站点打不开,崩溃了。那么问题来了:为什么抢购总是引发RD、OP恐慌?我理解是,爆品太火爆,瞬时请求太大,导致业务机器、存储机器都在抢购高峰时扛了太多压力。那么,我们今天以一个抢购业务场景为例,看看如何扛住压力,做好抢购业务!假设,这时候我们接到了产品层面的需求,如下图: 

PM也挺呵呵的,又要有时段的要求、又要有限量的要求,大而全呐! 
不过,对于咱们RD同学,也不是问题,我们一起来看看,如何设计业务架构,把需求满足的棒棒哒! 
首先,我们冷静的看看需求。

需求说:商品数据来自资源方。(哦,我们没有商品数据。) 
需求说:每天要有好几场抢购,每场抢购都有商品限制(哦,有点商场促销还限量甩的feel) 
需求说:商品要基于用户位置排序(哦,移动端业务嘛,这种需求总是有的) 
需求说:balabala……

2.具体抢购项目中的设计


通过我们先行的抢购需求分析,我们画一个粗略的流程图,如下: 
 
我们将自身简单划为两部分:业务层、数据层,并且旁路设计一个“运营控制”环节。 
当然,数据源自第三方嘛,我们的数据层基于第三方资源数据构建。 
这时,我们来看看这个草图里几个库和几个数据流,是怎样的。

首先,看看库。

数据层的“商品库”,显而易见,用于存储第三方商品数据,通过第三方推、我们拉的方式来构建这个数据库信息。数据库层的“抢购计划”库,主要由旁路的“运营控制”环节产生的数据,由运营同学来维护抢购场次、商品数量。

业务层的“抢购库”,其实是商品库的子集,由运营同学勾选商品并配好该商品放出多少用于抢购,发布到业务层面的抢购库中。

业务层的Transaction Data,一会我们讲到与第三方对账时候,我们再说它。

2.1 如何解耦前后端压力


我们此时回顾下目录,目录中我们讲,如何隔离前后端压力呢?做法是: 
1. 让我们业务的压力,不会传递到资源方,避免造成资源方接口压力同比增长。所以,我们自己建了商品库,此时,第三方笑了。 
2. 业务层与数据层解耦,我们让抢购库位于业务层,让商品库位于数据层。因为我们可以想象到,抢购高峰来临时,查询“商品还有没有?”的请求是最多的,若“有没有”这种高频请求每次都去数据层,那我们其实就将业务、数据耦合在一起了,那么,就有了抢购库这个子库,在业务层抗压力。(这里可以明确的是,数据层的商品库为关系型存储,业务层的抢购库为nosql的)

有了业务层的nosql(我们就用redis吧)抗高频压力,数据层的商品库笑了。 
这里就可以抛一个思想了:我们的架构设计中,需要分解压力,在互联网项目中,来自于用户的大流量不少见,这些流量最终都会落到一个地方,就看我们的设计如何分解这个压力了,如何避免它层层传递。抛个case,我们的水平分布业务机器,也是考虑通过水平扩展实例的方式,来分解大流量压力。 
不扯概念的东西了,我们回归我们的抢购业务。 
有了简单的分层设计,解决的大家都担心的压力问题,我们就看看抢购业务的时序是怎样的。 
我们的时序图分两个视角来说明: 
1. 商品的角度; 
2. 用户的角度; 
商品角度的时序图,从左到右:资源方、数据层、旁路-运营控制层、业务层。如下图: 
 
录入商品 即商品从资源方发布到我们的数据层,形式可以是通过API、可以是通过文件传输、可以是我们去拉去。通过我们的代码逻辑,记录到我们数据层的“商品库DB”。 
有了自建的商品库的数据,我们的运营同学就可以基于商品库设计每天的抢购场次(此事就有Web界面的事情,这里我们就不展开这块了),运营同学创建好一批抢购场次,记录在数据层的“抢购计划”这一关系型数据库中。 
运营同学创建完抢购场次后,没完事,还得应产品需求,基于商品库,配置每场抢购场次中覆盖的商品,及商品的数量。这些抢购场次内的商品配置,会简单的记录在业务层的“抢购库”中。(抢购库记录的信息较为简单,例如商品库中ID为123123的商品有100件,业务层的抢购库中只存ID 123123商品运营配了在第X场抢购中有5件) 
此时,数据层的 商品库有了资源方数据、数据层的 抢购计划库中有运营配的抢购计划,业务层的抢购库中每场抢购活动中商品的情况。 
那么,业务层此时就可以基于时间,来展示运营配的抢购场次了。业务层,如何展示,这块就是拼装数据、前端效果了,这里也不展开了。 
假设此事某场场次的抢购活动已经开始,我们再看看用户角度的时序图: 

用户点击某个商品的抢购按钮,业务层代码首先去看看抢购计划库此时是否开始(此步可缓存、也可cache在前端页面或Client,若有cache的话,此步可忽略)。若抢购在进行中,此时业务代码需要查询商品在本次抢购中的库存还有否(高频请求,即图中“争取名额”阶段)。 
“争抢名额”这块,一会我们细讲,先把时序图说完。 
若用户抢到了名额,就允许用户跳转到第三方的支付页面产生消费。(此时第三方笑了),产生消费后,第三方自己的库存-1,并且可以实时、异步、完事对账的方式通知我们。

2.2 如何保证商品库的库存可靠


此时,我们回顾下目录,“如何保证商品库的库存可靠”。 
我们其实是将商品库的子库前置在业务层抗压力。那么,如何保证大家的库存情况稳定,不会因为抢购业务,导致库存波动影响用户体验。这里就需要提一个业务RD需要关注的问题,需要做好取舍。要么,我们保证大家看到的库存规律一致,要么,我们保证单个用户看到的库存规律一致。若保证大家看到的库存减少的规律一致,且同一时刻库存大家看到的库存都一样。这就对系统有数据强一致性要求,需要很大成本,还只能逐渐逼近此要求要求的效果。而我们若选择后者,仅保证单个用户看到的库存减少规律一致,虽放弃了数据强一致,但以更少的时间尽可能实现了最好的效果。所以,我们用到了用户来排队,若抢到名额了,在抢购库中的库存 –(减减),这样单用户操作期间,能看到规律的减少,不会出现此事看剩10个,一会看还有11个的情况。这时我们说如何内部排队,如何来控制“查询商品在本次抢购中的库存还有否(高频请求)”这个高频请求。 

我们构建商品维度的cache,上图中虽然说是“队列”,我们可以用redis的list来真正实现个队列,也可以通过 /–来实现。

假设商品A,运营配了20件,此事来了N多用户的请求,业务代码都会来查询cache_prefix_a_id这个队列的长度,若队列长度≤0,则有权去–(减减)抢购库的商品库存。若队列长度在20件内,则通过业务代码内的等待来等待队头的位置,然后获得抢购权限。若队列长度太长,则可以直接返回,认为商品已被抢空。

这时插入一个运营配库的时序,便于大家理解。该时序图有详细的说明和标注,就不展开了,如下图: 

此时,我们可以想象,若上游用户的请求压力是N,这个N会压在业务层的抢购库,俗话说“责任止于此”:P

2.3 如何和第三方多方对账


那么,我们回顾目录“如何和第三方多方对账”? 
这里就要提到“Transaction Data”这个库了。 
Transaction ID为用户维度的Session记录,用户从进入抢购业务开始,产生一个Transaction ID,该Transaction ID生命周期截止到用户跳转去第三方支付为止。期间在生活服务中产生的浏览、抢购行为均会挂靠到该Transaction ID之下,并会在跳转去第三方支付页时携带该Transaction ID凭证。最主要的是需要记录下:用户获得商品名额后,跳转去第三方时,这一行为。 
考虑到Transaction ID为抢购业务中,用户操作行为的关键字段,值需要保证唯一。故此处可以采用发号器之类的能力。 
我们构建的Transaction Data记录,就可以按照DailyRun的方式,与第三方对账,来fix两方数据库库存不一致等问题。 
为什么会产生我们和资源方的库存不一致,可能是因为用户在第三方消费后,第三方callback我们时候失败造成,也可能是因为用户跳去第三方后并没有真正支付,但我们的商品库、抢购库的库存都已经减少造成的。原因可能有很多,对账机制是必要的。

3.项目总结


最后,我们回顾回顾设计,压力问题在业务层解决了,库存不一致问题我们通过对账机制解决了,产品的需求我们也通过旁路可配解决了,嗯,可以喝杯茶,发起评审,评审通过后开始写代码了。 :)

感谢大家。分享中的数据强一致那块,以及如何做取舍,都是很有意思的点,都可以展开聊很久,这里没展开,大家可以事后查查资料。

4.Q & A


Q1.1:请问,防刷是怎么做的?一般抢购都有很大优惠。如果有人恶意刷,那正常的用户就失去了购买的机会。比如,抢购的商品数为1000,有人恶意刷了900,那只有 100 被正常用户抢到。等恶意抢到的 900 经过后面的支付环节验证后,可能已经过了抢购时间了。就算恶意抢到的 900 都支付成功,那对正常用户也是不公平的。 
A1.1:在这个业务场景中,我们做的是商品展示、商品的购买权的发放,真正产生消费是在第三方。那么,用户刷的问题,需要我们和第三方支付页面一起来控制。在用户通过排队机制,获得了购买名额后,跳转去第三方时候,我们按照和第三方约定的加密方式传递加密信息,第三方按照约定的解密方式解密成功后才允许用户支付,加密解密的过程中可以带具有生命周期的内容。这样,用户在高频请求支付页面获取商品时候,实际只有:1)加密对;2)第一次,才可能获得。不过,第三方都是为了销售出商品,所以这类合作的成功几率不大。恶意刷,的确会在我们的业务层面展示商品没量了。导致想买的用户没了机会。但上面Q1的回复,可以保证第三方不受损。对于你提到的这种刷的情况,若想在我们业务层规避,我想这就是一个通用的防SPAM的问题了。这块自己真懂得不多。:P 
Q1.2:要想准确的放刷,判断的维度就多,逻辑就复杂;与之矛盾的,抢购要求的是响应迅速。 
A1.2:对的,@裴宝庆|SinoIOV ,抢购业务因为请求压力大、热门商品抢购并发高,切忌增加过多逻辑,切忌过多后端依赖,越简单效果越好。我们在设计系统时候,很多事不是咱们一个系统能cover的,多少需要一些前置模块、能力的构建ready后,我们的系统才能run的不错。还是建议 @裴宝庆|SinoIOV 快构建帐号体系、用户消费记录这两部分。

Q2:对账这里,只是和第三方去对比商品的库存量吗,金额这里是否去对比? 
A2:对账,其实是对比的消费数据。避免出现我们统计今日产生了X件商品共价值Y的消费,第三方给出的是消费了N件共M价值的消费。避免金额不一致,造成结算、分成等问题的出现。我想你问题中的库存量的diff问题,还得靠第三方定期的通过我们数据层的接口来update他们提供的商品。其实在我们的商品库中,商品不一定只允许第三方提供,也可以允许第三方通过接口减少商品嘛,比如和一个卖水果的第三方合作,第三方上周发布说有100件,但这周线下热销,只剩20件了,我们也应该允许第三方来update到一个低值。但这样,我们的系统中就会复杂挺多。

Q3:防刷,避免第三方的推广效果达不到问题。 
A3:对的,用户ID维度、IP维度,都是有效办法。看具体场景。有帐号体系的业务,用用户ID维度效果最好,借助存储记录下每个用户的购买记录,来控制就好。市面上的电商网站,基本是抢购业务都需要登录,并且限制每件商品单人购买数量,其实就是通过存储记录用户的消费,并且再次产生消费前查询并增加代码逻辑来控制。

Q4:每次抢购活动的时候用一套新的验证码? 
A4:验证码这个东东,属于图灵测试嘛,只要测试方法好,并且尽可能保证每次产生的验证信息从未出现过且无规律,就是好的验证码啦。:)

互联网秒杀设计--转载相关推荐

  1. 从Larbin看互联网爬虫设计(转载)

    来源: http://blog.chinaunix.net/u1/34978/showart_422243.html 从Larbin看互联网爬虫设计 于敦德 2005.12.16 转载请注明出处 互联 ...

  2. 互联网产品设计常用文档类型-BRD、MRD、PRD、FSD

    互联网产品设计常用文档类型-BRD.MRD.PRD.FSD 摘自:互联网产品设计常用文档类型-BRD.MRD.PRD.FSD 2017-03-16 1 BRD Business Requirement ...

  3. 交互设计师 mysql_UCD火花集2:有效的互联网产品设计 交互/信息设计 用户研究讨论...

    作者:UCDChina 编著 出版社:人民邮电出版社 编辑推荐: UCDChina网站的Angela.白鸦.千鸟等人的产品设计笔记大公开,成为一个优秀的产品设计师.产品经理必读的作品. 内容简介: 本 ...

  4. 五子棋AI设计(转载)

    五子棋AI设计(转载) 原始链接:https://blog.csdn.net/pi9nc/article/details/10858411 2013-09-01 22:15:52 pi9nc 阅读数 ...

  5. 亿级流量架构实战之秒杀设计

    前面已经写了很多亿级流量的文章, 中间讲了各种处理思路, 这儿将这些思路与业务综合起来, 情形一就是秒杀, 提到秒杀, 很多人都会觉得这是一件技术要求很高的事情, 因为这涉及到超大访问量(可能瞬间千万 ...

  6. 《UCD火花集2:有效的互联网产品设计 交互/信息设计 用户研究讨论》一2.3 交互设计师容易犯的错误:把自己禁锢在解决方案之中...

    本节书摘来自异步社区<UCD火花集2:有效的互联网产品设计 交互/信息设计 用户研究讨论>一书中的第2章,第2.3节,作者 UCDChina,更多章节内容可以访问云栖社区"异步社 ...

  7. IXDC 2018 | 打动人心的互联网保险设计

    背景:7月18日,2018 国际体验设计大会(IXDC)  在北京举行,今年大会主题是"构建体验新框架:人性化·智能化·平台化". 200位多位来自Google.Facebook. ...

  8. 头条Java后台3面(含答案):事务+List集合+慢查询SQL+Redis+秒杀设计

    头条Java一面 1.讲讲jvm运行时数据库区 2.讲讲你知道的垃圾回收算法 3.jvm内存模型jmm 4.内存泄漏与内存溢出的区别 5. select.epoll 的区别?底层的数据结构是什么? 6 ...

  9. 最新蚂蚁金服Java面试题:Docker+秒杀设计+RocketMQ+亿级数据设计

    蚂蚁金服一面: 1 自我介绍 2 讲一下ArrayList和linkedlist的区别,ArrayList的扩容方式,扩容时机. 3 hashmap的实现,以及hashmap扩容底层实现. 4 NIO ...

最新文章

  1. poj1738 an old stone game
  2. 应用基础计算机一级的题目,计算机应用基础一级模拟题
  3. JAVA输出希腊union,希腊文化认为,最为抽象的艺术形式是()。
  4. pioneer软件VoLTE测试步骤,Pioneer操作说明.docx
  5. 广告和间谍程序克星Spybot使用说明
  6. linux 学习笔记(基础)
  7. java 数独 gui,GitHub - fagen/sudoku: 数独终局生成器和GUI
  8. win7 C盘满如何清理
  9. c语言中阶乘相加怎么表示_c语言求阶乘累加和
  10. 软件需求分析学习日记(一)需求工程概述
  11. 关于微信公众号支付接口开发遇到的奇葩问题,始终返回get_brand_wcpay_request:fail。
  12. 华为云文档数据库服务更安全
  13. 求二维形状渐变的算法
  14. Hadoop项目实战---黑马论坛日志分析
  15. 关于Intellij IDEA中文注释字体不统一的解决办法
  16. python语言通过()来体现语句逻辑关系_【单选题】Python语言通过( )来体现语句之间的逻辑关系。...
  17. SAP HANA SQL获取当前日期加若干天后的日期
  18. 兔子繁殖问题(python递归解决)
  19. 软考证书电子版下载地址和软考成绩查询
  20. “Rimon天气”Android天气查询软件项目总结

热门文章

  1. php call_user_func_array 性能,php-call_user_func_array是否太慢?
  2. mysql引擎层存储层_MySQL存储底层技术:InnoDB底层原理解读
  3. qt vs 不出来dos窗口_VS嵌入QT后,建立QT工程后printf和cout无效,无法产生控制台应用程序窗口,需设置工程属性...
  4. linux意外重启分析,Linux关机重启流程分析
  5. 怎么修复手机服务器,新手机怎么恢复旧手机上的所有数据?
  6. android 调整字体,android设置:调整字体大小
  7. 第十七届全国大学生完全车模组竞速赛方案 - 草案
  8. Several ports (8005, 8080, 8009) required by Tomcat v5.5 Server at localhost are already in use.....
  9. php dir opendir,php opendir()列出目录下文件的方法代码
  10. python 分词包_NLP相关python包