You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
14 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 04 | 指日可待:一步一步搭建秒杀系统(下)
你好,我是志东,欢迎和我一起从零打造秒杀系统。
在上节课中我们完成了3个项目的搭建并给项目做了大致的最终目标职能划分。那么接下来我们就可以对秒杀业务的流程做一个详细的梳理了给出要实现的交互逻辑然后按照交互需求提炼出各个项目具体要提供的接口之后按照各个接口要实现的功能去具体**开发我们的业务代码**,最终实现秒杀活动开展的全闭环。话不多说,现在就开始吧。
## **秒杀业务流程梳理**
根据我们之前对秒杀业务的介绍,一场完整的秒杀活动的大概流程是这样的,我们一起梳理一下。
1. 运营人员在秒杀系统的运营后台,根据指定商品,创建秒杀活动,指定活动的开始时间、结束时间、活动库存等。
2. 活动开始之前由秒杀系统运营后台worker将活动商品的标识更改为秒杀标识。
3. 用户进入到商详页面时,系统会判断当前商品标识,如果是秒杀标识,则去查询当前商品的秒杀活动数据,判断是否正式开始,即通过商品标识+活动时间来判断活动是否真正开始。如果活动时间还没有到,页面可以是禁售展示,也可以是倒计时展示,或者是按正常价格售卖,这个可以按实际业务需求来定。
4. 当活动已经开始,用户进入商详页,可以看到立即抢购的按钮,这里我们可以通过增加一些逻辑判断来限制按钮是否可以点击,比如是否设置了抢购用户等级限制,是否还有活动库存,是否设置了预约等等。如果都没限制,用户可以点击抢购按钮,进入到秒杀结算页。
5. 在结算页,用户可更改购买数量,切换地址、支付方式等,这里的结算元素也需要按实际业务来定,更复杂的场景还可以支持积分、优惠券、红包、配送时效等,并且这些都会影响最终价格的计算。
6. 确认无误后用户提交订单在这里后端服务可以调用风控、限购等接口来完善校验都通过之后完成库存的扣减和订单的生成。如果结算页支持了第5步中提到的一些虚拟资产则还需要做对应的抵扣。
7. 订单完成后,根据用户选择的支付方式跳转到对应的页面,比如在线支付就跳转到收银台,货到付款的话,就跳到下单成功提示页。
**整个时序图如下:**
![图片](https://static001.geekbang.org/resource/image/2d/72/2d40cc6f38298361411f6f0fda810572.jpg?wh=1758x1568)
这样一来,秒杀业务从开始到用户抢购,到最后的活动结束关闭,整个流程就形成**闭环**了。当然上面列举的也只是主要的流程,实际业务可以在不同节点依据实际需求添加不同的业务功能,这个你可以灵活调整。
## **系统提供接口梳理**
从上面的时序图中,我们可以非常清楚地归纳出秒杀系统需要提供的**主要接口**
1. 活动数据查询接口:查询活动相关信息,包括开始、结束时间等。
2. 进结算页页面H5接口结算页H5并通过Ajax异步加载结算页数据。
3. 结算页页面初始化渲染所需数据的接口:大体包括活动信息、商品信息、结算信息(用户的地址、虚拟资产、价格等等)。
4. 结算页页面用户行为操作接口:支持地址列表查看和选择,虚拟资产的查看和使用等等,并在操作后更新页面价格相关信息。
5. 结算页提交订单接口:支持秒杀活动商品下单。
当然这是秒杀网关系统所需要提供的接口,但是要完整地实现整个秒杀功能,我们还得需要以下功能。而这些个功能点,不需要做到秒杀的主流程系统里,一般都有秒杀的运营系统来提供**相应能力**,简列如下:
1. 秒杀活动的创建:创建秒杀活动,主要要素包括活动名称、参加活动的商品、活动库存、活动单次限购数量、活动开始时间、活动结束时间。
2. 秒杀活动的查看:查看活动信息、活动状态等。
3. 秒杀活动的开始:一般活动都是提前创建,并在活动即将开始之前几分钟,自动更改活动商品标识,这样商详页就能区分出当前商品是普通商品还是秒杀商品了,然后执行不同的业务分支逻辑。
4. 秒杀活动的结束:活动时间到期或者运营人员手动关闭,并将活动商品的秒杀标识去掉。
同时为了我们整个秒杀功能的展示我们还需要有模拟商品信息的查询后台查看客户端商品的详情页面秒杀入口以及下单成功后的收银台页面这3个一般情况下不属于秒杀整个系统的功能范畴了这里仅仅是为了更好地展示秒杀的整个链路所做的模拟。
我们需要将所有网关入口都封闭在demo-nginx本地为了模拟一些业务功能会将部分入口放在demo-web方便访问。而所有操作数据库的入口都放在demo-support并且为了模拟整个秒杀的流程业务我们需要以下3张表来支撑
![图片](https://static001.geekbang.org/resource/image/23/aa/235361620fe038f528986d95abdd28aa.png?wh=1360x494)
一切就绪,接下来,我们就根据上面的设计,开始投入到实际的开发中去吧。
## **秒杀业务的实现**
这里,详细的开发细节就不说了,因为上面已经理清了所有的接口和对应的能力,实际的代码开发并不复杂,相信对你来说也不是难事。
这里我主要说一下demo-nginx的配置因为我们前面说过初版先用比较传统的结构来实现秒杀这样一来主要功能的开发都放在了demo-web和demo-support所以我们的demo-nginx现在还不会有太多的配置更改。只需要将对应的接口URL匹配配置到domain.com里即可实现对应接口请求的接收和分发修改后文件内容如下
![图片](https://static001.geekbang.org/resource/image/a0/3a/a05006cb11f22922dcc15aff5086a73a.png?wh=1920x1340)
这里结算页用户行为操作的接口,可能是一个或是多个,如果没有特别的处理,可以配置一个模糊匹配,并直接打到后端服务,不需要做额外处理。(其中 ~\* 表示启用正则匹配,同时忽略字母大小写,如果遇到请求静态资源不到的情况,也可以参照此方式配置)
省略掉中间的开发过程,我们先来看下最终要实现的效果吧,同时你也可以根据下面的交互,去理解一下我们为什么会要求提供上面的那些接口,**其中各个阶段要调用的接口,我都用橘色特别标识出了。**
### **第一步**
我们先在数据库商品表中初始化一条商品信息,用来模拟参加秒杀活动。然后再通过商品信息查询接口,在浏览器页面查看商品的信息(根据商品编号查询),这是个后台功能,主要是看下商品的基本信息,比如名称、价格、商品标识,特别是商品标识在参加秒杀活动前后的一个变化。
这里为了方便我把入口放在了demo-web服务我们通过demo-web的端口号访问对应的URL即可如下图所示
![图片](https://static001.geekbang.org/resource/image/07/ae/07b628c8cba3f7ddc132fe62ff9d4cae.png?wh=1920x702)
### **第二步**
用第一步的商品,创建一个秒杀活动。这个功能正常是放在运营系统里的,通过页面来进行秒杀活动的管理,这里为了方便教学,就直接调用秒杀活动创建接口,来完成秒杀活动的创建,效果如下:
![图片](https://static001.geekbang.org/resource/image/5e/cb/5e833346968a6024974bf3cea03131cb.png?wh=1920x294)
创建完成后,我们调用活动信息查询接口,来查看刚刚创建的活动,页面只是简单地列举了一下活动的主要元素,如下图所示:
![图片](https://static001.geekbang.org/resource/image/79/ae/79766a407df9d1b9f23fc64746cc82ae.png?wh=1920x553)
这里我们将参加秒杀活动的商品价格设为了998原价是1298并且设置了4件库存活动的开始时间是当前时间结束时间是两天后。正常情况下活动是已经开始了需要通过worker来启动活动并完成商品标识的修改但我本地模拟是没有加定时worker功能的想通过HTTP接口的方式来触发所以这里还是显示活动未开始。
### **第三步**
我们先不触发活动开始我们先模拟客户端进商详页看看现在活动入口页面的样式同样是通过URL方式直接访问demo-web效果如下
![图片](https://static001.geekbang.org/resource/image/0d/0b/0db0fa8ed2e1290a2ae399798566800b.png?wh=1629x1634)
可以看到活动虽然创建了但还没有开始所以这里展示的还是普通商品的名称和价格。下面我们就来手动触发一下让活动开始直接调用demo-web的活动开始接口
![图片](https://static001.geekbang.org/resource/image/ea/d9/ea02da1e2f1060da58c693123b7c63d9.png?wh=1920x254)
这样活动就触发成功了,这个时候,我们再分别看下活动信息和商品信息,看看都有什么变化:
![图片](https://static001.geekbang.org/resource/image/af/db/afe9a2273b8c356286e9e12f260df5db.png?wh=1920x527)
![图片](https://static001.geekbang.org/resource/image/14/f5/1458086b58abfa425f25cf1ed6e53af5.png?wh=1920x413)
正如我们所期望的,活动的状态变成了进行中,同时商品标识也变成了秒杀标识。
### **第四步**
秒杀活动开始后,我们再次进入到商详页。
![图片](https://static001.geekbang.org/resource/image/2c/a4/2c8074edfb7aa59a52b66745e8ebf5a4.png?wh=1611x1675)
对比之前的商详页,我们可以看到商品的图片、名称、价格展示,都已经变成了活动配置的,同时按钮也变成了立即抢购,并可以点击,说明到这里我们一切都进展的很顺利!
### **第五步**
这时我们点击立即抢购按钮去进入到秒杀结算页。这里点击按钮调用的是进结算页页面H5接口在加载了HTML后JavaScript通过Ajax调用结算页页面初始化渲染所需数据的接口去渲染页面展示效果如下
![图片](https://static001.geekbang.org/resource/image/9b/55/9b470cac45f0bb1ed04afb738b822455.png?wh=1642x1707)
页面的结算元素,这里只简单地展示了几个,当然你可以根据实际需要去灵活填充。展示中的结算页支持修改购买数量,修改后总金额会随之变化,而且有单次够买数量的限制,同时也允许用户切换支付方式、修改地址等操作,这里做的用户操作,会调用结算页页面用户行为操作接口。
### **第六步**
操作结算元素完成后我们就可以提交订单了调用的是结算页提交订单接口。在经过一系列的校验之后完成库存的预占和订单的生成并返回收银台的URL完成下单成功后的跳转动作如下图所示
![图片](https://static001.geekbang.org/resource/image/e7/e6/e7d9d60920619cf83989acd498af92e6.png?wh=1491x1512)
这里是跳转到了收银台的模拟页面,这时我们再回头看看我们的活动库存:
![图片](https://static001.geekbang.org/resource/image/21/f6/21414cc311c4db1c64fe98919173caf6.png?wh=1920x552)
由4件变成了3件说明成功做了库存扣减。后续用户可以继续完成支付相关操作那么用户的一次抢购行为也就结束了当然如果用户放弃了支付或是取消了订单那么需要将预占的库存再恢复回去。
我们这里可以模拟多次抢购,当我们把商品买完时:
![图片](https://static001.geekbang.org/resource/image/79/b9/790f1ayybea6e532717f4c0a6d64cab9.png?wh=1920x514)
再去商详页看一下:
![图片](https://static001.geekbang.org/resource/image/fd/09/fde6c5146e3fcd835be8e0bd3e04df09.png?wh=1726x1706)
可以发现,展示的虽然还是活动相关数据,但是按钮变成灰色的了,因为没有活动库存了。
### **第七步**
正常情况下当商品售完时活动也应该关闭掉了。因为我们没有worker所以我们就来手动关闭一下和触发活动开始一样调用活动关闭的接口去关闭活动并将商品的标识恢复成普通商品如下图所示
![图片](https://static001.geekbang.org/resource/image/bb/61/bbc0cd6cf4a72ec774c3222b642e4961.png?wh=1920x282)
成功后,我们再看下刷新下商详页:
![图片](https://static001.geekbang.org/resource/image/46/06/46248c7bcc93f888abdd4d2800b18906.png?wh=1610x1697)
可以看到页面已经恢复到最初的状态了,同时查看下活动信息与商品信息:
![图片](https://static001.geekbang.org/resource/image/f0/6a/f0178715f9024597e58047462fbb6d6a.png?wh=1920x551)
![图片](https://static001.geekbang.org/resource/image/7d/75/7d8f7a46d73d74e727ced50c74439575.png?wh=1920x391)
活动显示已经结束,商品标识也变回了普通商品,一切都符合预期。
到此,我们就完整地支持了一场秒杀活动的开展,秒杀系统中的一些关键链路也得以完美复现,并顺利地实现了我们设定的那个小目标——实现一个最简的秒杀系统。
## 小结
在这节课中,我们为了开发一个最简的秒杀系统,针对秒杀流程做了详细的梳理,画出了系统间的交互过程,同时明确列出了整个秒杀系统所需要提供的主要接口和能力,并且为了整个秒杀业务场景的再现,还加入了一些辅助接口,总体归纳如下:
![图片](https://static001.geekbang.org/resource/image/54/6b/5408aa838c6b05b8e732de0847c7ed6b.png?wh=1354x1258)
有了这些详细设计的指引,我们可以很快速地开发出一个最简的秒杀系统,并能在本地实现“秒杀活动的创建->活动开始的打标->从商详页进秒杀结算页->提交订单->活动的关闭与去标”的完整交互。一方面可以帮助我们熟悉和理解秒杀的整个流程,另一方面也可以让我们以“摸的着”的方式去近距离地接触秒杀系统,并感受秒杀系统的设计之美。
## 思考题
现在我们已经自己动手实现了整个秒杀业务,也让我们有了去优化秒杀系统的基石。现在你是时候该去认真思考一下,以上提供的每个接口的瓶颈点在哪里,会出现什么问题,以及如何有效应对了。
以上就是这节课的全部内容,欢迎你在评论区和我讨论问题,交流经验!