秒杀业务的设计及解决思路

一,前言

大家好,我是小墨。

今天我们来谈谈秒杀项目的设计和解决思路,我们平时都应该经历过双11那种剁手的疯狂,想象一下每秒数千万的请求压到服务器的感觉,我感觉到最开始淘宝推出这个活动的时候,开发业务的人员的抓头挠腮的蛋疼感。

当然对于那么大的请求量,整个架构都得进行各种更高层次的升级,我们现在不谈论千万级别QPS的架构解决方案,就聊聊假设只有数万QPS下秒杀活动,server服务的考虑出发点和几种解决方案,对于秒杀项目的解决网上都有不少的解决方案,讲得很详细,我根据我实际做的项目谈谈解决方案,然后升级到更高并发量后如何对架构进行优化。

二,考虑出发点

假设现在预计有10W左右的人员会抢购我们推出的超优惠的1000份优惠券,这时候的设计者的考虑思路该如何呢?

1,恶意请求

这其实是在做toC业务下一般都面临的问题,我们常说的黄牛和抢购软件都会针对这种情况对我们的普通消费者抢食,如何尽可能的封杀这些请求?

2,超卖

我们服务端得做好库存问题,不然假设卖出了2000份优惠券,公司岂不是亏死,到时得删库跑路了。

3,并发压力

一般在抢购时间点到来的前后,消费者一般都会刷新页面查看是否到了可以抢购的时候。

假设商品页面大小200K(主要是商品图片大小),那么需要的网络和服务器带宽是2G(200K×10000),这些网络带宽是因为秒杀活动新增的,超过网站平时使用的带宽,这时就会对我们造成巨大挑战。

如果是web端的话一般都得做前端的动静分离,临时租借CDN服务,防止请求压力全部打到我们服务器的带宽来。

4,数据库压力

对于每秒上万的QPS如果直接使用数据库来进行抢购的话,往往会击垮数据库,这时候我们都会使用缓存中间件来帮我们数据库缓解压力。

基于以上几点我们来考虑下项目的设计该如何解决,也结合现实我使用的例子来详解一下。

三,秒杀方案设计

1,恶意请求

这方面其实有许多解决方案,我们汇总一下:

1)前端时间未到时置灰按钮

这个是基操,防止各位剁手党手贱,点爆系统必做,我翻看其他比较成熟的方案时谈到统一时间的问题,诶,这个我们系统其实是没做的,这个是成熟系统为了更好地用户的体验吧,我们就知道就好,不多讲。

2)流控策略

这个是防止一个IP,一个账号在一秒内进行多次重复请求的策略,如果项目有网关,这一般都是在网关层需要做的策略,如果没有的话,就是做个请求IP,账号id的请求计数缓存,一旦达到假设是1S5次的话,直接拦截返回,不进入我们逻辑代码。

3)url动态化

我们设计为服务端会给每个要进行秒杀的用户前发一个md5加盐值,秒杀必须带这个值过来,可以防止知道秒杀接口的人进行抢先秒杀,防止内贼,哈哈。

 

2,请求响应

这个其实是我们要重点考虑的,我们的解决方案除了实现最基本的秒杀功能外,总不能让用户体验感差,出现隔个好几秒甚至10秒才能感知到秒杀结果。

假设我们希望达到10WQPS,即每秒能够处理10W个请求,我们自己这么估计:

设置每个web服务器的tomcat的最大连接数为500的话,假设每个请求处理时间得在0.1S左右,需要20台负载均衡用户请求,才能实现(20*500/0.1)10WQPS的目标,当然这个得自己进行项目压测才知道最终结果,因为往往会因为各种情况导致请求时间变长,然后延缓用户返回请求时间。

我们实际项目就是设置了20个web负担秒杀,这个平时都可以不启用,秒杀前直接用docker-compose一键运行20个秒杀 docker应用。

3,单一职责

其实上面就是使用了单一职责的原则,秒杀项目独立出来,防止影响正常业务使用。

4,缓存中间件使用

秒杀实际上就是去抢夺库存中的商品,那我们如果要让每个请求都去查下数据库是否有库存可以抢夺,那对数据库的压力就太大了,我们其实是可以提前将秒杀商品预热到redis,那么这样的话整个秒杀查询和扣除就在redis上了,然后我们使用消息中间件去异步通知数据库改库存即可,

5,超卖处理

这个其实是秒杀中的关键,因为并发带来了问题,20个web同时间去查redis,发现此时库存假设为10,那么下一步就去扣减redis的库存,就会发现超卖情况的出现,解决方案有以下几种:

1)分布式锁

将查库存和扣减库存放在锁里面实现,一般常用的分布式锁有zookeeper和redis分布式锁,具体实现方式不多讲,这样保证请求的前后顺序。我们就是使用这种方式

2)消息队列

可以使用FIFO队列,消息队列,redis队列都可以,先进队的先进场。

6,消息队列消费库存请求

我们前面设计了redis作为库存的抢夺实现,那么当抢夺成功后可以去数据库扣库存,但是为了尽量的削峰填谷,将扣库存消息放入MQ中,让数据库一个个去消费改库存即可。

 

整体的方案设计的架构图如下:

 

四,高并发下项目优化

我们这一节思考下我们目前遇到的性能瓶颈,然后思考下如何去改进,用于面对高并发下该怎么去处理,我们设计出一套解决方案

性能瓶颈

  1. 没有区分有库存和无库存下锁设计,当库存全部扣除,没有直接返回,还处于分布式锁排队等待
  2. 只用一个分布式锁,资源全部在一个锁内排队。

对于这种情况我们其实是可以针对这两种情况进行优化的。

  1. 对锁进行优化,我们知道当redis分布式锁被一个锁持有后,其他线程会进行自旋,判断是否锁已经放开,然后抢夺。我们这里都谈redis分布式锁,这里锁住的流程是1)判断当前是否存在库存 2)判断是否当前用户抢夺过 3)扣减库存  。   我们想如果能够让操作变成原子类,然后使用redis的单线程执行,是不是可以实现不通过加锁,就实现多线程的原子对库存的抢夺,其他线程当判断到库存被抢夺完,就会直接返回抢夺结束。
  2. 对于只有一个库存同时间只能被一个线程抢夺的问题,其实可以设计为将库存分散到n个redis中,然后集群化,举例子可以将10台web跟一个redis作为一个集群,然后将大量请求负载均衡到多个集群去,这种方式就可以实现高并发下的秒杀过程

 

五,总结

本文讲解了抢购系统中的项目设计,以及各种注意考虑事项,然后针对这些情况给出了一个现实的解决方案,希望能够给各位一个思路去解决这种抢购系统的设计,欢迎点赞讨论。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值