时间:2022-08-28 13:03:20来源:网络整理
抢购业务介绍
抢购和闪购在国外风靡之后,国内各家网站也开始做类似的业务。我们熟悉的唯品会、淘宝、京东都有这样的业务。快速购买等更多内容出现在电子商务网站上。那么,今天就和大家一起学习一下抢购业务形态的业务架构设计。
我们常见的抢购业务分为两种:限时抢购和限时抢购。我对这些案例做了简单的划分,如下图:
想必小米的抢购操作最为火爆。每一款新品都是限量发售的,每一次都让人心痒难耐。记得当时因为抢购太火了,网站打不开就崩溃了。那么问题来了:为什么抢购总是让RD和OP恐慌呢?我理解爆款产品太火爆,瞬时请求量太大,导致业务机和存储机在高峰期承受的压力太大。那么,今天就以抢购业务场景为例,看看如何顶住压力,做好抢购业务!假设此时我们收到了一个产品层面的需求,如下图:
PM也很好,有时间段的要求,有数量有限,大而全的要求!
不过,对于我们的RD同学来说,这不是问题。让我们看看如何设计业务结构并满足需求!
首先,让我们来看看需求。
需求说:商品数据来自资源端。(哦,我们没有产品数据。)
需求说:每天会有几次抢购,每次抢购都有商品限制(哦,有一些店铺促销,感觉有限)
需求说:产品要根据用户位置分类(哦,移动业务,总有这样的需求)
需求说:巴拉巴拉……
特定抢购项目中的设计
通过我们之前对抢购需求的分析,我们绘制了一个粗略的流程图如下:
我们简单地把自己分成两部分:业务层、数据层,绕过了“运控”环节的设计。
当然,数据来自第三方,我们的数据层是基于第三方资源数据构建的。
这时候我们来看看这个sketch中的几个库和几个数据流长什么样子。
首先,看看图书馆。数据层的“商品库”,显然是用来存储第三方商品数据的,数据库信息是由第三方push和我们pull构建的。数据库层的“抢购计划”库主要由绕过“运营控制”环节产生的数据生成,运营同学维护抢购会话和商品数量。
业务层的“抢购库”其实是商品库的一个子集。运营同学选择商品,匹配要发布多少商品进行抢购,发布到业务级抢购库。
业务层的事务数据,我们后面讲和第三方对账的时候再讲。
如何解耦前后压力
此时让我们回顾一下目录。在目录中,我们将讨论如何隔离前后端压力?做法是:
让我们业务的压力不传递到资源端,避免资源端接口的压力同比增加。所以我们自己建了一个商品库,这时候第三方笑了。
业务层与数据层解耦。我们把抢购库放在业务层,商品库放在数据层。因为我们可以想象,当抢购高峰来临时,查询“还有货吗?” 将是最需要的。如果“有没有”的高频请求每次都到数据层,那么我们实际上会把业务和数据放到数据层。耦合在一起,那么就有了抢购库的分库,可以在业务层抗压。(这里明确数据层的商品库是关系存储,业务层的抢购库是nosql)
用业务层的nosql(我们用redis)来抵抗高频压力,数据层的商品库笑了。
这里有一个想法:在我们的架构设计中,我们需要分解压力。在互联网项目中,来自用户的大流量并不少见电商系统 高并发库存系统设计,而这些流量最终会落到一个地方。这取决于我们的设计如何分解这种压力。现在,如何避免它逐层传递。举个例子,我们业务机器的横向分布也考虑了实例横向扩展的方法,以分解大流量的压力。
让我们回到我们的抢购业务。
简单的分层设计,就可以解决大家担心的压力问题。让我们来看看抢购业务的时机。
我们的时序图从两个角度说明:
产品的角度;
用户的观点;
从商品的角度看时序图,从左到右:资源端、数据层、旁路操作控制层、业务层。如下所示:
商品输入是指商品从资源端发布到我们的数据层。表单可以通过API,通过文件传输,或者我们可以拉出来。通过我们的代码逻辑,记录到我们数据层的“商品库数据库”中。
有了自建商品库的数据,我们运营同学可以根据商品库设计日常抢购(这件事有web界面,这里就不展开了),运营同学创建一个批次快照购买会话记录在数据层的“采购计划”的关系数据库中。
操作同学创建好抢购会话后,需要根据商品需求,根据商品库配置每个抢购会话涵盖的商品和商品数量。这些抢购会话中的商品配置将简单记录在业务层的“抢购库”中。(snap-purchase库中记录的信息比较简单,比如商品库中有100个ID为123123的商品,业务层的snap-purchase库中只存储了ID为123123的商品。有是第 X 次抢购中的 5 件商品。
此时,数据层的商品库有资源侧数据,数据层的抢购计划库有运营分配的抢购计划,业务层的抢购库有信息每个抢购活动中的商品数量。
那么,此时业务层就可以按时间显示操作分配的抢购情况。业务层,怎么展示,这部分是组装数据和前端效果的,这里就不展开了。
假设某事件的抢购已经开始,我们从用户的角度来看一下时序图:
当用户点击一个产品的snap-buy按钮时,业务层代码首先查看snap-buy计划库是否在这个时候启动(这一步可以缓存,也可以缓存在前端页面或者客户端,如果有缓存,这一步可以忽略)。如果正在进行抢购,则业务代码需要检查该产品的库存是否还在本次抢购中(高频请求,即图中“占位”阶段)。
一会儿我们会讲“抢位”,先把时序图讲完。
如果用户抢到额度,则允许用户跳转到第三方支付页面产生消费。(这时候第三方笑了),消费产生后,第三方自己的库存为-1,可以实时、异步、完全对账的方式通知我们。
如何保证商品库的可靠库存
至此,我们回顾了目录,《如何保证商品库库存的可靠性》。
其实我们把商品库的分库放在业务层前面是为了顶住压力。那么,如何保证大家的库存是稳定的,库存的波动不会因为商家的抢购而影响用户体验。这里需要提一个业务RD需要注意的问题,需要我们做出选择。要么,我们保证每个人看到的库存规则是一致的,要么我们保证单个用户看到的库存规则是一致的。如果保证大家看到的库存减少规律是一致的,大家同时看到的库存也是一样的。这就需要系统的数据强一致性,需要很大的成本,只能逐渐接近这个要求的效果。如果我们选择后者,我们只保证单个用户看到的库存减少规则是一致的。虽然我们放弃了强数据一致性,但我们可以在更短的时间内达到最好的效果。因此,我们使用用户来排队。如果我们抢了配额,我们会抢购仓库中的库存——(减少),这样在单个用户的操作过程中,我们可以看到有规律的减少,不会有剩下10个的情况。一会儿还有11个。这个时候我们讲内部怎么排队,怎么控制“检查产品的库存是否还在这个抢购中(高频请求)”的高频请求。我们可以在更短的时间内达到最佳效果。因此,我们使用用户来排队。如果我们抢了配额,我们会抢购仓库中的库存——(减少),这样在单个用户的操作过程中,我们可以看到有规律的减少,不会有剩下10个的情况。一会儿还有11个。这个时候我们讲内部怎么排队,怎么控制“检查产品的库存是否还在这个抢购中(高频请求)”的高频请求。我们可以在更短的时间内达到最佳效果。因此,我们使用用户来排队。如果我们抢了配额,我们会抢购仓库中的库存——(减少),这样在单个用户的操作过程中,我们可以看到有规律的减少,不会有剩下10个的情况。一会儿还有11个。这个时候我们讲内部怎么排队,怎么控制“检查产品的库存是否还在这个抢购中(高频请求)”的高频请求。
我们建立商品维度的缓存。上图中虽然是“队列”,但是我们可以使用redis的列表来实际实现一个队列,也可以通过/-来实现。
假设商品A有20件,有N多个用户的请求,业务代码会查询队列cache_prefix_a_id的长度。如果队列长度小于等于0,则有权去-(减少)抢购库存库中的商品。如果队列长度在20条以内,则通过业务代码中的等待等待队列头的位置,然后获得抢购权。如果排队太长,可以直接退货,以为商品已经售罄。
这时候插入一个运行配置库的时序,方便大家理解。时序图有详细的说明和注释,不再展开,如下图所示:
此时,我们可以想象如果上游用户的请求压力为N,这个N会压在业务层的抢购库上。俗话说“责任到此为止”
如何与第三方核对账目
那么,让我们回顾一下目录“如何与第三方和解”?
这里我们将提到“交易数据”库。
Transaction ID 是用户维度的会话记录。当用户进入快购业务时,会生成一个Transaction ID。交易ID生命周期结束,直到用户跳转到第三方支付。期间,生活服务中产生的浏览、抢购行为会与交易ID关联,跳转第三方支付页面时携带交易ID凭证。最重要的是记录:用户在获得产品配额后跳转到第三方时的这种行为。
考虑到Transaction ID是抢购业务中用户操作行为的关键字段,值需要唯一。所以这里可以使用发射器之类的能力。
我们构建的 Transaction Data 记录可以通过 DailyRun 的方式与第三方进行对账,以解决双方数据库库存不一致等问题。
我们与资源方库存不一致的原因可能是用户消费第三方后第三方未能给我们回电,也可能是用户跳转到第三方后并没有真正支付,但是我们的商品库,抢购库中的库存已经减少了。原因可能有很多,需要一个和解机制。
项目总结
最后我们对设计进行了回顾和审查,在业务层解决了压力问题,通过对账机制解决了库存不一致问题,通过旁路配置解决了产品需求。好了,我们可以喝杯茶,发起一个评审,评审通过后,开始写代码。:)
谢谢大家。分享中的数据是强一致的,如何取舍是很有意思的点。可以讨论很久。此处不展开。之后您可以查看信息。
问答
Q1:反刷是怎么做的?快照购买通常有很大的折扣。如果有人恶意刷,那么普通用户就失去了购买的机会。比如抢购的商品数量是1000件,有人恶意刷900件,普通用户只能抢到100件。恶意抢900在支付环节经过验证后,可能已经过了抢购时间。即使恶意抢900支付成功,对普通用户也是不公平的。
在这个业务场景中,我们做的是商品的展示和商品购买权的发放,真正的消费是在第三方。那么,用户刷单的问题需要我们和第三方支付页面来控制。用户通过排队机制获得购买额度并跳转到第三方后,我们按照与第三方约定的加密方式传输加密信息,第三方成功后才会允许用户付款按照约定的解密方式进行解密。流程可以承载具有生命周期的内容。这样,当用户在高频请求支付页面获取商品时,实际上只能获取到:1)加密对;2) 第一次。然而,第三方都是为了销售商品,所以这种合作方式不太可能成功。恶意刷单确实会说明我们业务层面的商品已经断货。这样一来,想购买的用户就没有机会了,但可以保证第三方不受损。这种刷机的情况,如果我们在业务层要避免的话,我觉得这是一般的反SPAM问题。我真的对这方面了解不多。
Q2:如果要准确放笔,判断维度多,逻辑复杂;与此相反,捕捉需要快速响应。
是的,因为请求压力大,热销产品抢购的高并发,不要添加太多逻辑,也不要太依赖后端。越简单越好。在我们设计系统的时候,很多事情是单一系统无法涵盖的。在需要一些前置模块和功能准备好之后,我们的系统可以运行良好。建议建立账户体系和用户消费记录。
Q3:对账是不是只是为了和第三方比较商品的库存,比较数量?
对账其实就是消费数据的对比。为了避免我们今天统计的总价值为Y的X件的消费,第三方给出了总价值为M的N件的消费。避免金额不一致,导致结算、分享等问题。我认为您问题中库存的差异问题取决于第三方通过我们数据层的接口定期更新他们提供的产品。其实在我们的商品库中,商品不一定只允许第三方提供,也可以允许通过接口减少商品。例如,我们与销售水果的第三方合作。第三方上周宣布有100件产品,但是这周线下销售,只剩下20件,我们还应该允许第三方更新到较低的值。但是这样一来,我们的系统就会复杂很多。
Q4:反刷,避免无法达到第三方推广效果的问题。
是的,用户ID维度和IP维度都是有效的方法。看具体场景。对于具有帐户系统的企业电商系统 高并发库存系统设计,使用用户 ID 维度效果最好。最好用存储来记录每个用户的购买记录,以便控制。市面上的电商网站基本都需要登录才能进行抢购业务,并且限制每件商品的购买次数。其实就是通过存储和记录用户的消费,再次产生消费前查询,加上代码逻辑来控制。
Q5:你们每次抢购活动都会使用一套新的验证码吗?
验证码属于图灵测试。只要测试方法好,保证每次生成的验证信息永远不会出现和不规则,就是一个好的验证码。
声明:文章仅代表原作者观点,不代表本站立场;如有侵权、违规,可直接反馈本站,我们将会作修改或删除处理。
图文推荐
2022-08-28 13:03:20
2022-08-28 12:10:04
2022-08-28 12:03:04
2022-08-28 11:03:32
2022-08-28 10:04:13
2022-08-28 09:02:10
热点排行
精彩文章
2022-08-26 19:10:18
2022-08-26 17:10:19
2022-08-26 14:01:10
2022-08-26 12:01:51
2022-08-26 10:01:08
2022-08-25 19:10:31
热门推荐