redis 7.0下string型bigkey判定标准应为memory usage >100kb,而非传统10mb;需结合scan与memory usage精准识别,并通过分片、压缩、懒加载及unlink(≥7.0.12)协同治理。

String类型BigKey的判定标准不能只看10MB
很多团队还在沿用“String超过10MB才算BigKey”的老经验,这在Redis 7.0里已经不安全了。实际业务中,一个user:profile:12345存了压缩后的JSON(比如gzip+base64),即使只有800KB,但反序列化时占满客户端堆内存、网络传输耗时超200ms,它就是事实上的BigKey。Redis 7.0默认启用了lazyfree-lazy-user-del yes,但对String类型无效——unlink只能释放集合类key的内存,对大String仍是同步回收。
优先用MEMORY USAGE精准定位,别依赖--bigkeys
--bigkeys只统计String的字节数,不反映真实内存开销(比如embstr vs raw编码差异、SDS额外头信息),而且扫描过程仍会间歇性争抢CPU。更准的做法是结合SCAN + MEMORY USAGE:
- 先用
SCAN 0 MATCH user:profile:* COUNT 1000分批获取候选key - 对每个key执行
MEMORY USAGE <key></key>,直接拿到实际内存占用字节数 - 筛选出>100_000(即100KB)的key,这才是Redis 7.0下真正需要干预的阈值
注意:MEMORY USAGE本身是O(1)命令,不会阻塞,但高频调用仍建议避开流量高峰。
拆分+压缩+客户端协同才是落地关键
单纯“删掉重来”解决不了问题,必须让业务代码感知并配合。推荐三步走:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 服务端写入时自动分片:把一个大String按每段≤64KB切分,存为
user:profile:12345:0、user:profile:12345:1…用HSET或LPUSH管理索引,避免业务层拼错顺序 - 启用
gzip压缩再存:Java侧用CompressUtil.compress(),Go用gzip.Writer,压缩后体积常降至1/3~1/5,且Redis 7.0对小对象压缩友好(embstr编码更易触发) - 客户端读取时做懒加载:不要一次性
GETRANGE全量拉取,改用GETRANGE <key> 0 65535</key>分段读,配合本地缓存合并
漏掉的一点是:如果该String用于下游系统直连(比如日志服务通过Redis拉原始数据),必须同步改造下游解析逻辑,否则拆分后它们会读到碎片化内容。
删除大String必须用UNLINK,但得确认Redis版本
很多人以为UNLINK在所有Redis 7.x都支持String异步删除,其实不然——只有7.0.12及以上才修复了UNLINK对大String的后台释放缺陷(早期版本仍会短暂阻塞)。验证方法:
- 执行
INFO server | grep redis_version,确保输出≥7.0.12 - 删除前先
DEBUG OBJECT <key></key>看encoding是否为raw(>44字节的String会升为raw),因为embstr编码的key即使UNLINK也走同步路径 - 生产环境删除前,务必用
CLIENT PAUSE 1000 WRITE暂停写入1秒,防止删除期间新数据写入导致内存抖动
最易被忽略的是:压缩后的String虽然体积小了,但解压时CPU飙升,如果多个客户端并发解压同一key,可能打满应用服务器CPU——这已不属于Redis层问题,但故障现象完全一样。










