云计算百科
云计算领域专业知识百科平台

大厂 Java 后端场景题:Redis 热 Key 打满单分片,如何排查、拆分与回答追问

大厂 Java 后端场景题:Redis 热 Key 打满单分片,如何排查、拆分与回答追问

适合准备 Java 后端校招、社招和系统设计面试,也适合正在处理 Redis Cluster 局部过载的开发者。读完你将得到一条能落地的证据链:先证明是热 Key 和单分片瓶颈,再止损、拆分、灰度迁移,最后用指标验收;文末还有面试官五轮追问和一份 90 秒回答。

先给结论:不要一看到某个 Redis 节点 CPU 高就直接“加机器”。 Redis Cluster 把 Key 映射到 16384 个 Hash Slot,稳定状态下一个 Slot 由一个主节点服务。若流量集中在一个 Key,它仍会落到一个 Slot、一个主分片;盲目扩容但不改变访问分布,热点不会自动均摊。

一、先把题目说清:热 Key 不是大 Key

面试题通常这样给现象:六个 Redis 分片中,只有一个分片 CPU、网络带宽和命令执行量持续打满,其他分片很空;应用 P99 延迟上升,偶尔超时,但总内存仍有余量。

第一句话应该先区分两个问题:

问题本质常见证据首要风险
热 Key 单位时间访问频率过高 单 Key QPS、LFU 频次、节点网络和 CPU 倾斜 单分片吞吐与延迟上限
大 Key 单个值占用内存或元素数量过大 –bigkeys、–memkeys、序列化大小 阻塞、网络抖动、删除和迁移成本

同一个 Key 可能既热又大,但两者不能混为一谈。热 Key 没有适用于所有系统的固定阈值,应结合该 Key 占节点 QPS 的比例、分片负载差、P99 延迟和业务 SLO 判断。

二、排查顺序:从应用到节点,再落到 Key 和 Slot

我的排查顺序是“应用请求 → Redis 节点 → 命令/Key → Hash Slot”,避免一上来就对生产库执行高风险命令。

1. 先确认不是应用侧流量或重试放大

先看接口 QPS、错误率、超时重试次数、缓存命中率和调用方分布。如果业务刚上线热点活动,或者下游超时引发客户端无上限重试,Redis 看到的高 QPS 可能只是二次放大。

同时按节点比较 CPU、网络入出、连接数、每秒命令数、慢查询和 P99。只有一个节点明显高,才继续判断 Slot 或 Key 倾斜;所有节点一起高,更像总容量不足。

2. 用低风险工具缩小范围

下面命令是排查模板,主机、端口和认证参数应通过安全配置注入,不要写进脚本或截图。

# 连续观察实例状态;先确认哪个节点的 ops、网络或延迟异常
redis-cli -h redis-host -p 6379 –stat -i 1

# 渐进扫描大 Key;-i 用来降低扫描对线上实例的影响
redis-cli -h redis-host -p 6379 –bigkeys -i 0.1

# 只有 maxmemory-policy 使用 LFU(如 allkeys-lfu)时才可依赖 –hotkeys
redis-cli -h redis-host -p 6379 –hotkeys -i 0.1

# 查候选 Key 的 LFU 频次;同样要求 LFU 策略
redis-cli -h redis-host -p 6379 OBJECT FREQ 'product:12345'

# 确认候选 Key 被映射到哪个 Slot
redis-cli -h redis-host -p 6379 CLUSTER KEYSLOT 'product:12345'

–bigkeys、–memkeys、–keystats 和 –scan 都使用渐进式扫描思路,-i 可降低扫描速度。–hotkeys 和 OBJECT FREQ 依赖 LFU 频次计数;如果淘汰策略不是 LFU,就不能把它们当作通用答案,应改用应用埋点、代理层统计、采样日志或监控平台的 Top Key 能力。

MONITOR 会输出服务器处理的所有命令,生产环境常态使用可能带来显著开销和敏感信息暴露。它最多只能在经过审批、短时、受控的故障窗口中使用,不能作为第一排查手段。

三、为什么加节点可能无效:单 Key 仍只属于一个 Slot

Redis Cluster 使用 CRC16(key) mod 16384 计算 Slot。集群扩容和 Reshard 能把不同 Slot 分给更多节点,却不能把同一个 Key 的单次读写拆到多个主分片。

更容易被忽略的是 Hash Tag:Key 中若包含有效的 {…},只有花括号内的内容参与计算。它常用于让相关 Key 落在同一 Slot 以执行多 Key 操作,但写错会制造热点。例如:

product:{12345}:detail
product:{12345}:stock
product:{12345}:recommend

这三个 Key 会被固定到同一 Slot。若目标是把热点副本分散到不同 Slot,就不能给所有副本复用同一个 {12345} 标签。面试中能主动指出这一点,通常比只说“Key 后面加随机数”更有工程含量。

四、先止损:本地缓存、请求合并、限流和只读副本

根治方案上线前,先保护 Redis 和业务 SLO。

  • 进程内短 TTL 缓存:适合读取远多于写入、允许短暂不一致的数据。TTL 加随机抖动,避免大量实例同时失效。
  • SingleFlight/请求合并:同一进程内,一个 Key 失效时只允许一个请求回源,其他请求等待结果,减少缓存击穿。
  • 按业务优先级限流与降级:保留交易、支付等关键链路,推荐或统计类请求可返回旧值、默认值或稍后重试。
  • 读副本分担读流量:只有业务能接受复制延迟时才使用;它缓解读压力,但不能解决强一致写热点。
  • 本地缓存不能只写“加个 Caffeine”。必须同时回答失效方式、最大容量、TTL、冷启动、更新并发和一致性边界。Redis 的客户端侧缓存还可用 CLIENT TRACKING 接收失效通知,但网络断连和失效通知竞态仍需处理,不能承诺绝对不读旧值。

    五、根治:把一个逻辑热点拆成多个物理 Key

    如果热点是读多写少的配置、商品详情或活动信息,可以建立 N 个内容相同的副本,读请求通过稳定散列或随机策略打散:

    int replicas = 16;
    int bucket = Math.floorMod(userId.hashCode(), replicas);
    String physicalKey = "product:12345:hot:" + String.format("%02d", bucket);
    Product value = redisTemplate.opsForValue().get(physicalKey);

    这里的关键不在字符串拼接,而在四个约束:

    • N 由峰值 QPS、单分片安全吞吐、热点比例和扩容余量估算,不拍脑袋固定为 16。
    • 多个副本必须落到不同 Slot;不要把相同 Hash Tag 放进每个副本。
    • 更新时要定义版本号、批量刷新或失效广播,避免 16 个副本返回不同版本。
    • 删除、过期和回源要有并发保护,否则拆分后仍可能同时击穿数据库。

    如果热点来自一个超大 Hash 中的少数字段,可按业务维度拆字段;如果是计数器写热点,可分桶累加后异步汇总,但要明确实时性、幂等和最终一致性。任何拆法都要先从读写语义出发,而不是机械地给 Key 加随机后缀。

    六、无损迁移:版本化、双写、影子读、灰度切换、回滚

    生产系统不能停机改 Key。比较稳妥的迁移顺序是:

  • 建立 v2 物理 Key 和版本字段,保留旧 Key。
  • 新写请求先双写旧 Key 与全部新副本,并记录失败和版本差异。
  • 对存量数据回填;回填过程限速,避免进一步挤压热点分片。
  • 以小比例影子读取新 Key,只比较结果,不向用户返回。
  • 差异率达标后,从 1%、5%、20%、50% 逐步切读,持续观察 P99、错误率和各节点负载。
  • 出现异常立即把读流量切回旧 Key;问题稳定一段时间后再停止旧写并延迟清理。
  • 双写不是“天然一致”。需要定义写入顺序、部分失败补偿、幂等键、版本比较和告警。面试官追问“如果一个副本写失败怎么办”,应回答:以版本号或变更日志识别不一致,失败进入可重试队列,读路径在迁移期可校验版本并回退旧 Key。

    七、如何验收:用前后对比证明拆分真的有效

    成功标准必须在上线前写清楚。至少记录这些基线与发布后结果:

    • 热点节点 CPU、网络入出和每秒命令数下降,节点间负载差收敛;
    • 接口 P95/P99、超时率和错误率回到业务 SLO;
    • N 个物理 Key 的访问量分布符合预期,没有产生新的单桶热点;
    • 缓存命中率没有明显下降,数据库回源 QPS 没有异常升高;
    • 双写失败、版本差异、补偿积压均低于预设阈值;
    • 故障演练能在目标时间内切回旧 Key。

    不要给所有公司套一个“CPU 低于 60%”的万能阈值。正确答案是:上线前根据当前峰值、历史抖动和 SLO 冻结本系统的阈值,并用同一时间窗口做前后对比。

    失败分支怎么处理

    • 各节点都高:回到总容量、慢命令、连接池和业务流量排查,不要误判单 Key。
    • 只有网络高、CPU 不高:检查值大小、序列化、批量命令和客户端读取模式,可能是大 Key 或带宽问题。
    • 拆分后数据库 QPS 暴涨:通常是副本同时过期或回源未合并,补 TTL 抖动、SingleFlight 和预热。
    • 新旧结果不一致:停止扩大灰度,按版本和变更日志定位双写缺口,读流量回退旧 Key。
    • 扩容后热点仍在原节点:检查同一 Key、Hash Tag 和 Slot 分配;Reshard 不会自动拆开一个 Key。

    八、面试官连续五问:每一问在考什么

    追问一:你怎么证明是热 Key,而不是大 Key?

    得分点:从应用 QPS、节点倾斜、候选 Key 访问频次、Value 大小和 Slot 五层取证;说明 –hotkeys 的 LFU 前提;避免直接在生产长时间 MONITOR。

    追问二:为什么加 Redis 节点没有解决?

    得分点:说清 16384 个 Slot、单 Key 只落一个 Slot、扩容只能迁移 Slot,不能拆一个 Key;指出 Hash Tag 可能把多个 Key 主动固定到同一 Slot。

    追问三:本地缓存怎么保证一致性?

    得分点:先声明可接受的不一致窗口,再说短 TTL、主动失效、版本号、断线处理和回源合并;不承诺强一致。

    追问四:拆成 16 个 Key 后如何更新?

    得分点:版本化 Key、双写或失效广播、部分失败补偿、幂等、影子读比对,以及能够回滚。

    追问五:上线后看哪些指标?

    得分点:分片 CPU/网络/QPS 的均衡度,业务 P99 和错误率,缓存命中、数据库回源、版本差异与回滚耗时;指标必须和 SLO、发布前基线绑定。

    九、一个可复用的 100 分评分表

    维度分值满分表现
    定义与取证 25 区分热 Key/大 Key,用应用、节点、Key、Slot 形成证据链
    止损方案 20 缓存、请求合并、限流、读副本均说明适用边界
    根治与一致性 25 按语义拆分,覆盖版本、更新、失效、补偿
    灰度与回滚 15 双写、回填、影子读、逐级切流、可回退
    验收与表达 15 指标绑定 SLO,结构化回答追问,不背万能阈值

    低分答案通常只有“加机器、加本地缓存、Key 后加随机数”三句话;中等答案能给方案,但没有证据、迁移和回滚;高分答案会先建立判断条件,再分别回答止损、根治、一致性和验收。

    十、90 秒可复述答案

    我会先区分热 Key 和大 Key,不会直接加节点。先看接口 QPS、重试和缓存命中,再比较 Redis 各节点的 CPU、网络、命令量和 P99,确认是否单节点倾斜。之后用应用或代理层 Top Key、采样日志定位候选 Key;如果实例采用 LFU,可以用 –hotkeys 和 OBJECT FREQ 辅助,再用 CLUSTER KEYSLOT 确认 Slot。MONITOR 不作为常规生产手段。

    止损阶段会根据一致性要求使用短 TTL 本地缓存、SingleFlight、限流降级,读多写少且可接受复制延迟时才考虑读副本。根治时按业务语义把一个逻辑热点拆成多个物理 Key,让它们分散到不同 Slot,同时设计版本号、失效和失败补偿,注意不能复用相同 Hash Tag。

    上线采用版本化 Key、双写、限速回填、影子读比对和逐级灰度;异常就切回旧 Key。最终用节点负载均衡度、接口 P99、错误率、缓存命中、数据库回源和版本差异验收,而不是套一个固定阈值。

    十一、官方资料与复核边界

    本文技术边界于 2026-08-27 按 Redis 官方资料复核:

    • redis-cli 扫描、bigkeys、hotkeys 与 MONITOR
    • OBJECT FREQ 命令说明
    • Redis 客户端侧缓存与失效通知
    • Redis Cluster 规范:16384 Slots、Hash Tag、MOVED 与 ASK

    工具参数和客户端能力会随版本变化;实际操作前应在测试环境核对当前 Redis 版本、淘汰策略、代理层和云厂商限制。本文没有把无法核验来源的公司名称或“原题”当作事实,只讨论可复现的通用场景。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 大厂 Java 后端场景题:Redis 热 Key 打满单分片,如何排查、拆分与回答追问
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!