如何设计出健壮的秒杀系统

1 超卖问题

分析秒杀的业务场景,最重要的有一点就是超卖问题,假如备货只有100个,但是最终超卖了200,一般来讲秒杀系统的价格都比较低,如果超卖将严重影响公司的财产利益,因此首当其冲的就是解决商品的超卖问题

我们可以采用数据库乐观锁的方式,避免

2 高并发

秒杀具有时间短、并发量大的特点,秒杀持续时间只有几分钟,而一般公司都为了制造轰动效应,会以极低的价格来吸引用户,因此参与抢购的用户会非常的多。短时间内会有大量请求涌进来,后端如何 防止并发过高造成缓存击穿或者失效 ,击垮数据库都是需要考虑的问题。

解决这个问题有几个思路。

2.1 秒杀页面静态化

将商品的描述、参数、成交记录、图像、评价等全部写入到一个静态页面,用户请求不需要通过访问后端服务器,不需要经过数据库,直接在前台客户端生成,这样可以最大可能的减少服务器的压力。具体的方法可以使用 freemarker/thymeleaf 模板技术,建立网页模板,填充数据,然后渲染网页,并将静态网页上传至 CDN 以避免流量涌入后端。

2.2 缓存技术

秒杀是一个读多写少的场景,非常适合使用 Redis 作为缓存。不过考虑到缓存击穿的问题,我们应当建立集群,采用哨兵模式,提高缓存系统的可用性。

2.3 优化 SQL 查询

一个典型的场景是在库存扣减的场景,传统的做法是先查询再扣减(即先 SELECT 再 UPDATE),我们可以将两条语句合并成一条,可以保证库存不会超卖并且一次更新库存。

2.4 接口限流

秒杀最终的本质是数据库的更新,但是有很多大量无效的请求,我们最终要做的就是如何把这些无效的请求过滤掉,防止渗透到数据库。

比如说,在前端请求实现接口限流,通过禁止用户的重复点击,来避免普通用户的无效点击;

在后端服务器上采用限流算法,如令牌桶算法(Java 可以使用 Guava 的令牌桶 API 来实现限流,或者采用 Alibaba 的 Sentinel 流量控制框架来实现限流功能)。

3 接口防刷

现在的秒杀大多都会出来针对秒杀对应的软件,这类软件会模拟不断向后台服务器发起请求,一秒几百次都是很常见的,如何 防止 这类软件的重复无效请求 ,防止不断发起的请求也是需要我们针对性考虑的。

4 秒杀 URL 随机性

对于普通用户来讲,看到的只是一个比较简单的秒杀页面,在未达到规定时间,秒杀按钮是灰色的,一旦到达规定时间,灰色按钮变成可点击状态。如果用户通过浏览器控制台找到秒杀的 url 地址,通过特定软件去请求也可以实现秒杀;而提前知道秒杀 url 地址的人,一请求就直接实现秒杀了。

为了避免有程序访问经验的人通过下单页面url直接访问后台接口来秒杀货品,我们需要将秒杀的url实现动态化,即使是开发整个系统的人都无法在秒杀开始前知道秒杀的url。

具体的做法就是通过md5加密一串随机字符作为秒杀的url,然后前端访问后台获取具体的url,后台校验通过之后才可以继续秒杀。

5 数据库设计

秒杀有把我们服务器击垮的风险,如果让它与我们的其他业务使用在同一个数据库中,耦合在一起,就很有可能牵连和影响其他的业务。

为了防止此类问题,我们应当单独设计一个秒杀数据库,防止因为秒杀活动的高并发访问拖垮整个网站。

最简设计来说,只需要两张表,一张是秒杀订单表,一张是秒杀货品表。

详解:如何设计出健壮的秒杀系统?

还有一些其他的业务表,诸如秒杀商品表(关联 goods_id)、用户表(关联 order 表)等。

5.1 分库分表

为了应对海量数据的效率问题,我们可以采用分库分表的方式来提升数据库的承载量和可用性。

6 大量请求问题

按照1.2的考虑,就算使用缓存还是不足以应对短时间的高并发的流量的冲击。  如何承载这样巨大的访问量,同时提供稳定低时延的服务保证,是需要面对的一大挑战。我们来算一笔账,假如使用的是redis缓存,单台redis服务器可承受的QPS大概是4W左右,如果一个秒杀吸引的用户量足够多的话,单QPS可能达到几十万,单体redis还是不足以支撑如此巨大的请求量。

6.1 消息队列削峰填谷

因此,我们可以采用消息队列来承载消息,并以稳定可控的速率发送给消费者,来实现流量的削峰填谷。

6.2 下单流程异步化

为了提升下单的效率,并且防止下单服务的失败,我们可以将下单这一操作进行异步处理。

最常采用的办法是使用延迟队列,在后台经过了限流、库存校验之后,流入到这一步骤的就是有效请求。然后发送到队列里,队列接受消息,异步下单。

下完单,入库没有问题可以用消息通知用户秒杀成功;

失败的话,还可以采用补偿机制,重试或回滚。

6.3 服务降级

假如在秒杀过程中出现了某个服务器宕机,或者服务不可用,应该做好后手准备,采用服务降级的策略将缓存的数据返回给用户;或是给用户反馈一个失败的消息。

IInfinity

IInfinity

大道虽简,知易行难。
CN