昨天遇到这个问题,发现自己临时总结的不是很好,所以现在想重新整理一下思路。
分析一下问题:
类似淘宝那种做秒杀系统活动,你是如何设计的?
场景分析: 1. 需到达某个时刻才可以开始秒杀(某个时刻之前需要控制拒绝请求)。
2. 一瞬间大量的请求到后台,服务器,数据库,缓存都会扛不住。(前端拦截、削峰,限流)
3. 满足条件才可以进行秒杀(最先过滤这些不满足条件的)
4. 防止恶意刷单请求,网站攻击(SQL注入,CSRF)
5. 库存情况,会有大量读写(缓存)
整体流程按照如下所示:
前端设计:
- 提前把静态化页面,html,css,js等缓存在用户浏览器或app端
- 秒杀的点击按钮可以开始时间之前置灰,在开始秒杀活动之前,避免内部人员或外面的人提前刷物品。
- 避免链接暴露,在浏览器模式下,F12模式会看到请求的地址。
- 多次点击,设置按钮点击后就置灰,只能退出再重新点击。
nginx
网关层,可以做负载均衡算法,过滤一些恶意的ip地址。
api层
可以做验证用户是否登录,是否具备秒杀资格。
库存的数量我想存放在redis缓存中,使用String的方式。使用redis自带的string自减方式去减库存,用户请求进入先验证库存是否还有,如果还有库存,就继续往下走。这里也可以说是库存预热。
这个使用lua脚本的方式,写一个脚本把判断库存扣减库存的操作都写在一个脚本丢给Redis去做,那到0了后面的都Return False了是吧,一个失败了你修改一个开关,直接挡住所有的请求,然后再做后面的事情嘛。
业务相关层
刚开始进来肯定是订单,订单需要去验证缓存中是否还有库存,如果还有,才可以继续往下走
这里一般是订单层,可以存放在mq中,去解耦和削峰。一点一点的去实现减库存。
同时,多余的请求进来的时候,这时候有的前端可能有实现控制了1秒内没返回,前端就返回响应错误,可以把队列中的减库存操作,类似线程池中拒绝策略那样,把等待队列中超过一秒的直接丢弃回给前端,返回失败。
最后经过上面的层层调控,进入到减库存操作的已经剩下很少的流量的,如果是秒杀超过10000件物品的,就需要mq去慢慢减库存,实现解耦。
关于缓存层,并发量还是很大,redis可以做读写分离,主从复制,做集群。redis并发竞争减库存,可以去使用lua脚本,去读取和减库存这一系列操作,库存数为0,就返回。
最后还有一个主要的因素,就是解决超卖的现象产生,你只有10000件物品的话,多出了好几十件,这部分的损失不可能让卖家背锅啊,只能秒杀程序员了。这里去减库存判断是否还有库存时,需要使用大于等于0判断,而不是等值判断。
还有各个业务层,nginx,数据库都做集群处理,多部署几太服务器,才能抗住大流量。
网友评论