秒杀系统架构思路
应用场景
限时抢购,10w人抢购100个商品。这种情况下如果直接走到数据存储层,瞬间会把数据库打挂掉,如果业务处理不好(流程过长),会出现超卖现象
优化方向
尽量将请求拦截在上游
充分利用缓存
1. 前端方案
- 页面静态
- 防重复提交
- 用户限流
2. 后端方案
- 网关限制
- 缓存
- 消息队列削峰
优化细节
这里我们由简单往细节深入(因为要考虑实际的用户量,先做最简单最有效的处理)
简单高效处理方式
- 前端防重复提交
这是最基本的 - redis缓存校验
如果没有缓存,由于业务校验时间过长,比如在200ms内10w个人同时读了数据库库存仅剩1,都是可购买的,然后同时走到下单流程就会超卖,另外就是如果并发量过高,数据库会挂掉。
如果是缓存校验,则只有一个可下单。其余全部直接拦截。
redis数据类型选型
如果不考虑抢购的下单数量和购买限制大于1,那直接kv或者list都是可以的。否则可以考虑hash或者zset。
这里对比一下kv和list:
kv的一般处理方式是预加或者预减:累计购买数量超过总库存或者剩余库存小于0,则校验不通过,同时回退。
list:预存库存长度的list,不断pop,无法pop则校验不通过。
tip:注意原子性
判断最好走lua。
比如kv,如果库存1,10人同时下单,如果是程序判断,则全部不能下单。而如果用lua,用户判断和回退是原子性的,则有一个人可以下单成功。
如果使用list,当抢购数量大于1时,回退也需要用事务,不然会出现,比如库存3,A下单5,B下单2。B在回退push的过程中,又被Apop了1从而判断库存不足。导致两人都不能下单。
复杂完善处理方式
- redis集群,主从同步,读写分离(读多写少)。
- nginx负载均衡
- 前端资源静态化:只有少部分内容是动态的的
- 按钮控制
- 缓存预热
- mq削峰:队列下单
详细内容可以参考大佬们的文章,我只是一个搬运工
架构设计图:
参考文档:
https://www.zhihu.com/question/54895548
https://yq.aliyun.com/articles/69704?utm_campaign=wenzhang&utm_medium=article&utm_source=QQ-qun&utm_content=m_10737