秒杀系统设计浅析
一.引言
先假设一个业务场景,某商品秒杀活动,100件库存,大概预估10w人参加活动
二.系统面临的问题
1.高并发
- 秒杀这种业务场景的特点就是时间极短,瞬间用户量极大
2.超卖问题
- 卖出高于库存数量的商品
3.链接暴露,恶意请求问题
- 类似黄牛,专门抢这种低价秒杀商品,然后又转手高价卖出去
4.数据库压力问题
- 十几万的QPS基本都要把数据库打挂,如果秒杀业务还设计其他业务,没有降级,限流,熔断等策略,基本要把其他业务也搞挂
三.如何解决这些问题?
1.服务单一职责
- 给秒杀系统单独开一个服务,与其他业务服务隔离开来,单独给它建一个数据库。
- 这样设计的好处就是即使秒杀系统没有抗住,崩了,也不会影响其他业务服务。
2.秒杀链接加盐
- URL链接动态化,通过md5之类的加密算法加密随机的字符串去做url
3.redis集群架构
- 单机redis是肯定扛不住秒杀系统压力的,并且秒杀完全就是读多写少的场景,直接采用redis cluster集群
4.负载均衡
- 多租点流量机
5.网关拦截恶意请求
- 在网关层面,就把不像人为的请求拦截掉。
- 避免打到后台,占用网络带宽或把服务器打崩或缓存击穿等等。
6.资源静态化
- 一般都是前后端分离的系统,前端也要有自己发服务器
- 把一些前端资源能放入cdn服务器的东西都放进去,进一步减轻真正秒杀时的压力。
7.按钮控制
- 没到秒杀时间的时候,秒杀按钮置成灰色,不可按状态。
- 避免用户在快到秒杀时间的时候在最后几秒疯狂请求,导致还没到秒杀时间系统就挂了
8.前后端限流
- 前端限流:秒杀按钮不能一直点,一般是点一下或者两下等几秒之后才可以继续点击
- 后端限流:产品全卖完了,前端秒杀结束,后端也跟着结束关闭
9.库存预热
- 秒杀系统设计的业务数据都加载到redis中,让整个流程都在redis里面去做.
- 等秒杀结束了,再异步去数据库修改库存
10.redis+lua脚本,解决超卖问题
lua脚本是redis在2.6版本提供的,通过内嵌对lua环境的支持,redis解决了长久以来不能高效处理CAS(check and set)命令的缺点,并且可以通过组合使用多个命令,轻松实现以前很难实现或者不能实现的事务模式
lua脚本类似redis事务,有一定的原子性,不会被其他命令插队,可以完成一些redis事务性的操作
- 解决超卖问题:把判断库存和减库存的操作都交给lua脚本
11.采用MQ削峰填谷
- 采用rabbit mq,对于突然来到的大量请求,可以配置流控规则,以稳定的速度逐步处理这些请求,起到削峰填谷的作用,从而避免流量突刺造成的系统崩溃。
四.总结
- 先用cnd将页面静态化
- 然后采用nginx做负载均衡,将流量均分到多个秒杀服务上。
- 然后通过redis集群提供业务数据服务。
- 通过lua脚本进行判断库存和减库存操作。
- 然后生成订单,通过rabbit mq队列进行下单,异步修改库存操作mysql。