秒杀场景的技术挑战和对应的设计原则
- 并发高
- 秒杀的服务、数据库单独部署
- 上游服务限流
- 读多写少
- 使用CDN静态化秒杀商品数据,商品详情页直接访问CDN
- 超卖问题
- 库存扣减使用本地缓存+redis分布式缓存
- redis分段锁机制,提升并发度
秒杀服务后端方案设计
异步方案
- 处理秒杀请求
- 验证码校验
- 通过mq消息队列长度判断是否限流
- 发mq异步处理秒杀请求
- 异步处理秒杀请求
- 业务规则校验
- 扣减redis缓存中的商品库存
- 生成token
- 短轮询秒杀资格
- 返回token
- 下单
- 校验token
- 过期,回补缓存里的商品库存
- 未过期,下单成功,删除token
- 校验token
优点:
- 上游通过mq限流,减轻了下游(应用服务器、redis)压力
缺点:
- 增加了额外缓存用户token的成本
同步方案
与异步的区别:
- 不用mq限流,处理秒杀请求时直接减库存,生成token
- 减库存策略不同,采取本地缓存减库存+redis缓存减库存
异步方案采用mq限流,同步方案使用本地缓存拦截额外的请求,达到限流的效果。二者的本质目的都是减少redis减库存压力
减库存方案优化
本地缓存优化
本地缓存预设库存+buffer,防止服务器在高qps压力下宕机,造成少卖
- 因为还要redis减库存成功才认为减库存成功,所以加buffer不会造成超卖。不过buffer加的过大起不到本地缓存限流的作用,因此需要折中考虑
redis缓存优化
库存过大时,使用redis存在热点key问题,且减库存的并发度不高
解法是分桶
- 把大库存分成多个小份,用不同的key表示。在redis额外存储一份商品id和分桶key列表的映射关系
- 这些Key的哈希值不同,大概率不在Redis的同一个槽位中,避免热点key带来的性能问题
- 每个redis分桶key可以并发做库存扣减操作,提高减库存的并发度