这一次,彻底弄懂“秒杀系统”( 三 )

订单处理流程
这里的“扣减服务”完成了最简单的扣减库存工作,并没有和其他项目服务打交道,更没有访问数据库 。
 

这一次,彻底弄懂“秒杀系统”

文章插图
 
 
订单流程示意图
后面的流程相对比较复杂,我们先看图,根据图示来讲解:
  • 首先,扣减服务作为下单流程的入口,会先对商品的库存做扣减 。同样它会检查商品是否还有库存?
  • 由于订单对应的操作步骤比较多,为了让流量变得平滑,这里使用队列存放每个订单请求,等待订单处理服务完成具体业务 。
  • 订单处理服务实现多线程,或者水平扩展的服务阵列,它们不断监听队列中的消息 。一旦发现有新订单请求,就取出订单进行后续处理 。
注意,这里可以加入类似 ZooKeeper 这样的服务调度来帮助,协调服务调度和任务分配 。
  • 订单处理服务,处理完订单以后会把结果写到数据库 。写数据库是 IO 操作,耗时长 。
  • 所以,在写数据库的同时,会把结果先写入缓存中,这样用户是可以第一时间查询自己是否下单成功了 。
  • 结果写入数据库,这个操作有可能成功也有可能失败 。
  • 为了保证数据的最终一致性,我们用订单结果同步的服务不断的对比,缓存和数据库中的订单结果信息 。
一旦发现不一致,会去做重试操作 。如果重试依旧不成功,会重写信息到缓存,让用户知道失败原因 。
  • 用户下单以后,焦虑地刷新页面查看下单的结果,实际上是读到的缓存上的下单结果信息 。
虽然,这个信息和最终结果有偏差,但是在秒杀的场景,要求高性能是前提,结果的一致性,可以后期补偿 。
数据库设计
讲完了秒杀的处理流程,来谈谈数据库设计要注意的点 。
数据估算
前面说了秒杀场景需要注意隔离,这里的隔离包括“业务隔离” 。就是说我们在秒杀之前,需要通过业务的手段,例如:热场活动,问卷调查,历史数据分析 。通过他们去估算这次秒杀可能需要存储的数据量 。
这里有两部分的数据需要考虑:
  • 业务数据
  • 日志数据
前者不言而喻是给业务系统用的 。后者,是用来分析和后续处理问题订单用的,秒杀完毕以后还可以用来复盘 。
分表分库
对于这些数据的存放,需要分情况讨论,例如,MySQL 单表推荐的存储量是 500W 条记录(经验数字) 。
如果估算的时候超过了这个数据,建议做分表 。如果服务的连接数较多,建议进行分库的操作 。
数据隔离
由于大量的数据操作是插入,有少部分的修改操作 。如果使用关系型数据来存储,建议用专门的表来存放,不建议使用业务系统正在使用的表 。
这个开头提到了,数据隔离是必须的,一旦秒杀系统挂了,不会影响到正常业务系统,这个风险意识要有 。表的设计除了 ID 以外,最好不要设置其他主键,保证能够快速地插入 。
数据合并
由于是用的专用表存储,在秒杀活动完毕以后,需要将其和现有的数据做合并 。其实,交易已经完成,合并的目的也就是查询 。
这个合并需要根据具体情况来分析,如果对于那些“只读”的数据,对于做了读写分离的公司,可以导入到专门负责读的数据库或者 NoSQL 数据库中 。
压力测试
构建了秒杀系统,一定会面临上线,那么在上线之前压力测试是必不可少的 。
我们做压力测试的目的是检验系统崩溃的边缘在哪里?系统的极限在哪里?
这样才能合理地设置流量的上限,为了保证系统的稳定性,多余的流量需要被抛弃 。
压力测试的方法
合理的测试方法可以帮助我们对系统有深入的了解,这里介绍两种压力测试的方法:
  • 正压力测试
  • 负压力测试
正压力测试 。每次秒杀活动都会计划,使用多少服务器资源,承受多少的请求量 。
可以在这个请求量上面不断加压,直到系统接近崩溃或者真正崩溃 。简单的说就是做加法 。
 
这一次,彻底弄懂“秒杀系统”

文章插图
 
 
正压力测试示意图
负压力测试 。在系统正常运行的情况下,逐步减少支撑系统的资源(服务器),看什么时候系统无法支撑正常的业务请求 。
例如:在系统正常运行的情况下,逐步减少服务器或者微服务的数量,观察业务请求的情况 。说白了就是做减法 。


推荐阅读