如果发现 Redis 内存溢出了?你会怎么做?请给出排查思路和解决方案
- 标签:后端、场景题
🏛 业务架构师
我的排查 SOP 分止血、定位、根治三段:
第一步:止血(先恢复业务,再查根因)
- 降级非核心的 Redis 使用方(通知、统计类切走或关闭);
- 紧急扩容(云上垂直升配最快)或主从切换;
- 保交易主链路:核心缓存走本地缓存兜底/限流保护 DB。
第二步:定位(数据去哪了)
info memory:used_memory 与 used_memory_rss、碎片率——碎片高(>1.5)是回收失衡,重启或 activedefrag;- 过期堆积:expires 与总 key 数对比——惰性删除跟不上过期速度(批量短 TTL key 场景),大量"逻辑过期物理未删";
- bigkey 扫描:
redis-cli --bigkeys/ RDB 离线分析——一个 500MB 的大集合是内存溢出的头号常客; - 淘汰策略与 maxmemory 检查:noeviction 下写报错但内存仍在涨?策略是否符合数据分级;
- 增长曲线对齐业务事件:某次上线/活动后开始涨 = 新代码引入的泄漏(缓存只写不清、TTL 没设)。
第三步:根治与预防
- bigkey 拆分/结构调整;TTL 全覆盖审计(没 TTL 的 key 要白名单报备);
- 冷数据下线归档;
- 机制化:内存水位告警(70% 警告/85% 动作)、周期巡检 bigkey、新缓存需求评审过"增长模型 + 过期策略 + 丢失影响"三问;
- 大促前容量压测与扩容预案。
业务视角总结:内存溢出几乎都是**"缓存无纪律"的积累**——写得爽、不管死。治理的关键是把"每个 key 的生命周期都有 owner"变成团队规范,架构师的责任是让制度跑在事故前面。
🏗 系统架构师
Redis 内存溢出(达到 maxmemory 后写入报 OOM,或机器级内存耗尽)我按"排查 → 应急 → 根治"三段答:
1. 排查定位:
INFO memory:used_memory vs maxmemory、mem_fragmentation_ratio(碎片率 > 1.5 说明碎片严重,频繁写删小对象所致;< 1 可能已用 swap,最危险);INFO keyspace:各库 key 数量与 TTL 覆盖率——大量无 TTL 的 key 是头号嫌疑;redis-cli --bigkeys/ RDB 离线分析定位 big key;MEMORY USAGE key精确单 key;- 客户端连接数与缓冲区(client-output-buffer,慢消费者堆积)。
2. 应急止血:
- 临时调大 maxmemory(有物理余量时);
- 淘汰策略确认:缓存场景确保是 allkeys-lru/lfu 而非默认 noeviction;
- 低峰清理明确的垃圾 key(分批 UNLINK,禁止 FLUSHALL);
- 杀掉大 key 来源的写入(某些任务在灌脏数据)。
3. 根治:
- big key 拆分压缩;无 TTL 的 key 补过期策略;持久化 fork 内存翻倍预留(maxmemory 设物理内存 50~60%);
- 容量规划:监控 used_memory 增速,水位 70% 告警,到 80% 扩容/分片(迁移用 SCAN 双写切流);
- activedefrag 碎片整理(4.0+,低峰开启)。
预防机制:内存水位是 Redis 最核心的容量指标,我的规范里 big key 扫描(周任务)+ TTL 覆盖率巡检 + 增速告警是三件必配。
💻 全栈开发专家
先稳住,再排查,按"数据面 → 配置面 → 架构面"走:
第一步:确认现象和止血
bash
info memory # used_memory vs maxmemory;fragmentation ratio- 已经 OOM 拒写:立即评估能否临时扩容 maxmemory(有物理余量时)或清理明确可丢的 key;
- 核心原则:不能让 Redis 故障传导成 DB 打穿——客户端限流/熔断先开起来。
第二步:定位内存去向(四个常见元凶)
- bigkey:
redis-cli --bigkeys+MEMORY USAGE;找到就拆分/删除(UNLINK); - 没设 TTL 的缓存:
redis-cli --extended-describe... 实际用扫描脚本统计无过期 key 的量和类型(业务 bug 常见:SET覆盖丢了 TTL); - 淘汰策略不对:
noeviction+ 内存满 = 拒写;纯缓存实例改allkeys-lfu,CONFIG SET即时生效; - 内存碎片:
mem_fragmentation_ratio > 1.5说明碎片严重(频繁修改不同大小 value),开activedefrag或重启整理。
第三步:治本
- 容量规划:峰值数据 × 2 倍冗余;内存使用率 70% 告警;
- 架构:单实例内存超 10GB 就该拆实例/上 Cluster(fork 停顿和故障影响面都小);
- 流程:bigkey 巡检、TTL 规范进上线 checklist。
真实案例:我处理过一次"本地缓存迁移后忘删旧 key",8GB 实例 90% 是 3 个月前的僵尸数据——SCAN + 按前缀批量 UNLINK,两小时清完,比扩容便宜得多。