# 如何设计一个秒杀功能?

7 min read
Table of Contents

如何设计一个秒杀功能?

秒杀功能设计

【核心定义】

秒杀功能是一种在极短时间内应对海量并发请求,通过多层次的技术手段确保系统高可用、数据一致性,并最终实现有限库存商品公平、高效售出的分布式系统解决方案。

【关键要点】

  1. 架构分层与流量削峰:采用“动静分离”与“漏斗型”架构,将静态资源(商品图片、描述)推至CDN,动态请求通过缓存、队列逐层过滤,避免流量直接冲击数据库。
  2. 缓存极致化:将商品库存等热点数据预加载至Redis等内存数据库,所有扣减操作在缓存中完成,仅异步同步至数据库,将读性能提升至毫秒级,写操作通过原子命令保证一致性。
  3. 异步化与最终一致性:用户秒杀请求经合法性校验后,立即生成唯一ID并进入消息队列(如RocketMQ/Kafka),后端服务异步消费,完成库存扣减、订单创建等耗时操作,实现请求的快速响应与业务解耦。
  4. 防刷与限流:在网关层实施多重防护,包括:验证码/答题机制分散请求、用户ID/IP频率限制、商品购买次数校验、恶意请求识别等,确保流量公平性与系统安全。
  5. 降级与熔断:预设降级策略(如直接返回“已售罄”)、配置熔断器(如Sentinel),在系统压力过大时保护核心链路,避免雪崩。

【深度推导/细节】

核心矛盾:超高并发下的库存超卖与系统崩溃

Step 1 – 请求拦截层:

  • 用户请求首先经过负载均衡器(如Nginx/LVS),分发至网关集群。
  • 网关执行令牌桶或漏桶算法限流,将请求速率限制在系统承载范围内,多余请求直接返回“繁忙提示”。

Step 2 – 缓存扣减与原子性:

  • 通过Lua脚本或Redis的DECR/INCR原子命令执行库存扣减:
    local stock = redis.call('get', KEYS[1])
    if stock and tonumber(stock) > 0 then
    redis.call('decr', KEYS[1])
    return 1 -- 扣减成功
    end
    return 0 -- 库存不足
  • 关键数字“-1”:预扣库存可设置为实际库存的120%(例如120件秒杀100件),防止因用户支付失败导致库存浪费,后续通过定时任务回收。

Step 3 – 订单异步处理:

  • 扣减成功的请求,将用户ID+商品ID+唯一序列号组合消息发送至消息队列。
  • 订单服务消费消息,完成数据库写入(订单表、库存流水表),此处采用本地事务表+消息重试确保最终一致性。

Step 4 – 库存同步:

  • Redis中的库存变化通过binlog监听(Canal) 或定时任务同步回数据库,确保数据源最终一致。

【关联/对比】

  • 秒杀 vs 普通电商下单:
    • 普通下单:直接读写数据库,依赖数据库事务。
    • 秒杀:99%的流量在缓存层处理,数据库仅作异步持久化,架构本质是用空间(缓存)换时间(响应速度)。
  • Redis vs 数据库:
    • Redis单机QPS可达10万+,而数据库(如MySQL)单机QPS仅数千,两个数量级差距是采用缓存方案的根本原因。
  • 消息队列选型:
    • RocketMQ:提供顺序消息、事务消息,更适合金融级秒杀场景。
    • Kafka:吞吐量更高,但消息延迟相对较大,适合日志类或对一致性要求稍低的场景。

『面试官追问』

  1. 如何防止同一用户重复购买?

    • 在Redis中设置USER:UID:SKU键,扣减库存前用SETNX判断,成功后设置过期时间(如秒杀活动时长)。
  2. Redis集群崩溃怎么办?

    • 采用集群模式(Cluster) 与持久化(AOF每秒刷盘) 保证高可用。
    • 降级方案:直接切换至“售罄状态”,或启用备用缓存(如本地缓存Guava Cache),但需注意数据一致性风险。
  3. 秒杀结束后如何恢复超卖库存?

    • 设置订单支付超时回调(如15分钟),未支付订单释放库存,通过消息队列重新加回Redis与数据库。
  4. 如何保证公平性(防止程序抢购)?

    • 加入行为验证(如滑动拼图、点选验证码)。
    • 请求路径动态化,每次活动生成随机URL,防止接口被提前爬取。
  5. 数据一致性如何保障(缓存与数据库不一致)?

    • 最终一致性方案:采用“先更新数据库,再通过Canal监听binlog删除缓存”策略,避免并发更新导致的脏数据。

【版本差异/演进】

  • V1.0(单体架构):数据库行锁(SELECT ... FOR UPDATE),性能瓶颈明显,QPS低于500。
  • V2.0(缓存化):引入Redis,库存扣减移至缓存,QPS提升至1万+。
  • V3.0(分布式队列):引入消息队列异步下单,系统解耦,支持横向扩展,QPS可达10万级。
  • V4.0(云原生):采用Serverless(如函数计算)处理峰值,结合弹性伸缩,实现成本与性能的最优平衡。

设计精髓:秒杀系统的本质是将同步操作异步化、将集中式压力分散化、将强一致性弱化为最终一致性,通过多层次的技术栈组合,在性能、一致性、可用性之间取得最佳平衡。

My avatar

文章看完了,不打算去别的篇章转转吗?👀 感谢你的耐心阅读!如果你有问题想探讨,或者发现了文中的 Bug,请务必通过页脚的链接联系我


More Posts

# 如何设计一个点赞系统?

9 min read

点赞系统是一个高并发、高可用、最终一致性的计数与状态管理服务,其核心本质是处理海量“写-读”请求下的数据一致性、性能与扩展性平衡。

Read

Comments