Redis内存使用率突然飙升怎么办?先排查大对象
Redis内存使用率毫无征兆地飙升,这事儿在运维圈里太常见了。十有八九,背后是某个或多个“大块头”在作祟——这里说的“大”,可不是指Key的名字长,而是它存储的Value体积过大,或者集合里的元素数量惊人。想要快速定位,redis-cli --bigkeys 扫描通常是第一选择,但这里有个关键提醒:千万别在主节点上贸然执行,否则服务卡顿的苦果,可能得自己咽下。

为什么 --bigkeys 不能在主节点随便执行
这个命令的工作原理,本质上是对全库进行遍历,并对每个Key执行TYPE命令,再根据类型调用STRLEN、HLEN这类命令估算大小。整个过程是阻塞式的,会独占Redis的单线程。实测下来,一个拥有500万Key的实例,扫描持续几十秒是常事,期间所有请求都得排队等待,超时风险极高。
- 执行节点有讲究:务必优先选择从节点执行。如果没有从节点?那就只能等到业务流量低谷期,并做好可能影响服务的心理准备。
- 善用休眠参数:加上
-i 0.01参数,让每次scan后休眠10毫秒,能显著降低对主线程的冲击,当然,总耗时也会相应拉长。 - 理解其局限性:它只返回“每种数据类型中最大的那个Key”。比如
hash类型,只会告诉你元素最多的那个,并不会列出前十名。 - 警惕“水分”统计:对于集合类型(
hash、zset等),它只统计元素个数,而非实际内存占用。这就意味着,1万个空字符串元素和1万个10KB字符串元素,在--bigkeys眼里都是“10000”,但后者对内存的真实压力要大得多。
--bigkeys 输出结果怎么看
命令的输出格式大致如下:
-------- summary ------- Sampled 100000 keys in the selected DB There are 24746 strings greater than 10 kB Biggest string found 'user:profile:10086' has 123456 bytes Biggest hash found 'order:20260405' has 8921 fields
面对这份报告,需要重点关注三类信息:
Biggest string found:这里列出的是值大小超过默认阈值(通常是10KB)的字符串Key。关键要看具体字节数,是否已经接近甚至超过1MB、10MB的警戒线。Biggest hash found:这里显示的是字段数异常多的哈希Key。字段数超过5000就值得警惕,但更要结合业务逻辑判断。例如,order:20260405存储单日订单快照,字段多情有可原;但如果一个用户配置Keyuser:conf:123拥有8000个字段,那大概率是数据写入错误或历史数据未清理。- 末尾的统计行:像
24746 strings greater than 10 kB这样的数据,揭示了问题的规模。如果发现有成百上千个字符串都超过了10KB,那就不是偶发问题,很可能涉及数据结构或使用方式的设计缺陷。
扫出来 bigkey 后,下一步做什么
找到可疑的Key只是第一步,接下来要做的,是确认它是否真的在拖累内存和性能:
- 核实真实内存:使用
MEMORY USAGE命令(Redis 4.0+ 支持)查看Key的实际内存占用。这比--bigkeys的估算准确得多,尤其对于hash、zset这类复杂结构。 - 探查访问模式:通过
SLOWLOG GET 10查看慢日志,检查是否有HGETALL、LRANGE 0 -1这类O(n)复杂度的命令频繁操作该Key。同时,INFO commandstats命令输出的cmdstat_hgetall等统计信息,也能反映相关命令的耗时是否异常。 - 检查过期策略:如果这个bigkey设置了过期时间(
EXPIRE),而Redis配置中开启了lazyfree-lazy-expire yes,那么在其过期被清理的瞬间,仍可能引起主线程阻塞。这种“安静的冲击波”往往最难排查。 - 谨慎执行删除:千万不要直接使用
DEL命令!对于Redis 4.0+版本,改用UNLINK进行异步删除。对于hash这类大Key,也可以考虑使用HSCAN结合HDEL进行分批删除,避免主线程被长时间卡住。
话说回来,真正棘手的bigkey往往隐藏在冷数据中:无人访问、不触发慢查询、却稳稳占据着几MB甚至更大的内存。这类Key因为不是“最大”的,可能不会出现在--bigkeys的榜首,但它们会悄无声息地推高整体内存水平。要揪出这些“隐形杀手”,定期执行 SCAN 扫描并结合 MEMORY USAGE 进行全量采样分析,才是更彻底的解决方案。
