如何解决 Redis 中的热点 key 问题?
- 标签:后端、Redis
🏛 业务架构师
热点 Key 指访问集中到单个 key(爆款商品、大 V 主页、头部直播间),QPS 十万级打到一个 Redis 分片的一个 key 上——集群再大也白搭,分片扛不住单 key 的物理极限。
定位:redis-cli --hotkeys、监控分片级别的 QPS 倾斜、客户端采样统计——分片流量不均就是信号。
治理按业务形态分层:
- 读热点(最常见):商品详情、直播间信息
- 本地缓存(L1)挡第一波:Caffeine 缓存 1~5 秒,95% 热点流量根本不出应用——秒级过期换取数据新鲜度,商品价格这类敏感字段再走短 TTL 校准;
- Redis 多副本打散(L2):key 复制成
key:1 ~ key:N,读随机挑一个——单 key QPS 被 N 份分摊; - 极端场景读写分离,从库扩读。
- 写热点(更难):大 V 发微博写 Feed、热点账户更新
- 合并写(攒批):更新请求先进内存队列,按毫秒级窗口合并成一次写——1 万次/秒变 10 次/秒;
- 分桶 counter:计数拆 N 个子 key 各自 incr,读时求和。
业务联动(架构师视角的重点):热点是运营事件的投影——爆款商品、大促会场、头部直播都有营销日历。我的机制:运营活动提前报备 → 技术侧提前预热 L1/L2 + 临时扩容——把"突发热点"变成"已知高峰",反应式变预案式。
一句话:热点 Key 的解法不在 Redis 参数,在"多级缓存摊读、合并写摊写、业务联动预热"的体系——单点流量均摊化是唯一出路。
🏗 系统架构师
热点 key 指访问集中在少数 key(秒杀商品、爆款直播间),单 key QPS 达十万级,压力落在 Redis 单个分片/主线程上——集群再多节点也帮不了你,因为 key 只在一个节点。
发现:redis-cli --hotkeys(LFU 策略下)、客户端埋点统计 key 访问频次、代理层(如 proxy)访问日志聚合、监控单分片 CPU/QPS 异常突出。
治理方案(按层次):
- 本地缓存兜底(首选):热点数据前置到应用进程内 Caffeine,90%+ 读请求根本不出进程——把 Redis QPS 降一个量级,顺带消除网络 RT;代价是短暂不一致(接受秒级)与内存(可控 TTL 短一些);
- key 打散多副本:
hot:key:1 ~ hot:key:n(随机后缀),读时随机选一个副本,写时同步更新全部副本——把单 key 压力摊到多个 slot/节点;适合计数类可合并的场景(读时聚合); - 读写分离:热点读走从库/只读副本,扩读能力;
- key 拆分:大 Hash 按字段逻辑拆 key,访问也随 field 分散;
- 限流与预判:对可预见的热点(大促名单)提前预热进本地缓存 + 网关限流兜底。
架构心法:热点问题的本质是"散列不均",解法要么改分布(打散),要么加缓存层(本地化),要么升容量(副本)——本地缓存是性价比之王。
💻 全栈开发专家
热点 key = 访问极度集中在少数 key,把单分片 CPU/带宽打满(比如爆款商品详情、明星微博)。
排查:
bash
redis-cli --hotkey # 4.0+,基于 LFU 计数
# 或客户端埋点统计 key 访问频次;monitor 只能秒级采样,生产慎用现象特征:集群整体 CPU 不高但某节点 100%、某接口偶发超时(路由到该节点的请求)。
治理三板斧:
1. 本地缓存兜底(首选):热点数据再放一层 JVM 内存,Caffeine 两级缓存:
java
Cache<String, Product> local = Caffeine.newBuilder()
.maximumSize(10_000).expireAfterWrite(3, TimeUnit.SECONDS).build();
Product p = local.get(key, k -> redis.get(k)); // 热 key 请求不再打 Redis3 秒过期容忍度换取 10 倍扛压能力。
2. key 打散多副本:hot:1:{0..9} 写时写全部/随机写一个,读随机挑一个——把单 key 流量摊到多个分片。适合可重算的计数类。
3. 读写分离 + 隔离:从库扛读;真正写热点的(秒杀扣库存)改队列串行化或分桶(库存拆 10 个子 key)。
4. 产品/架构层:静态化 + CDN(商品详情页推边缘)、合并请求(同一 key 的并发读只放一个回源,SingleFlight 模式)。
预防:大促前对预判热点(运营配置)提前本地缓存预热;热点监控接入告警(单 key QPS 阈值)。