前言
大家好,这里是程序员阿亮
今天来给大家讲解一下Redis的热key问题
如果你经常刷微博,一定经历过这样的场景:某位顶流明星突然官宣结婚,或者爆出惊天大瓜,几分钟内涌入几千万网友围观。紧接着,微博热搜挂了,页面刷新不出来了。
不仅是微博,电商双 11 的“1元秒杀”、直播间的“千万级红包雨”,都面临着同样的终极技术挑战。在这类极端高并发场景下,后端系统最容易被击穿的薄弱环节,往往指向同一个概念——Redis 热 Key(Hot Key)。
上一篇文章我们聊了占用内存空间的“大 Key”,今天,我们就来会一会这个在瞬间榨干 CPU 和网络带宽的高并发杀手:热 Key。
一、什么是热 Key?它和普通的流量突增有什么区别?
顾名思义,热 Key 就是在极短的时间内,遭遇了极其密集的访问(主要是读操作)的特定 Redis 键。
业界通常没有一个绝对的数值标准,但一般来说,如果单一 Key 的 QPS(每秒查询率)超过了 10,000,或者某个 Key 的访问量占据了所在 Redis 节点总访问量的绝大比例,我们就可以称之为热 Key。
典型的产出场景:
突发性热点事件: 明星大瓜爆出时的该明星个人资料页缓存。
大促与秒杀: 双 11 期间,首页最显眼位置的那个“爆款商品”的库存或详情数据。
头部主播直播间: 直播间的在线人数统计、滚动公屏消息。
核心误区: 有人会问,我组建了 20 台机器的 Redis Cluster(集群),能抗百万并发,区区一个热点事件怎么会扛不住?
真相是: 在 Redis 集群中,数据是根据 Key 的 Hash 值路由到某个具体节点上的。这意味着,不管你集群有 20 台还是 100 台机器,针对同一个 Key 的所有请求,最终都会全部打向集群中的某 1 台单机! 剩下的 99 台机器都在看戏。
二、热 Key 的致命破坏力(蝴蝶效应)
热 Key 的出现,往往会引发一场系统级的“海啸”,它的破坏过程通常是这样的:
1. 单点 CPU 和网卡被瞬间打满
Redis 是单线程处理命令的。当几万、十几万的请求瞬间涌向一台节点请求同一个 Key 时,这台机器的网卡带宽会被瞬间打满,单线程的 CPU 也会跑满(100%)。
2. 正常业务被连带“误杀”
一旦这台 Redis 节点因为热 Key 满载,响应变慢甚至拒绝服务,那么存储在这个节点上的其他正常 Key(比如普通用户的登录 token、正常商品的缓存)也会无法被访问。这就是典型的“城门失火,殃及池鱼”。
3. 恐怖的“缓存击穿”(最严重的后果)
如果这个热 Key 因为过期时间到了被自动删除,或者所在的 Redis 节点直接被巨大的流量“打死”宕机了,接下来会发生什么?
这数以万计的并发请求在 Redis 里找不到数据,会瞬间全部穿透到后层的关系型数据库(如 MySQL)。MySQL 的抗并发能力远不及 Redis,通常几千并发就能让其连接池耗尽、CPU 飙升并直接宕机。
MySQL 一死,整个微服务架构就会发生雪崩,系统彻底瘫痪。
三、 预警雷达:如何揪出潜伏的热 Key?
实际上热key问题一般是突发的,判断热key我们能做的只有事前预测与事发处理
比如说在促销活动开始前进行热点商品预测,在开始后基于redis的服务进行hotkey检查或者其他第三方进行检查
1. 客户端收集(推荐:轻量且精准)
在微服务代码(如 Java 客户端、Jedis/Lettuce 封装层)中,使用本地内存(如 ConcurrentHashMap)对各个 Key 的访问次数进行滑动窗口计数。一旦某个 Key 的访问频率在 1 秒内超过设定阈值(如 1000 次),就异步上报给监控中心。
优点: 截获在源头,对 Redis 服务端零压力。
2. 代理层(Proxy)监控
如果你的架构中使用了中间代理层(如 Twemproxy、Codis,或各云厂商的代理版 Redis),可以在 Proxy 层面做访问统计和拦截。
优点: 对业务代码无侵入。
3. Redis 服务端:–hotkeys 命令 (Redis 4.0+)
Redis 自带了热 Key 扫描工具,但前提是你必须将内存淘汰策略(maxmemory-policy)设置为 LFU (allkeys-lfu 或 volatile-lfu)。
redis-cli -a "password" –hotkeys
缺点: 这是一个离线/异步扫描工具,无法做到毫秒级实时报警,更多用于事后复盘或常规巡检。
四、 终极防御机制:如何解决热 Key 问题?
发现热 Key 后,如何处理?业界经过多年的双 11 和春晚实战,总结出了以下几招“杀手锏”:
方案一:本地缓存(多级缓存)
这是应对读热点最有效、最彻底的方案。既然流量全打到一台 Redis 上受不了,那就不去查 Redis 了!
在我们的应用服务器(Tomcat/Spring Boot)内存中,引入一层本地缓存(如 Java 中的 Guava Cache、Caffeine,Go 中的 BigCache)。
-
执行逻辑:
发现热 Key 后,业务系统将该 Key 的数据缓存到自己 JVM 的内存中,设置一个较短的过期时间(如 5 秒)。 -
效果展示:
假设有 100 台应用服务器,千万级并发打过来,全部在业务机的内存层面就被拦截并返回了。根本没有网络开销,Redis 的压力瞬间降为 0。 -
代价: 本地缓存存在数据不一致的问题。如果数据被修改,本地缓存的 5 秒内依然是旧数据。对于“明星吃瓜”这种容忍短暂延迟的场景极其完美,但对于“账户余额”就不适用了。
方案二:热 Key 散列(打散/拆分)—— 物理分身术
如果你不能用本地缓存,或者需要保证更高的数据一致性,可以使用拆分法。
既然一个 Key 只能存在一个节点上,那我们把一个 Key 变成 100 个副本 Key!
-
执行逻辑:
将热 Key goods_info_1001,复制并重命名为 goods_info_1001#1, goods_info_1001#2 … goods_info_1001#100。
由于后缀变了,根据 Hash 算法,这 100 个 Key 会被均匀分布到 Redis Cluster 的各个节点上。 -
读取机制: 客户端读取时,在代码里生成一个 1~100 的随机数,拼接在 Key 后面再去访问。这样,原本打向一台机器的流量,被完美平摊到了整个集群的所有机器上。
-
写入机制: 当该商品信息更新时,业务代码需要同时更新这 100 个分身 Key。
方案三:读写分离架构
针对读多写少的场景,可以为那一台承担热 Key 的 Redis Master 节点,挂载大量的 Slave(从节点)。
主节点只负责写入,业务端通过配置直接去读取所有的从节点。流量自然被多台从库分担。
方案四:保底机制 —— 限流与熔断
所有的系统都有容量上限。当热点流量大到连“本地缓存 + Redis 集群”都扛不住时(比如遭到了恶意 DDoS 级别的热 Key 攻击),必须在网关层(如 Nginx、API Gateway、Sentinel)直接进行限流。
超过系统承受能力的请求,直接返回“系统繁忙,请稍后再试”或友好的排队页面。活着,比什么都重要。
五、 总结
Redis 热 Key 是对架构师综合能力的终极考验。
-
面对大并发,永远不要奢望单点数据库能抗下所有。
-
监控前置化: 建立热 Key 自动发现与上报机制。
-
多级防护线: 优先采用本地缓存(Caffeine)拦下 99% 的读流量;对于无法缓存的,采用Key 打散(副本分发)策略;最后,永远留有限流熔断的底牌。



