秒杀场景设计主要看以下三点:
- 高可用
- 高性能
- 最终一致性
秒杀场景的特点:
- 读多写少
- 瞬时流量
- 流程简单
下面就从前端到后端链路的分析和设计秒杀场景。
参考:
业务
可以适当增加参与秒杀的条件
前端
- 前端静态化,并搭配CDN减少服务器的压力
- 在尚未开始前,将button置为灰色,减少不必要的请求。
- 设置验证码或答题,将请求打散。
网关
对于一些高频访问的拉入黑名单中。还有一些比如在10点开抢,10点准时到达的请求,也一并拦截,因为验证码和答题不可能有那么快。
后端
活动预热,将热点数据提前缓存到redis中
非核心服务的降级,限流,拒绝,将非核心的业务暂时降级处理,将资源在短时间内先留给核心业务。
核心服务的限流处理,比如秒杀1000件商品,当请求量大于10000后就快速返回失败(令牌桶)。
采用redis库存预扣减。
使用消息队列异步下单。
在后端保证数据的一致性,即超卖问题。
- 采用分布式锁。
- 采用分布式事务。
- 在数据库减库存时加上库存数量判断,防止数据变为负数。
- 如果只允许抢购一单,那么需要数据库加唯一索引,防止用户重复购买。同时可以在redis中维护set,记录用户购买情况。
步骤:
- 首先将库存缓存在redis中。
- 当请求到达时先在redis中进行库存预扣减,当redis中库存不足时返回失败,查看Set中是否存在该用户,存在就返回失败,不存在插入返回成功,整个过程使用lua脚本保证原子性。
- 采用消息队列异步下单。
- 扣库存的时候先扣数据库库存,再扣减redis库存,保证在同一个事务里。数据库扣减库存时加入
where 库存 > 0
。 - 客户端轮询是否下单成功。