# 如何设计一个秒杀系统? 👍
秒杀业务的典型特点有:
- 瞬时流量大
- 参与用户多,可秒杀商品数量少
- 请求读多写少
- 秒杀状态转换实时性要求高
秒杀系统本质上就是一个满足高并发、高性能和高可用的分布式系统
参考流程图:
# 限流
- 接入层(nginx)漏桶算法限流
- 网关层面添加sentinel限流(窗口算法)
# 如何保证不超卖
# 一、数据库解决(一般不可行)
- 在查询商品库存时加排它锁(for update)
- 更新数据库减库存,加上乐观锁(stock > 0 )
数据库加锁的解决方案,性能很不好,在高并发的情况下,还可能存在因为获取不到数据库连接或者因为超时等待而报错。
# 二、分布式锁
- Redisson 分布式锁对商品加锁,只有获取到锁的才能去扣库存。
这种方案的缺点是:很多用户对一个商品同时下单时,因为是基于分布式锁的串行处理,导致无法同时处理同一个商品的大量下单请求。
# 三、分布式锁 + 分库存
- 把商品的库存分为N个KEY
- 用户下单对用户ID进行%N计算,看选中哪个KEY。
- 当其中KEY库存不足时,可以自动释放锁,并自动换成下一个分段的KEY,在尝试去扣库存。
# 四、redis lua 脚本 + 异步队列/MQ
- 首先在redis中进行预减库存(lua 脚本 写判断条件,然后执行 decr 指令),当redis中的库存不足时,直接返回失败;
- 将预减库存成功的,放入请求异步队列;
- 服务端从异步队列,根据业务判断(例如:是否已经秒杀过了)取出请求,生成秒杀订单,减少数据库库存;
以上的异步队列,也可以换成异步消息(MQ)
缺点:由于异步写入DB,可能存在数据不一致。