redis大key指value过大,string超10kb、集合类超5000元素等;其导致内存倾斜、性能下降、网络拥塞及主从同步风险;推荐用redis-cli --bigkeys采样扫描而非全量遍历。

redis-cli 里查不出大 Key,别硬扫
直接用 redis-cli 连上去执行 KEYS * 或 SCAN 遍历所有 key,再挨个 MEMORY USAGE 测大小,不仅慢,还会阻塞主线程——尤其当 key 数量超过 10 万时,基本不可行。更糟的是,MEMORY USAGE 对某些复合结构(比如带大量 field 的 HASH)返回值不准确,容易误判。
真正有效的做法是先跳过逐个测量,改用采样 + 分类统计:
- 用
redis-cli --bigkeys快速扫描出疑似大 Key(它会按数据类型分组统计 top N 最大 key,不全量遍历) - 配合
redis-cli --memkeys(Redis 7.0+)或第三方工具如redis-rdb-tools解析 RDB 文件,获取精确内存分布 - 若已知业务模块,优先检查高频写入的 key 前缀,例如
user:session:*、cache:report:*,再针对性查MEMORY USAGE
maxmemory 设置不生效?检查配置加载路径和运行时状态
在 redis.conf 里写了 maxmemory 2gb,但 redis-cli INFO memory 显示 used_memory_human 远超这个值,说明配置没生效。常见原因有三个:
-
redis-server启动时没指定该配置文件,实际加载的是默认配置(检查启动命令是否带-c /path/to/redis.conf) - 配置被运行时命令覆盖:执行过
CONFIG SET maxmemory 0(即禁用限制),需用CONFIG GET maxmemory确认当前值 - Docker 容器中挂载配置失败:检查
docker inspect输出的Mounts是否真实映射到容器内/usr/local/etc/redis/redis.conf路径
验证方式很简单:redis-cli CONFIG GET maxmemory 返回值必须是非零正整数,且单位是字节(比如 "2147483648" 表示 2GB)。
allkeys-lru 不等于“自动清理”,它只在写操作触发时才淘汰
设了 maxmemory-policy allkeys-lru,但内存还是持续上涨,不是策略失效,而是触发条件没满足。LRU 淘汰只在以下情况发生:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 新写入命令(如
SET、HSET、LPUSH)导致内存即将超限,Redis 才会主动淘汰旧 key - 读操作(
GET、HGETALL)不会触发淘汰,哪怕内存已满 - 如果业务全是读请求,或者写入量极低,淘汰机制就“睡着了”,内存不会下降
所以不能指望它像 GC 一样定期清扫。如果发现内存长期高位不动,要确认是否有持续写入,以及淘汰后是否仍有新数据快速填坑——这时候得看业务逻辑是否在反复写入相同 key,或 key 设计本身不合理(比如把日志堆进一个 LIST)。
volatile-* 策略要求你主动设过期时间,否则无效
选了 volatile-lru 却发现没 key 被淘汰,大概率是因为你根本没给 key 设置过期时间。volatile-* 类策略只作用于带 EXPIRE 或 PEXPIRE 的 key,其他 key 视为“永久”,完全不受影响。
检查方法:redis-cli TTL some_key 返回 -1(永不过期)或 -2(key 不存在),都不是淘汰目标。临时补救可以批量加过期:
redis-cli --scan --pattern "user:*" | xargs -n 1 -I {} redis-cli EXPIRE {} 3600
但更关键的是从代码层确保写入时带上 EXPIRE 或直接用 SETEX,而不是事后补。
Redis 内存问题最难缠的地方不在配置开关,而在于“淘汰”和“过期”是两套独立机制——前者管空间,后者管时效;两者叠加时,行为取决于你是否同时满足条件(比如既要写入触发淘汰,又要 key 本身有过期时间)。漏掉任一环,策略就形同虚设。










