跳转到主内容
极星编程网:以代码为星,赴技术山海!

golang如何设计高并发秒杀系统_golang高并发秒杀系统设计详解

秒杀系统需从Redis原子操作、channel限流、异步落单三层面硬控:DECR须校验返回值并回滚;channel容量需压测确定;成功后立即响应,后续全异步。 秒杀系统不是“加个锁就能跑”,高并发下超卖、雪崩、OOM 几乎是默认行为,必须从 Redis 原子操作、channel 限流、异步落单三个层面硬控,缺一不可。 redis.Decr 必须校验返回值并立即回滚 直接
redis.Decr
后不看结果就创建订单,等于主动送库存进负数。DECR 返回的是扣减后的值,不是操作是否成功的布尔值。 遇到
redis.Nil
(key 不存在)要区分是活动未开始还是配置漏了,不能 panic 返回值
< 0
表示已售罄,此时必须立刻
redis.Incr
回滚,否则网络中断或 panic 会导致库存永久缺失 别用 Lua 脚本封装“先 GET 再 DECR”——这破坏原子性;正确脚本只做
DECR
+ 条件判断,且必须返回新值供 Go 层校验 channel 限流的容量不能拍脑袋定
make(chan struct{}, 100)
这个 100 是系统生死线,不是经验值。它直接决定你 Redis 的 p99 延迟、MySQL 的
Threads_running
和机器内存水位。 压测时盯紧
Redis INFO commandstats
中
cmdstat_decr
的延迟,超过 5ms 就得降 channel 容量 MySQL
SHOW STATUS LIKE 'Threads_running'
持续 > 200,说明 DB 已排队,channel 得缩容 CPU 长期 > 70% 或内存使用率逼近 90%,不是加机器,而是 channel 已超载,再撑下去会触发 OOM killer 异步落单不是优化,是防止 503 的底线 秒杀成功那一刻,只要
redis.Decr
返回 ≥ 0、订单号生成完成,就必须立刻 HTTP 响应。后续所有操作——写 MySQL 订单表、发风控 MQ、更新销量统计——全扔进异步队列。 立即学习 “ go语言免费学习笔记(深入) ”; 同步写库一旦卡在 MySQL 的行锁或主从延迟上,goroutine 就卡住不归还
chan
令牌,新请求直接 503 别用
sync.WaitGroup
等异步任务结束——它不释放 channel 令牌,起不到限流作用 异步任务失败必须有重试+死信兜底,但重试不能影响用户侧响应时间,这是两层逻辑 幂等下单必须用 SETNX,禁用本地缓存和唯一索引 前端 disabled、session 标记、JWT claim 里塞 flag,对脚本重放完全无效。幂等控制必须服务端强约束。
SETNX seckill:order:123:user456
的 key 必须含场次 ID + 用户 ID,value 存毫秒时间戳或随机 token,过期时间设为支付超时 + 30s
SETNX
返回 0 就直接返回 “您已参与本场秒杀”,不走任何后续逻辑 本地
map
或
sync.Map
在多实例部署下彻底失效;MySQL 唯一索引写入太慢,扛不住瞬时洪峰,会把 DB 打挂 真正难的不是写对一行
Decr
,而是让 channel 容量、Redis 过期时间、SETNX 过期时间、异步队列重试策略这四组参数在压测中形成闭环咬合——差一个毫秒,整条链就可能滑向超卖或雪崩。

相关文章