一、为什么秒杀系统是后端工程师的 "试金石"
秒杀场景的核心矛盾在于:瞬时上万级 QPS 冲击 vs 有限的库存与数据库承载能力。一场普通的秒杀活动,峰值流量可能是日常流量的几十甚至上百倍,直接打垮数据库是常态。
很多.NET 开发者接触高并发场景不多,一提到秒杀就觉得是大厂专属技术。但实际上,掌握秒杀系统的设计思想,对你理解缓存穿透、异步解耦、分布式锁、流量削峰等核心架构理念有质的提升,也是中高级工程师面试的高频考点。
本文将基于 .NET 8 + Redis + RabbitMQ 技术栈,从零带你搭建一套可落地的秒杀系统,全程附带核心代码,看完就能在本地跑起来。
二、技术选型与架构总览
2.1 核心组件分工
三、核心环节一:Redis 原子性库存预扣减
秒杀最大的坑就是超卖。如果用普通的 "读 - 改 - 写" 模式,高并发下必然出现库存负数。
3.1 为什么用 Lua 脚本
Redis 单线程执行 Lua 脚本,保证整个扣减逻辑的原子性,比分布式锁性能高一个数量级。
3.2 库存扣减 Lua 脚本
技术提升点:这里直接把 Lua 脚本内嵌在代码中是演示用,生产环境建议预加载(ScriptLoad)复用,减少网络传输。
四、核心环节二:RabbitMQ 异步下单削峰
Redis 扣减成功只是 "抢到资格",真正的订单创建要丢给消息队列异步处理。这样即使瞬间一万个请求进来,数据库也不会被打垮。
4.1 生产者:扣减成功后发消息
4.2 消费者:后台异步落库
使用 .NET 8 的 BackgroundService 做消费者,配合手动 ACK 保证消息不丢失:
技术提升点:一定要开启手动 ACK+死信队列。否则消费者异常会导致订单丢失,出现 "Redis 扣了库存但没生成订单" 的资损问题。
五、关键优化点:让系统再稳一个量级
5.1 接口限流:把流量拦在最外层
使用 .NET 8 自带的 RateLimiting 中间件,或基于 Redis 滑动窗口限流:
5.2 消息幂等性:防止重复消费
RabbitMQ 的 At-Least-Once 机制决定了消息可能重复投递,必须做幂等:
方案 1:数据库唯一索引(用户 ID + 活动 ID) 方案 2:Redis 去重表(消费前检查,已消费直接 ACK)
5.3 库存最终一致性校准
定时任务对比 Redis 库存与数据库库存,出现偏差时自动校准,防止极端场景下的数据不一致。
使用 Native AOT 发布,启动速度提升数倍,容器部署更轻量 利用 Keyed Services 注册多组 Redis/RabbitMQ 连接池 接口返回统一使用 IResult + 源生成序列化,减少 GC 压力