Redis内存溢出OOM怎么排查:从应急止血到根因定位的6个步骤
线上Redis报OOM无法写入时如何快速恢复并定位内存瓶颈?本文整理了一套实用的Redis内存溢出OOM排查流程,涵盖状态确认、大Key定位、碎片分析与容量预警。
凌晨值班遇到Redis写入报错OOM,先别急着重启。这时候最要紧的是确认实例是真满了,还是配置策略导致的拒绝写入。连上Redis先执行INFO memory,重点看used_memory和maxmemory的差值。如果差值很小,再看mem_fragmentation_ratio。有时候used_memory没到上限,但RSS过高触发了系统OOM killer,这种情况调大maxmemory没用,得先清理内存。
1. 应急止血与配置确认
确认是内存满导致的写入失败后,优先恢复业务。如果物理机还有余量,可以临时调大maxmemory,但别超过机器剩余内存的80%。更稳妥的做法是检查maxmemory-policy,如果是noeviction,改成allkeys-lru或volatile-lru让Redis自动淘汰。改完配置后观察几秒,确认客户端不再报错,再开始排查根本原因。
2. 内存分布拆解分析
INFO memory里的used_memory只是个总数,需要拆开看。执行MEMORY STATS,关注dataset.bytes和overhead.total。如果overhead占比超过30%,大概率是客户端输出缓冲区或者复制积压缓冲区占用过高。执行CLIENT LIST抓取omem较大的连接,发现异常客户端直接CLIENT KILL断开。另外,Lua脚本缓存也可能占用不少内存,容易被忽略。
3. 大Key扫描与清理
多数OOM情况都与大Key有关。先用redis-cli --bigkeys扫一遍,生产环境记得加-i 0.1降低扫描频率。如果实例太大,bigkeys运行缓慢,可以抽样用MEMORY USAGE查询几个业务前缀的key。找到大Key后,避免直接DEL,应使用UNLINK异步删除,防止阻塞主线程。如果是Hash或ZSet,考虑拆分成多个小Key或者定期清理过期数据。
4. 内存碎片率排查
有时used_memory不高但RSS很高,mem_fragmentation_ratio飙到2以上,这就是内存碎片在作怪。碎片多是因为大量短Key频繁写入删除,或者大量Key集中过期。Redis 4.0以上可以开启activedefrag自动整理,开启后查看INFO stats里的active_defrag_running是否在运行。如果碎片率长期下不来,且业务允许,找低峰期重启实例最为彻底。
5. 过期与驱逐策略评估
执行INFO stats,对比expired_keys和evicted_keys。如果expired_keys很高,说明过期键在大量清理,此时若仍OOM,可能是写入速度远超过期速度。如果evicted_keys持续上涨,需确认淘汰的Key是否都是冷数据,若误删热数据会导致业务性能断崖式下跌。这种情况建议调整过期时间或直接扩容,避免过度依赖驱逐策略。
6. 建立常态化容量预警
处理完故障后,将内存使用率加入告警系统,达到80%即发通知。定期执行bigkeys扫描并做成巡检脚本,将结果存档做趋势对比。此外,代码评审时需关注Key的设计,单个String超过10KB、Hash超过5000个field就要警惕。日常预留30%的内存余量,避免内存打满后再被动应对。