登录 |  注册
首页 >  规范·架构·案例 >  电商项目实战教程笔记 >  如何设计一个秒杀系统

如何设计一个秒杀系统

高并发下如何设计秒杀系统?

秒杀系统是网络商家为了促销等目的进行的网上限时抢购活动。比如某宝某东某夕夕上的秒杀。用户在规定的时间内,定时定量的秒杀,无论商品是否秒杀完毕,该场次的秒杀活动都会结束。

秒杀系统具有瞬时流量、高并发读、高并发写以及高可用等特点。秒杀时会有大量用户在同一时间进行抢购,瞬时并发访问量突然增加10倍,甚至100倍以上都有可能。


今天我们一起来看看,一套秒杀系统在架构设计上需要有哪些考量:

  • 秒杀场景的特点

  • 秒杀系统的架构设计思想主要有

  • 客户端设计:页面静态化

  • 代理层设计

  • 应用层设计

  • 数据库设计

  • 压力测试

  • 总结

秒杀场景的特点

    秒杀场景是电商网站定期举办的活动,这个活动有明确的开始和结束时间,而且参与互动的商品是事先定义好了,参与秒杀商品的个数也是有限制的。同时会提供一个秒杀的入口,让用户通过这个入口进行抢购。

    总结一下秒杀场景的特点:

    • 定时开始,秒杀时大量用户会在同一时间,抢购同一商品,网站瞬时流量激增。

    • 库存有限,秒杀下单数量远远大于库存数量,只有少部分用户能够秒杀成功。

    • 操作可靠,秒杀业务流程比较简单,一般就是下订单减库存。库存就是用户争夺的“资源”,实际被消费的“资源”不能超过计划要售出的“资源”,也就是不能被“超卖”。

    秒杀系统的架构设计思想主要有

    (1)缓存

    把部分业务逻辑迁移到内存的缓存或者Redis中,从而极大地提高并发读效率。

    (2)削峰

    杀开始的一瞬间,会有大量用户冲进来,所以在开始时会有一个瞬间流量峰值。如何使瞬间的流量峰值变得更平缓,是成功设计秒杀系统的关键。要实现流量的削峰填谷,一般的方法是采用缓存和MQ中间件。

    (3)异步

    将同步业务设计成异步处理的任务,以提高网站的整体可用性。

    (4)限流

    由于活动库存量一般都很少,只有少部分用户才能秒杀成功,所以需要限制大部分用户流量,只准少量用户流量进入后端服务器。

    客户端的设计:页面静态化

    • 活动页面是用户流量的第一入口,所以是并发量最大的地方。

      • 如果这些流量都能直接访问服务端,恐怕服务端会因为承受不住这么大的压力,而直接挂掉。

    • 活动页面绝大多数内容是固定的,比如:商品名称、商品描述、图片等。为了减少不必要的服务端请求,通常情况下,会对活动页面做静态化处理。用户浏览商品等常规操作,并不会请求到服务端。只有到了秒杀时间点,并且用户主动点了秒杀按钮才允许访问服务端。

    • 但只做页面静态化还不够,因为用户分布在全国各地,有些人在北京,有些人在成都,有些人在深圳,地域相差很远,网速各不相同。

    • 这就需要使用CDN,它的全称是Content Delivery Network,即内容分发网络。

    • 图片使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

    秒杀.jpg

    代理层设计

    说完了秒杀系统的前端设计,请求自然地来到了代理层。由于用户的请求量大,我们需要用负载均衡加上服务器集群,来面对如此空前的压力。

    在这一层是可以做缓存,过滤和限流的:

    秒杀架构设计2.jpg

    缓存,以 Nginx 为例,它可以缓存用户的信息。假设用户信息的修改没有那么频繁,即使有类似的修改也可以通过更新服务来刷新。总比从服务器上获取效率要高得多。

    过滤,既然缓存了用户信息,这里就可以过滤掉一些不满足条件的用户。注意,这里的用户信息的过滤和缓存只是一个例子。

    主要想表达的意思是,可以将一些变化不频繁的数据,提到代理层来缓存,提高响应的效率。

    应用层设计

    “秒杀系统”秒杀的是什么?无非是商品。对于系统来说就是商品的库存,购买的商品一旦超过了库存就不能再卖了。

    防止超卖

    超过了库存还可以卖给用户,这就是“超卖”,也是系统设计需要避免的。为了承受大流量的访问,我们用了水平扩展的服务,但是对于他们消费的资源“库存”来说,却只有一个。

    为了提高效率,会将这个库存信息放到缓存中。以流行的 Redis 为例,用它存放库存信息,由多个线程来访问就会出现资源争夺的情况。

    也就是分布式程序争夺唯一资源,为了解决这个问题我们需要实现分布式锁。假设这里有多个应用响应用户的订单请求,他们同时会去访问 Redis 中存放的库存信息,每接受用户一次请求,都会从 Redis 的库存中减去 1 个商品库存量。

    当任何一个进程访问 Redis 中的库存资源时,其他进程是不能访问的,所以这里需要考虑锁的情况(乐观,悲观)。

    Redis 缓存承载库存变量

    如果锁长期没有释放,需要考虑锁的过期时间,需要设置两个超时时间:

    资源本身的超时时间,一旦资源被使用一段时间还没有被释放,Redis 会自动释放掉该资源给其他服务使用。

    服务获取资源的超时时间,一旦一个服务获取资源一段时间后,不管该服务是否处理完这个资源,都需要释放该资源给其他服务使用。

    订单处理流程

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

    由于订单对应的操作步骤比较多,为了让流量变得平滑,这里使用队列存放每个订单请求,等待订单处理服务完成具体业务。

    订单处理服务实现多线程,或者水平扩展的服务阵列,它们不断监听队列中的消息。一旦发现有新订单请求,就取出订单进行后续处理。

    注意,这里可以加入类似 ZooKeeper 这样的服务调度来帮助,协调服务调度和任务分配。

    订单处理服务,处理完订单以后会把结果写到数据库。写数据库是 IO 操作,耗时长。

    所以,在写数据库的同时,会把结果先写入缓存中,这样用户是可以第一时间查询自己是否下单成功了。

    结果写入数据库,这个操作有可能成功也有可能失败。

    为了保证数据的最终一致性,我们用订单结果同步的服务不断的对比,缓存和数据库中的订单结果信息。

    一旦发现不一致,会去做重试操作。如果重试依旧不成功,会重写信息到缓存,让用户知道失败原因。

    用户下单以后,焦虑地刷新页面查看下单的结果,实际上是读到的缓存上的下单结果信息。

    虽然,这个信息和最终结果有偏差,但是在秒杀的场景,要求高性能是前提,结果的一致性,可以后期补偿。

    数据库设计

    讲完了秒杀的处理流程,来谈谈数据库设计要注意的点。

    数据估算

    前面说了秒杀场景需要注意隔离,这里的隔离包括“业务隔离”。就是说我们在秒杀之前,需要通过业务的手段,例如:热场活动,问卷调查,历史数据分析。通过他们去估算这次秒杀可能需要存储的数据量。这里有两部分的数据需要考虑:

    业务数据

    日志数据

    前者不言而喻是给业务系统用的。后者,是用来分析和后续处理问题订单用的,秒杀完毕以后还可以用来复盘。

    分表分库

    对于这些数据的存放,需要分情况讨论,例如,MySQL 单表推荐的存储量是 500W 条记录(经验数字)。如果估算的时候超过了这个数据,建议做分表。如果服务的连接数较多,建议进行分库的操作。

    数据隔离

    由于大量的数据操作是插入,有少部分的修改操作。如果使用关系型数据来存储,建议用专门的表来存放,不建议使用业务系统正在使用的表。这个开头提到了,数据隔离是必须的,一旦秒杀系统挂了,不会影响到正常业务系统,这个风险意识要有。表的设计除了 ID 以外,最好不要设置其他主键,保证能够快速地插入。

    数据合并

    由于是用的专用表存储,在秒杀活动完毕以后,需要将其和现有的数据做合并。其实,交易已经完成,合并的目的也就是查询。这个合并需要根据具体情况来分析,如果对于那些“只读”的数据,对于做了读写分离的公司,可以导入到专门负责读的数据库或者 NoSQL 数据库中。

    压力测试

    构建了秒杀系统,一定会面临上线,那么在上线之前压力测试是必不可少的。我们做压力测试的目的是检验系统崩溃的边缘在哪里?系统的极限在哪里?这样才能合理地设置流量的上限,为了保证系统的稳定性,多余的流量需要被抛弃。

    总结

    秒杀系统的特点,并发量大,资源有限,操作相对简单,访问的都是热点数据。因此,我们需要把它从业务,技术,数据上做隔离,保证不影响到现有的系统。因此,架构设计需要分几层来考虑,从客户请求到数据库存储,到最后上线前的压力测试。

    秒杀架构设计.jpg


    <<上一课程
    推荐文章
    • 之前看过一篇文章介绍H标签的使用方法:H1必须有只能是一个,H2标签可以是多个。不同标签的作用h1和h2标签主要是提高关键词的密度更容易让蜘蛛抓取我们首先要明白HEADER标签是什么。HEADER标签就是HTML语言中的h1到h6定义标题头的六个不同文字大小的TAGES。本质是为了呈现内容结构,共有
    • 高并发下如何设计秒杀系统?秒杀系统是网络商家为了促销等目的进行的网上限时抢购活动。比如某宝某东某夕夕上的秒杀。用户在规定的时间内,定时定量的秒杀,无论商品是否秒杀完毕,该场次的秒杀活动都会结束。秒杀系统具有瞬时流量、高并发读、高并发写以及高可用等特点。秒杀时会有大量用户在同一时间进行抢购,瞬时并发访
    • 经常做仓储管理系统,很少关注电商系统,之前兼职做过一个电商系统,其对应的商品档案就很容易和仓储管理系统混淆,今天抽个时间整理下他们在前端展示的区别和联系。一个电商系统,SPU、SKU、快照等设计的好坏,影响到后面的开发进度,以及架构的调整等。而SPU、SKU、快照又是一个电商系统的核心。SPU,是s
    • Java8新特性中最为重要的便是Lambda表达式和StreamAPI了,先来了解一下Lambda表达式吧。Lambda表达式Lambda表达式是一个匿名函数,我们可以将Lambda表达式理解为一段可以作为参数传递的代码,通过Lambda表达式,我们可以将Java程序变得更加简洁和灵活。来看一段程序
    • Java8中的Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregateoperation),或者大批量数据操作(bulkdataoperation)。StreamAPI借助于同样新出现的Lambda表达式,极大的提高编程效率和
    • 要养成一个好的编码习惯从自己编码开始,对自己代码的合理化命名,编码不仅对自己有好处,而且别人也容易读懂你的代码。所以下载阿里的代码规范插件来约束自己凌乱的代码。阿里规范插件GitHub地址:https://github.com/alibaba/p3cIDEA安装该插件步骤:1.打开IDEA,File
    学习大纲
     SPU和SKU区别与联系
    如何设计一个秒杀系统