26.实战案例复盘——秒杀库存扣减 Lua 脚本,排行榜赛季结算 2 亿条数据,社交平台 Feed 流推送

部署运行你感兴趣的模型镜像

在这里插入图片描述
26. 实战案例复盘
——秒杀库存扣减 Lua 脚本,排行榜赛季结算 2 亿条数据,社交平台 Feed 流推送

一、秒杀库存扣减:把并发锁做成“单线程”

  1. 业务背景
    大促峰值 18 w/s,SKU 总数 2 000,单 SKU 最大 6 w/s。早期用 Redis + 分布式锁,CPU 空转 35 %,超卖 12 件。

  2. 设计目标
    0 超卖、1 ms 内返回、横向可扩展、降级方案不击穿 DB。

  3. 核心思路:把“锁”预埋在 Lua 里
    (1)数据模型
    sku:1001:stock // 剩余库存
    sku:1001:order // 已购用户集合(去重)
    sku:1001:lock // 分布式互斥令牌,过期 50 ms

(2)Lua 脚本(精简版)

local sku   = KEYS[1]
local uid   = ARGV[1]
local now   = tonumber(ARGV[2])

-- 1. 重复购买检查
if redis.call('SISMEMBER', sku..':order', uid) == 1 then
    return {-1, 'REPEAT'}
end

-- 2. 令牌锁,防多集群并发
if redis.call('EXISTS', sku..':lock') == 1 then
    return {-2, 'LOCKED'}
end

-- 3. 库存扣减
local left = redis.call('DECR', sku..':stock')
if left < 0 then
    redis.call('INCR', sku..':stock')   -- 回滚
    return {-3, 'SOLD_OUT'}
end

-- 4. 记录用户
redis.call('SADD', sku..':order', uid)
redis.call('EXPIRE', sku..':order', 86400)

-- 5. 下发延迟令牌,用于异步关单
redis.call('ZADD', 'sku:delay', now+600, sku..':'..uid)
return {left, 'SUCCESS'}

(3)性能
6 w/s 单 SKU 压测,P99 0.8 ms;CPU 降至 12 %;0 超卖。

  1. 踩坑记录
    ① EVALSHA 缓存穿透:预热脚本列表,脚本变更版本号 + 1。
    ② bigkey 阻塞:拆成 1 000 子桶,脚本内做二次 hash。
    ③ 节点宕机迁移:stock 与 order 落在同一 slot,保证原子。

  2. 降级链路
    Lua 拒单 → 发送 MQ → 消费端二次校验 DB 库存 → 真超卖时人工补货。

二、排行榜赛季结算:2 亿条纪录 5 min 跑完

  1. 业务规模
    赛季 30 天,日活 800 w,写入 9 000 w/天,共 2.1 亿条积分明细。

  2. 老方案痛点
    MySQL 聚合 + 单线程排序,结算窗口 4 h,高峰 CPU 90 %,影响在线业务。

  3. 新架构:Redis 跳表 + 离线合并
    (1)实时写
    ZINCRBY rank:2025S1 3 user:123
    写入同时落地 Kafka,用于离线对账。

(2)赛季末流程
Step-1 并行 Dump
Redis Cluster 16 个 master,各自执行 redis-cli --rdb,RDB 落 HDFS,5 min。

Step-2 MapReduce 去重合并
Key -> userId,Value -> score,相同 user 多分区累加,输出 <userId, totalScore>,2 亿 → 1.2 亿。

Step-3 Spark SQL 排序
df.sortBy($"score".desc).zipWithIndex 生成 rankId,持久化到 ClickHouse 本地表。

Step-4 写回 Redis 新 Key
ZADD rank:2025S1:final rankId userId,用于新赛季榜单展示。

  1. 性能
    200 核 Spark 集群,5 min 完成排序;Redis 只读 1 Gbps,无阻塞。

  2. 一致性保障
    ① RDB 快照时间戳对齐,所有节点在同一 slave 上执行 LASTSAVE 确认。
    ② 离线结果与 Redis 实时榜差异 < 0.01 %,超出阈值触发人工复核。

三、社交平台 Feed 流推送:读扩散 + 写扩散混合

  1. 场景
    关注模型 30 亿边,日新增 Feed 8 000 w,首页 Timeline 要求 P99 < 300 ms。

  2. 模型选型
    大 V 写扩散,普通用户读扩散,阈值 1 w 粉丝。

  3. 写扩散(Push)
    (1)表结构
    feed:{userId}:{timestamp} -> protobuf 内容
    inbox:{fanId} -> Redis List,LPUSH 新消息 ID,LTRIM 保持 500 条。

(2)并发写入
使用 Redis pipeline,单次 100 条,batch 大小 8 k,单机 40 w/s。

(3)冷启动补偿
粉丝 > 1 w 的大 V 发 Feed 时,若 fan 的 inbox 为空,触发异步任务补全最近 20 条,防止首刷空窗。

  1. 读扩散(Pull)
    (1)小 V 不发 inbox,只写 feed:userId;粉丝读取时实时聚合:
    ZUNIONSTORE tmp 5 feed:101 feed:102 ... WEIGHTS 1 1
    ZREVRANGE tmp 0 20

(2)聚合结果缓存 5 s,缓存键 union:{fanId}:{slice},slice = 时间戳 / 5。

  1. 热点防护
    ① 本地缓存 + 异步合并:Guava 缓存 1 s,同一 fanId 请求合并为一次 ZUNION。
    ② 大 V 突然爆炸:粉丝列表拆 1 k 桶,写入限速 2 w/s,超量转读扩散。

  2. 性能
    线上 22 w/s 写扩散,P99 写入延迟 18 ms;首页聚合 P99 220 ms,缓存命中率 96 %。

四、三板斧共性总结

  1. 把“并发原语”压进单线程:Lua、pipeline、单 Key 事务,消灭分布式锁。
  2. 让数据围着计算走:RDB dump + 离线 Spark,避免在线大排序。
  3. 读写模型动态切换:阈值、桶、降级开关,实时根据画像调整策略。

五、留给下一个赛季的 TODO
• 秒杀:探索 Redis 7 Function,把 Lua 升级为 JS,脚本热更新不下线。
• 排行榜:引入 Redis 7.4 的 JSON.TOPK,实时维护赛季 Top100,省去离线合并。
• Feed:研究 Dragonfly 的 LFRU 缓存,单节点 4 QPS 提升 40 %,减少分桶复杂度。
更多技术文章见公众号: 大城市小农民

您可能感兴趣的与本文相关的镜像

Qwen-Image-Edit-2509

Qwen-Image-Edit-2509

图片编辑
Qwen

Qwen-Image-Edit-2509 是阿里巴巴通义千问团队于2025年9月发布的最新图像编辑AI模型,主要支持多图编辑,包括“人物+人物”、“人物+商品”等组合玩法

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔丹搞IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值