redis-cli --bigkeys仅统计元素个数而非真实内存占用,易误判大Key;应结合MEMORY USAGE或redis-rdb-tools解析RDB获取准确内存分布,并依据encoding、元素大小等特征识别伪大Key与真隐患。

redis-cli --bigkeys 只能看“最大个数”,不是真实内存占用
执行 redis-cli --bigkeys 时,它对 String 类型按字节数排序,但对 Hash/List/Set/ZSet 全部只统计元素个数——比如一个 List 有 10 万个空字符串,--bigkeys 会把它标为“最大”,但它实际内存可能不到 1MB;反过来,一个含 500 个长 JSON 字符串的 Hash,元素数不突出,却可能占 20MB+。
常见错误现象:
- 误以为
--bigkeys报出的 “Biggest hash” 就是内存元凶,结果优化后内存没降 - 在腾讯云等限制
DEBUG或MEMORY USAGE的环境里,仅靠--bigkeys做决策,偏差更大
建议做法:
- 日常巡检可用
--bigkeys快速过一遍,但别直接删或拆分 - 发现可疑 Key 后,务必用
MEMORY USAGE <key>在从节点验证(主节点上执行可能阻塞) - 若环境禁用该命令(如部分云 Redis),跳过这步,直接走 RDB 分析
用 redis-rdb-tools 解析 dump.rdb 才能看清真实内存分布
redis-rdb-tools 是目前最接近 Redis 内存分配逻辑的离线分析工具。它模拟 jemalloc 的块管理规则,计算出的 size_in_bytes 比单纯 strlen(value) 高 10%~30%,更贴近实例中实际占用。
实操关键点:
- 先在 Redis 上执行
BGSAVE,拿到最新dump.rdb文件(注意:不要用正在写的文件,避免解析失败) - 基础命令:
rdb -c memory /path/to/dump.rdb > memory.csv,输出含database,type,key,size_in_bytes,encoding等列 - 想聚焦排查?加过滤:
rdb -c memory --db 0 --filter "user:*" --largest 100 /path/to/dump.rdb > user_top100.csv - 大 RDB 文件易 OOM?加
--bytes 536870912(512MB)分片解析
注意:报告里的 size_in_bytes 是近似值,通常略低于真实值,但排序绝对可靠——Top 10 一定是真正吃内存的 Key。
识别“伪大Key”:编码方式决定内存是否真紧张
同一个数据结构,不同编码方式内存差 3~5 倍。比如 Hash 在元素少、值短时用 ziplist,紧凑;一旦超阈值(默认 hash-max-ziplist-entries 512),自动转成 hashtable,内存翻倍还带指针开销。
看 CSV 报告时重点盯这两列:
-
encoding:值为ziplist/quicklist通常是友好型;hashtable/skiplist要警惕 -
num_elements和len_largest_element:如果元素多但单个很短(如 ID 字符串),大概率是缓存类数据;如果单个元素就 >10KB,基本是日志、序列化对象等“脏数据”
典型陷阱:
- 把
encoding=quicklist的List当成安全结构,忽略其size_in_bytes已达 50MB - 看到
type=hash+encoding=hashtable就认定要拆分,其实可能是业务增长自然导致,需结合访问模式判断
淘汰策略下,大Key是否真被优先清理?
Redis 的 volatile-lru、allkeys-lru 等淘汰策略,**只看 Key 的最后访问时间,不看大小**。也就是说,一个 100MB 的 Hash 如果刚被读过,它比一堆 1KB 的冷 Key 更难被淘汰。
所以“当前淘汰的是大Key还是小Key”这个问题本身有误导性——淘汰行为和 Key 大小无关,只和访问频次、TTL、策略类型有关。真正危险的是:
- 大 Key 被淘汰时,释放内存动作本身会阻塞主线程(尤其
DEL操作) - 大 Key 占着内存不释放,把小 Key 挤出淘汰队列,导致缓存命中率下降
- 主从同步时,大 Key 的 RDB/AOF 传输拖慢整个复制流
结论很实在:别指望淘汰机制帮你“自动清大Key”,得靠 rdb -c memory 定期扫,人工确认后,用 UNLINK(非阻塞删除)或分批 HSCAN/SSCAN 清理。


















