秒杀业务最大的业务特点,短时间内,高并发,大量读请求,大量的写请求。如果不经任何优化,直接将全部读写请求打到数据库层,数据库层由于锁冲突,特别是热点数据行锁冲突,很容易造成死锁,降低数据库执行效率。而且流量很大的情况,很容易将会把数据库压死。数据库层若挂了,如果再次启动,很可能又会被大流量再次压垮。

从系统的角度来看,在秒杀业务的情况下,我们要保护数据层的安全。

为了保证数据库的安全,我们就要降低最后到达数据库层读写流量,使其一直处于安全的情况下运行。

从读写方向,优化思路:

  • 降读
  • 降写

降低数据层读请求,主要办法就是加缓存,数据优先读取缓存,缓存不存在再从数据库层读取。缓存解决办法比较多,下面主要介绍降写的处理办法。

降低数据层写请求,我们就必须在上游应用层过滤写清求。

技术优化手段

假设我们的系统架构如下:

网站/APP—->站点接入应用——>后台服务—->数据库层

我们可以在这三层做优化,拦截写请求,降低数据层写压力。

在网站/APP 层,我们可以使用 JS 等手段,防止用户重复点击。

不过这种手段只能预防普通用户,高级用户可以通过抓包获取请求接口,通过程序发起,绕开 JS。

所以我们需要在站点接入层通过计数的方式,防止同一用户频繁发送请求。比如我们可以限制同一用户每 5 秒,只有一次请求才有效,其余请求返回请求速率过快。

站点层只能限制单一用户,可以通过多用户手段绕开这一限制。

等到写请求到达服务层,服务层可以发送到 MQ 队列或者内存队列,然后根据库存数量,或者数据库抗压能力处理。

比如说某件商品库存只有 2000 个,这时服务层现收到 2 w 个写请求,全部发送到队列中。假设数据库层只能最大只能处理 1000 个写请求,那我们消费程序就拉取 1000 条消息,真正进行数据写请求。

写入成功之后,再次消费消息,直到库存为 0 。这时剩下的消息,都无需再执行数据库的写请求。

产品手段

除了上述的技术手段之外,我们还可以在产品设计方面减少写请求。

我们可以在页面使下单按钮置灰,防止重复点击。

我们还可以页面是不显示库存具体数量,只显示库存的是否还有,降低缓存的淘汰率。

我们还可以将下单与支付流程分离,下单成功后,才能去支付。这时支付系统的压力就很小很多。

相关问题

站点层服务压力很大的处理方案

在我们上面的方案中,站点接入层需要计数过滤,压力可能会很大。由于站点接入层一般都是无状态应用,可以水平扩展。所以我们可以适当增加机器,增加处理能力。

另外,我们还可以设置一定阈值,等请求到达阈值之后,服务降级,抛弃后续请求。

计数问题

计数我们可以存储在 Redis 中,如果 Redis 性能不够,我们可以水平扩展,使用类似 Redis Cluster 方案。

Redis 吞吐量很大,如果害怕网络带宽成为瓶颈,我们可以考虑不使用 Redis ,直接在内存中计数,不过这种方案就需要考虑数据一致性。

如果使用内存计数,同一用户的请求就必须落在同一台机器上。这里的处理的方案我们可以在 Nginx 层使用 用户 ID 切分,然后在分发到的站点接入层。

另外使用内存计数,我们降低数据的一致性与准确性,允许因业务重启,导致内存的丢失的情况。

队列异步处理,浏览器/APP处理方式

1.在请求发送到队列中时,我们可以提前预分配一个订单号,消息发送成功,将订单号返回给页面

2.浏览器/APP 拿到订单号返回之后,跳转到中间也,然后定时轮询。页面我们可以提示用户,订单正在排队中,若刷新将会再次进入排队,防止用户再次刷新下单。

热点隔离

秒杀系统设计的第一个原则就是将这种热点数据隔离出来,不要让1%的请求影响到另外的99%,隔离出来后也更方便对这1%的请求做针对性优化。针对秒杀我们做了多个层次的隔离:

业务隔离

把秒杀做成一种营销活动,卖家要参加秒杀这种营销活动需要单独报名,从技术上来说,卖家报名后对我们来说就是已知热点,当真正开始时我们可以提前做好预热。其实这种方法比较恶心,也是现在某宝,某东经常做的,而且还有那种游戏里面做的也是这种形式。

系统隔离

系统隔离更多是运行时的隔离,可以通过分组部署的方式和另外99%分开。秒杀还申请了单独的域名,目的也是让请求落到不同的集群中。 数据隔离。秒杀所调用的数据大部分都是热数据,比如会启用单独cache集群或MySQL数据库来放热点数据,目前也是不想0.01%的数据影响另外99.99%。

动静分离

大家看一下图一

这是把整个页面Cache在用户浏览器,这样把90%的静态数据缓存在用户端或者CDN上,当真正秒杀时用户只需要点击特殊的按钮“刷新抢宝”即可,而不需要刷新整个页面,这样只向服务端请求很少的有效数据,而不需要重复请求大量静态数据。秒杀的动态数据和普通的详情页面的动态数据相比更少,性能也比普通的详情提升3倍以上。所以“刷新抢宝”这种设计思路很好地解决了不刷新页面就能请求到服务端最新的动态数据。

其实这种我发现也是用于解决高并发的一种手段,像如果要是很多培训出来的同学的话,有做电商项目的可能会用到的,希望能给大家有一些好的启发,如果能唬住面试官的话,那肯定能获取一份不错的offer