商品秒杀提高QPS解决方案

提高QPS有不变的几个思想:

  1 缓存数据好过直接操作数据库

  2 批量修改,好过单条修改

  3 保护系统不宕机,宕机以后QPS 为0.

 

场景和要求:活动商品秒杀,需要支持大量的用户的瞬时冲击,我们需要尽量的做到QPS 高,然后我们要保证即便用户超出我们系统预期也能稳定运行。

  不优化情况我们一般怎么做:

      请求过来,查询库存,判断库存还有,减少库存,生成用户购买记录,返回数据。

      如果不做任何优化,系统数据库写入必然是瓶颈,尤其库存的修改,阻塞严重,数据库写入阻塞以后,请求堆积,很容易整个系统就雪崩的宕机。

 

  优化过程:

      1 把库存放到缓存里面去,请求来了,直接读取缓存里面的库存,并且扣减库存,这时候不能告诉用户抢购成功,因为我们实际啥都没做,只是缓存预先扣减了库存,所以我们返回用户抢购中,客户端收抢购中以后轮询服务器秒杀结果。

 

      2 秒杀结果肯定也是走缓存,不走数据库的,在服务器没有处理的情况下,默认缓存里面没有数据,直接返回抢购中(轮询时间建议值2-5秒)。

 

      3 第1步的时候缓存预扣减了库存,返回用户抢购中,后端这时候可用使用mq缓冲写入数据库的请求(这个请求要做的事情,扣减数据库库存,生成购买记录)

 

      4 扣减数据请求已经在mq了,每个请求做的事情都一样,我们完全可以批量的扣减库存,然后批量的写入购买记录。比如我每次批量1000,检查这1000用户余额是否足够,挑选余额足够的(比如有900),然后库存直接扣900,用户余额扣减记录,用户购买记录直接批量插入。需要注意的是,如果是拉取模式的mq,一定时间里即便不到1000个请求,也必须要处理。

 

      5 第4步的的mq缓冲的请求有两种结果成功和失败,这时候我们应该把结果数据写入缓冲(是我们处理主动写入缓存,而不是查不到缓冲然后loadDB,免得把数据库读死),前面客户端轮询到结果成功,提示用户抢购成功。轮询到失败,提示失败。没有轮询到结果,重新轮询。了没有轮询到结果,并且轮询了一次次数,抢购失败。

 

      6目前的情况,我们用户请求都没有直接读写数据库(都是走的缓存),数据库入库效率也很高了(批量)。我们已经近尽可能的提高了系统的QPS。但是如果用户还是太多,依旧可能把系统缓存写上,依旧可能批量数据库写死。

 

      7我们还可以限流,比如在nginx上面做限流,超过我们系统理论能够处理的上限,我们就直接返回系统压力过大(这样不好,但是可以保护我们的系统不宕机)。同样tomcat 可以做限流(控制请求数量),批量写数据库也可以做限流(比如我们限制每秒只能写入 100次批量 ,超过就等待,请求等待时间太久的可以在读取轮询次数标志,判断是否还需要批量入库)

 

      8 另外,客户端不一定需要轮询,如果要求抢购响应时效性比较高,并且有支持推送的(比如三方推送,比如websockter ),我们可以处理完起批量请求以后直接告知推送服务器,推送结果给用户,然后用户获取到抢购成功和失败的结果。

      

      9 缓存预扣除的库存,在批量的时候失败的情况,需要向缓存里面补偿,上面的例子需要在批量结束以是缓存的库存+100,用户取消订单根据业务的要求,是否需要添加库存。

 

      10 如果依旧有性能瓶颈,大概我们需要数据的切分,来提高写入性能的瓶颈。缓存方面,一般可以通过集群,读写分离,库存也可以是分段(10个key分别缓存库存,通过模运算,有库存的key个数,分配扣减那一份库存),然后再走后面的流程。

mq方面本来qps就很高,然后可以通过水平拓展集群,提高qps。

 

 

      

posted on 2022-05-01 14:06  zhangyukun  阅读(670)  评论(0编辑  收藏  举报

导航