秒杀场景必须用allkeys-lfu,因其基于访问频次(带衰减)淘汰,能守住预热后的爆款key;而allkeys-lru依赖最近访问时间,易导致冷数据误续命、爆款反复加载,引发缓存雪崩。

秒杀场景下必须用 allkeys-lfu,allkeys-lru 在预热不充分时会引发“加载→淘汰→再加载”循环,直接导致缓存雪崩和数据库压垮。
为什么秒杀开始前Redis内存就爆了
不是QPS太高,是冷数据批量加载撞上错误淘汰策略。用户刷商品页、库存、倒计时等请求,会集中触发大量未缓存的 product:1001、sku:2005:stock 等 key 加载;如果此时策略是 noeviction,写入直接失败;如果是 allkeys-lru,刚加载进来的爆款 key 可能立刻被踢出——因为它的 lru 时间戳最“新”但还没来得及被多次访问,而一批刚被扫过的冷 key(比如后台任务遍历的用户列表)反而因“最近访问过”被误续命。
这导致下一轮请求又回源查库,重复加载,内存持续飙升直至 OOM。
关键点:
-
allkeys-lru看的是“最后一次访问时间”,对单次突发访问零抵抗力 - 秒杀预热往往只覆盖核心 key,但页面聚合查询可能顺带拉入大量关联冷数据
- 默认
maxmemory-samples 5下,采样偏差大,冷 key 被偶然选中续命的概率不可忽视
allkeys-lfu 如何守住爆款 key
allkeys-lfu 的 lru 字段低 16 位存频次(带衰减),高 8 位存时间戳。爆款 key(如 sku:2005:stock)在预热后被高频读取,频次快速上升;即使有冷 key 被扫一次,其频次也因衰减机制无法冲高,权重自然偏低。
这意味着:
- 预热后的爆款 key 几乎不会被淘汰——只要访问频次稳居前列
- 后台扫描类任务(如每小时统计)不会污染缓存,冷 key 频次衰减后自动让位
- 它不依赖 TTL 控制生命周期,适合那些本就不该设过期时间的核心状态(如实时库存)
注意:allkeys-lfu 频次是 8 位无符号整数,最大值 255;秒杀期间每秒访问超百次的 key 会饱和,失去区分度——但这反而是好事:说明它确实是绝对热点,本就不该被淘汰。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
maxmemory 设置必须配合 allkeys-lfu 使用
光换策略不够,maxmemory 必须按秒杀峰值反推,否则 allkeys-lfu 还没来得及积累频次,内存就满了。
估算步骤:
- 列出必缓存 key 类型:
product:*、sku:*:stock、activity:seckill:config、user:limit:* - 按实际大小估算(例如
sku:2005:stockJSON 约 1.2KB,100 个爆款 ≈ 120KB) - 预估并发活跃 key 数量(不是总量!10 万用户刷前 20 个 SKU,最多活跃 200 个
sku:*:stock) - 加 30% 余量:Lua 脚本、临时集合、连接缓冲都会吃内存
错误示例:maxmemory 1gb 看似够用,但若基线 800MB + 峰值需 600MB,实际会触发频繁淘汰——allkeys-lfu 需要稳定窗口积累频次,抖动会削弱效果。
容易忽略的 LFU 衰减行为
allkeys-lfu 的频次不是永久累加,它每分钟衰减一次(可通过 lfu-log-factor 调整衰减速度)。这对秒杀很关键:活动结束后的冷数据会自然降温,不用靠 TTL 清理;但如果你把 lfu-log-factor 设得过大(如 100),衰减太慢,历史热点可能长期霸占内存,挤占新爆款空间。
建议保持默认值 10,除非你有明确周期性需求(如每日固定时段秒杀),才考虑调低衰减力度。
真正难处理的,是那些“半热不冷”的 key:访问频次略高于均值但远低于爆款,它们在 LFU 下淘汰节奏模糊,需要结合业务监控(如 redis-cli --stat 或 CacheCloud 热点分析)定期识别并人工干预。










