Redis遇到热点key如何解决

张开发
2026/4/9 23:44:53 15 分钟阅读

分享文章

Redis遇到热点key如何解决
一句话结论热点 Key 的核心问题是访问集中在一个节点上解决方案是本地缓存减少请求 读写分离分散读压力 Key 分片分散到多个节点。热点 Key和大key的区别热点 Key 是指被大量客户端频繁访问的 Key其 QPS 远高于其他 Key导致单个 Redis 节点成为性能瓶颈。维度热点 Key大 Key问题本质访问频率过高数据体积过大核心危害单节点 CPU / 网络被打满主线程阻塞、网络拥塞典型场景秒杀商品、热门文章、热搜话题一个 10MB 的 JSON、百万级集合解决思路分散访问压力拆分数据体积深度解析一、热点 Key 到底有什么危害img上图展示了热点 Key 在 Redis Cluster 中的危害单节点过载热点 Key 集中在某个节点上该节点的 CPU、网卡带宽被瞬间打满而其他节点可能很空闲。影响其他业务同一节点上的其他 Key 也会因为资源被占满而响应变慢产生 邻居效应。主从同步延迟如果热点 Key 涉及写操作主节点压力大时主从复制延迟增大读从节点可能拿到旧数据。二、热点 Key 的典型场景img上图列出了热点 Key 的三种典型场景突发热点明星官宣、热搜话题、突发新闻等短时间内大量用户访问同一页面对应的 Redis Key 被疯狂读取。这类热点不可预测最危险。预期内热点秒杀商品、限时抢购等在活动期间某些 Key 的 QPS 会飙到极高。这类热点可以提前准备。架构设计不当把全局配置、系统参数放在单个 Key 中每个请求都要读取造成人为的热点。三、如何发现热点 Key方法一redis-cli --hotkeysRedis 4.0# 需要先开启 maxmemory-policy 为 LFU 系列策略 redis-cli --hotkeys # 输出示例 # [Hot Key] user:profile:10086 (access count: 583210) # [Hot Key] seckill:goods:1001 (access count: 421305) # [Hot Key] hot:news:202 (access count: 389102)关键点基于 Redis 的 LFU 计数器统计能直接列出访问频率最高的 Key。前提条件必须将淘汰策略设为volatile-lfu或allkeys-lfu否则无法使用。方法二MONITOR命令临时排查# 实时监控 Redis 执行的所有命令危险仅用于临时排查 redis-cli MONITOR | grep GET\|HGET | awk {print $NF} | sort | uniq -c | sort -nr | head -20 # 输出示例 # 583210 GET user:profile:10086 # 421305 GET seckill:goods:1001 # 389102 GET hot:news:202关键点MONITOR会输出 Redis 执行的每一条命令可以用管道统计哪些 Key 被访问最多。严重警告MONITOR本身会消耗 Redis 性能高 QPS 下可能导致 10%~30% 性能下降只能短时间使用不能长期开启。方法三业务层面监控/** * 简单的热点 Key 检测器 * 统计每个 Key 的访问频率超过阈值告警 */ publicclass HotKeyDetector { // Key 访问计数器可用 Guava Cache 设置滑动窗口 privatefinal CacheString, AtomicLong counterCache CacheBuilder.newBuilder() .expireAfterWrite(1, TimeUnit.SECONDS) // 1 秒滑动窗口 .build(); // 热点阈值1 秒内访问超过 1000 次 privatestaticfinallong HOT_THRESHOLD 1000; public void recordAccess(String key) { AtomicLong counter counterCache.get(key, () - new AtomicLong(0)); long count counter.incrementAndGet(); if (count HOT_THRESHOLD) { // 触发告警 alertService.warn(检测到热点 Key key QPS count); } } }关键点在应用层统计每个 Key 的访问频率超过阈值触发告警。这种方式对 Redis 零侵入不影响 Redis 性能适合长期运行。可以结合 Sentinel、Prometheus 等监控系统做可视化展示。四、热点 Key 的解决方案img上图展示了热点 Key 的四种解决方案本地缓存最优先在应用服务器本地缓存一份热点数据请求直接从本地内存返回不经过 Redis大幅降低 Redis 访问压力。读写分离增加从节点读请求分散到多个从节点热点 Key 的读压力被多个节点分担适合读多写少的场景。Key 分片将一个热点 Key 复制为 N 个副本分布在不同节点上读请求随机选择一个副本读取。限流 熔断对热点 Key 的访问频率进行限流超过阈值的请求直接返回降级数据保护 Redis 和 DB 不被压垮。五、方案详解与代码示例方案一本地缓存Caffeine/** * 使用 Caffeine 本地缓存解决热点 Key * 适合数据量小、更新不频繁、读多写少 */ publicclass LocalCacheSolution { // Caffeine 本地缓存 privatefinal CacheString, String localCache Caffeine.newBuilder() .maximumSize(10000) // 最多缓存 1 万个 Key .expireAfterWrite(5, TimeUnit.SECONDS) // 5 秒过期容忍短暂不一致 .recordStats() // 记录统计信息 .build(); public String getHotData(String key) { // 1. 先查本地缓存 String value localCache.getIfPresent(key); if (value ! null) { return value; // 本地缓存命中直接返回不访问 Redis } // 2. 本地缓存 miss查 Redis value redis.get(key); if (value ! null) { localCache.put(key, value); // 回写本地缓存 return value; } // 3. Redis 也 miss查 DB value db.query(key); if (value ! null) { redis.set(key, value, 30, TimeUnit.MINUTES); localCache.put(key, value); } return value; } }关键点使用 Caffeine 作为本地缓存高性能、支持过期淘汰5 秒过期容忍短暂的数据不一致。热点 Key 的请求大部分会命中本地缓存Redis 的 QPS 可能从 30 万降到几千。注意本地缓存适用于数据量小、更新不频繁的场景。如果数据更新频繁要注意本地缓存和 Redis 的一致性问题。方案二Key 分片/** * 热点 Key 分片方案 * 将一个热点 Key 复制为 N 个副本分散到不同节点 */ publicclass HotKeyShardingSolution { privatestaticfinalint SHARD_COUNT 16; // 分片数量 // 写入时同时写入所有分片 public void setHotKey(String key, String value) { for (int i 0; i SHARD_COUNT; i) { String shardKey key :shard: i; redis.set(shardKey, value, 30, TimeUnit.MINUTES); } } // 读取时随机选择一个分片读取 public String getHotKey(String key) { int shard ThreadLocalRandom.current().nextInt(SHARD_COUNT); String shardKey key :shard: shard; return redis.get(shardKey); } }关键点写入时同时写 N 个分片读取时随机选一个分片把 QPS 均摊到 N 个节点上。比如 30 万 QPS 的热点 Key分 16 片后每个节点只承受约 1.9 万 QPS。代价写入开销增大写 N 次、内存占用增大存 N 份、数据一致性维护成本高。适合读远多于写的场景如秒杀商品详情。方案三读写分离 热点探测京东零售方案img上图展示了京东零售的热点 Key 多级缓存方案第一级本地缓存挡住 90% 请求应用层统计 Key 访问频率超过阈值自动标记为热点 Key存入 Caffeine 本地缓存。第二级Redis 读写分离挡住 9% 请求热点 Key 的读请求路由到从节点分散读压力。第三级DB 熔断兜底1% 请求Redis 全部 miss 时查 DB 前先限流DB 扛不住则返回降级数据。三级缓存协同工作30 万 QPS 的热点 Key 也能稳定应对。六、方案对比总结方案优点缺点适用场景本地缓存性能最好直接挡在应用层多实例数据不一致内存有限数据量小、更新不频繁Key 分片读写都能分散通用性强写入开销大维护成本高读远多于写读写分离对应用透明运维层面解决主从延迟从节点成本读多写少有从节点资源限流降级兜底保命实现简单部分用户看到降级数据兜底方案配合其他方案使用生产推荐组合本地缓存首选 读写分离分散读压力 限流降级兜底保命。面试高频追问追问一热点 Key 和大 Key 有什么区别热点 Key 是访问频率过高问题在于单节点 CPU / 网络被打满大 Key 是数据体积过大问题在于操作耗时长、阻塞主线程。两者可能同时存在比如一个又大又被频繁访问的 Key但解决思路完全不同热点 Key 要分散访问大 Key 要拆分数据。追问二本地缓存和 Redis 缓存的一致性怎么保证本地缓存的过期时间设短一些如 3~5 秒容忍短暂的不一致。如果对一致性要求高可以用Redis Pub/Sub或MQ 广播通知所有应用实例失效本地缓存。也可以接受最终一致性大多数热点数据商品详情、文章内容短暂不一致是可接受的。追问三如何提前预知热点 Key对于可预期的热点如秒杀、大促可以提前将热点数据加载到本地缓存中活动开始前就预热好。对于突发热点需要依赖热点探测机制实时发现并自动缓存。结合监控告警当某个 Key 的 QPS 超过阈值时自动触发本地缓存。常见面试变体变体一Redis 中某个 Key 访问量特别大怎么办变体二秒杀场景下 Redis 的热点 Key 如何处理变体三如何发现 Redis 中的热点 Key变体四本地缓存和 Redis 缓存怎么配合使用记忆口诀热点 Key访问太多单节点扛不住 —— 流量太集中。解决方案优先级本地缓存挡最多 Key 分片分散节点 读写分离分散读 限流降级兜底。与大 Key 区别热点是 来的人太多大 Key 是 东西太大搬不动。生产最佳实践热点探测 本地缓存 读写分离 限流降级四板斧组合使用。总结Redis 热点 Key 是指被大量客户端频繁访问的 Key会导致单个节点 CPU 和网络被打满。发现热点 Key 可以用--hotkeys、MONITOR、业务层监控等手段。解决方案的核心是分散访问压力优先使用本地缓存Caffeine挡住大部分请求配合 Key 分片或读写分离分散 Redis 的读压力最后用限流降级兜底保命。

更多文章