# 如何设计一个秒杀功能?
7 min read
Table of Contents
如何设计一个秒杀功能?
秒杀功能设计
【核心定义】
秒杀功能是一种在极短时间内应对海量并发请求,通过多层次的技术手段确保系统高可用、数据一致性,并最终实现有限库存商品公平、高效售出的分布式系统解决方案。
【关键要点】
- 架构分层与流量削峰:采用“动静分离”与“漏斗型”架构,将静态资源(商品图片、描述)推至CDN,动态请求通过缓存、队列逐层过滤,避免流量直接冲击数据库。
- 缓存极致化:将商品库存等热点数据预加载至Redis等内存数据库,所有扣减操作在缓存中完成,仅异步同步至数据库,将读性能提升至毫秒级,写操作通过原子命令保证一致性。
- 异步化与最终一致性:用户秒杀请求经合法性校验后,立即生成唯一ID并进入消息队列(如RocketMQ/Kafka),后端服务异步消费,完成库存扣减、订单创建等耗时操作,实现请求的快速响应与业务解耦。
- 防刷与限流:在网关层实施多重防护,包括:验证码/答题机制分散请求、用户ID/IP频率限制、商品购买次数校验、恶意请求识别等,确保流量公平性与系统安全。
- 降级与熔断:预设降级策略(如直接返回“已售罄”)、配置熔断器(如Sentinel),在系统压力过大时保护核心链路,避免雪崩。
【深度推导/细节】
核心矛盾:超高并发下的库存超卖与系统崩溃
Step 1 – 请求拦截层:
- 用户请求首先经过负载均衡器(如Nginx/LVS),分发至网关集群。
- 网关执行令牌桶或漏桶算法限流,将请求速率限制在系统承载范围内,多余请求直接返回“繁忙提示”。
Step 2 – 缓存扣减与原子性:
- 通过Lua脚本或Redis的
DECR/INCR原子命令执行库存扣减:local stock = redis.call('get', KEYS[1])if stock and tonumber(stock) > 0 thenredis.call('decr', KEYS[1])return 1 -- 扣减成功endreturn 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:吞吐量更高,但消息延迟相对较大,适合日志类或对一致性要求稍低的场景。
『面试官追问』
-
如何防止同一用户重复购买?
- 在Redis中设置
USER:UID:SKU键,扣减库存前用SETNX判断,成功后设置过期时间(如秒杀活动时长)。
- 在Redis中设置
-
Redis集群崩溃怎么办?
- 采用集群模式(Cluster) 与持久化(AOF每秒刷盘) 保证高可用。
- 降级方案:直接切换至“售罄状态”,或启用备用缓存(如本地缓存Guava Cache),但需注意数据一致性风险。
-
秒杀结束后如何恢复超卖库存?
- 设置订单支付超时回调(如15分钟),未支付订单释放库存,通过消息队列重新加回Redis与数据库。
-
如何保证公平性(防止程序抢购)?
- 加入行为验证(如滑动拼图、点选验证码)。
- 请求路径动态化,每次活动生成随机URL,防止接口被提前爬取。
-
数据一致性如何保障(缓存与数据库不一致)?
- 最终一致性方案:采用“先更新数据库,再通过Canal监听binlog删除缓存”策略,避免并发更新导致的脏数据。
【版本差异/演进】
- V1.0(单体架构):数据库行锁(
SELECT ... FOR UPDATE),性能瓶颈明显,QPS低于500。 - V2.0(缓存化):引入Redis,库存扣减移至缓存,QPS提升至1万+。
- V3.0(分布式队列):引入消息队列异步下单,系统解耦,支持横向扩展,QPS可达10万级。
- V4.0(云原生):采用Serverless(如函数计算)处理峰值,结合弹性伸缩,实现成本与性能的最优平衡。
设计精髓:秒杀系统的本质是将同步操作异步化、将集中式压力分散化、将强一致性弱化为最终一致性,通过多层次的技术栈组合,在性能、一致性、可用性之间取得最佳平衡。