Redis 是个内存数据库,快是快,但内存满了就是硬墙。一旦触发 (error) OOM command not allowed when used memory > 'maxmemory',写操作全停,业务立刻受影响。下面这套流程分「先保命、再定位、后根治」,按分钟级响应来设计。
第一分钟:看清现场
连上 Redis 后先抓三个指标:
redis-cli INFO memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio" redis-cli CONFIG GET maxmemory-policy redis-cli INFO stats | grep evicted_keys
如果 maxmemory-policy 是 noeviction,那满了就会直接拒写。如果是 allkeys-lru,Redis 会自己踢老 key,但也会增加时延抖动。
第二分钟:马上止损
业务不能等排查,先做三件事:
- 临时扩容:
redis-cli CONFIG SET maxmemory 4gb,前提是宿主机还有余量。 - 开淘汰策略:
redis-cli CONFIG SET maxmemory-policy allkeys-lru,让冷数据自动出去。 - 清大 key:用
UNLINK代替DEL,异步删除不阻塞。
redis-cli --bigkeys redis-cli UNLINK session:bulk:list temp:cache:batch
第三分钟:找出内存大户
盲目扩容只是拖延,得知道谁在吃内存。推荐两条命令:
redis-cli --bigkeys redis-cli MEMORY DOCTOR
常见元凶有三类:单个超大 String(比如 500 MB 的 JSON)、成员数爆炸的 ZSET/HASH、没设 TTL 的临时缓存。
长期治理:别让 OOM 再来
临时调整要落进配置文件,否则重启就丢:
maxmemory 4gb maxmemory-policy allkeys-lru activedefrag yes
另外几个习惯能避免大部分内存事故:
- 所有缓存 key 必须带 TTL,业务 key 按生命周期分级。
- 大 HASH/ZSET 按业务维度拆小,单 key 成员数别过百万。
- 监控
used_memory / maxmemory,80% 就告警。 - Redis 只放热数据,冷数据归档到持久化数据库。
淘汰策略怎么选
| 策略 | 行为 | 适用场景 |
|---|---|---|
| noeviction | 写操作直接报错 | 关键数据,不能丢 |
| allkeys-lru | 踢最近最少用 | 通用缓存,最常用 |
| volatile-ttl | 优先踢快过期的 | 带 TTL 的业务数据 |
| allkeys-lfu | 踢访问频率最低 | 访问差异大的缓存 |
常见问题
Q:能不能直接关掉 maxmemory 限制?
A:生产环境不建议。Redis 吃光内存后会被 Linux OOM Killer 直接杀掉,反而全挂。宁可设合理上限加淘汰策略。
Q:mem_fragmentation_ratio 大于 1.5 怎么办?
A:说明内存碎片高。Redis 4.0+ 可以在线开 active defrag:CONFIG SET activedefrag yes。
Q:集群版 Redis 也会单分片 OOM 吗?
A:会。这叫内存倾斜,某个 key 过大或 hash tag 设计不当会让某个分片先满。需要按 key 重新分片或拆分大 key。
你的 Redis 有没有因为某个大 key 半夜报警?欢迎在 fenij.com 留言,把踩过的坑分享出来。