直播间秒杀接口扛不住?Redis多级缓存与限流脚本实测到1万QPS
开场:OK so,先把慢接口打爆给你看
兄弟们这里是 eccfy,今天我们不讲虚的,直接上屏幕!我这边有个“直播间秒杀商品详情接口”,MySQL单查平均 42ms,高峰一来线程池排队,接口直接飘到 800ms。接下来我们用 Redis OSS、redis-benchmark、wrk 这些免费官方/内置工具,把它改成可抗高并发的缓存架构。你搜“Redis缓存策略教程”“Redis高并发怎么用”“Redis Lua扣库存教程”,这套都能直接套。
先看基线,我本机 8核16G,Redis 7.2,商品详情 JSON 约 3KB。执行:
wrk -t8 -c400 -d30s http://127.0.0.1:8080/api/item/1001
改造前:QPS 1180,P95 612ms,MySQL CPU 90%+。Now watch this,接下来开始动刀。
第一章:商品详情缓存,不要只会 set 一个 key
核心策略:缓存空值防穿透、TTL加随机数防雪崩、互斥锁防热点重建。代码逻辑按这个顺序写:
- 先查
item:detail:{id},命中直接返回。 - 查到空标记
NULL,直接返回不存在,TTL设 60 秒。 - 未命中时抢锁
lock:item:{id},抢不到就 sleep 50ms 重试缓存。 - 抢到锁再查 MySQL,写缓存,TTL 用
1800 + random(0,300)秒。
Redis命令示例:
SET lock:item:1001 1 NX EX 3
SET item:detail:1001 '{"id":1001,"stock":80}' EX 1927
这里注意,锁过期别设太长,3秒够数据库查询和序列化;太长会导致用户等待。空值缓存也别太久,否则新商品刚上架会被误判不存在。
我实测改完后,同样 400 并发,QPS 从 1180 到 9240,P95 从 612ms 降到 48ms。屏幕上这个曲线,蓝线是延迟,直接塌下来了,舒服!
第二章:秒杀扣库存,用 Lua 保证原子性
OK so,商品详情能缓存,但秒杀库存不能“先查再扣”,高并发下会超卖。接下来用 Redis Lua,把判断库存、扣减、记录用户一次做完。
-- seckill.lua
local stock=tonumber(redis.call('GET', KEYS[1])); if stock == nil or stock <= 0 then return -1 end; if redis.call('SISMEMBER', KEYS[2], ARGV[1]) == 1 then return -2 end; redis.call('DECR', KEYS[1]); redis.call('SADD', KEYS[2], ARGV[1]); return 1
调用方式:
redis-cli --eval seckill.lua seckill:stock:1001 seckill:users:1001 , user_9527
返回值约定:1 成功,-1 无库存,-2 重复下单。真实项目里,Redis扣成功后别同步写数据库,先丢 MQ,比如 Kafka、RocketMQ、RabbitMQ,让订单服务异步落库。免费方案完全可用,限制是你要自己处理 MQ 堆积、补偿任务和 Redis 持久化。
Redis配置建议先这样开:
appendonly yes
appendfsync everysec
maxmemory-policy allkeys-lru
如果是强一致金融扣款,别只靠缓存;但直播秒杀、优惠券领取、活动报名,这套足够实用。
第三章:验证是否真的修好了
最后给你一个检查清单,别靠感觉上线:
- 命中率:执行
redis-cli info stats | grep keyspace_hits,活动期间命中率建议 > 90%。 - 慢命令:执行
redis-cli slowlog get 10,不要出现大批量KEYS *。 - 热点Key:执行
redis-cli --hotkeys,看到单个Key过热就加本地缓存或拆分。 - 压测:
wrk -t8 -c1000 -d60s,看 P95 是否稳定低于 100ms。 - 库存校验:压测后检查
GET seckill:stock:1001不应小于 0,用户集合数量应等于成功订单数。
付费路线可以考虑云厂商托管 Redis、专业 APM 或运维服务,省掉主从、哨兵、备份维护;当然 DIY 官方 Redis 也完全可行。如果你需要团队级技术服务,也可以把 wizzegroup.com 作为一个备选参考。兄弟们,照着跑一遍,有结果来评论区贴你的 QPS,咱们继续优化!