# 如果发现 Redis 内存溢出了?你会怎么做?请给出排查思路和解决方案
7 min read
Table of Contents
如果发现 Redis 内存溢出了?你会怎么做?请给出排查思路和解决方案
Redis 内存溢出排查与解决方案
【核心定义】
Redis 内存溢出是指 Redis 实例使用的内存超过了其配置的最大内存限制(maxmemory),导致写入操作失败或触发内存淘汰策略,进而影响服务可用性。
【关键要点】
- 确认溢出现象:通过
INFO memory命令查看used_memory是否接近或超过maxmemory,并检查used_memory_peak的历史峰值。 - 分析内存组成:使用
MEMORY STATS或INFO memory细分内存占用,重点关注used_memory_dataset(数据占用)与used_memory_overhead(管理开销)。 - 识别大Key:通过
redis-cli --bigkeys或MEMORY USAGE key命令定位占用异常的大Key(如大String、大Hash、大List)。 - 检查客户端与副本:确认
client-output-buffer-limit是否合理,避免客户端阻塞或副本同步缓冲区积压;检查used_memory_slaves(副本缓冲区)。 - 评估淘汰策略:检查当前
maxmemory-policy配置,确认淘汰策略是否生效及是否合理。
【深度推导/细节】
内存溢出的根本原因逻辑拆解
Step 1 – 数据增长超预期
- 业务数据量自然增长,未及时调整
maxmemory。 - 写入流量突增,如热点数据爆发或爬虫灌入。
Step 2 – 内存碎片过高
- Redis 内存分配器(jemalloc)产生外部碎片,导致
used_memory_rss(物理内存)远大于used_memory(逻辑内存)。 - 频繁更新不同大小的键值对加剧碎片化,可通过
mem_fragmentation_ratio(= used_memory_rss / used_memory)判断(>1.5 需警惕)。
Step 3 – 缓冲区与开销失控
- 客户端输出缓冲区积压(特别是发布订阅或慢查询时)。
- AOF 重写或 RDB 保存时的写时复制(Copy-On-Write)内存峰值。
- 大量连接(每个连接约 10KB)或大量键(每个键元数据约 96 字节)导致管理开销膨胀。
Step 4 – 淘汰策略失效
- 设置为
noeviction时,写入直接报错(OOM)。 - 设置为
allkeys-lru但所有键均无过期时间或访问模式均匀,LRU 近似算法失效。
【关联/对比】
- Redis vs. Memcached:Redis 支持复杂数据结构与持久化,内存开销更大;Memcached 纯缓存,内存管理更简单。
- 内存淘汰 vs. 过期删除:淘汰是主动移除键以释放空间(触发条件:
used_memory > maxmemory);过期是被动或定期删除(基于 TTL)。 - Redis 集群模式:集群模式下内存溢出可能仅发生在单个分片,需按分片诊断。
【解决方案】
应急处理
- 临时扩容:动态调整
maxmemory(需确保物理内存充足)。 - 强制淘汰:手动执行
FLUSHDB或删除大Key(风险高,优先从副本操作)。 - 切换策略:将
maxmemory-policy临时改为allkeys-lru或volatile-lru缓解压力。
根治措施
- 优化数据结构
- 拆分大Key:将大Hash拆分为多个小Hash(通过哈希取模)。
- 使用压缩:对长字符串启用
LZF压缩(hash-max-ziplist-entries/value等参数调优)。
- 控制内存开销
- 设置合理 TTL,避免永久存储。
- 限制客户端缓冲区:调整
client-output-buffer-limit。 - 监控碎片率:定期重启或使用
MEMORY PURGE(仅支持 jemalloc ≥ 5.0)整理碎片。
- 架构升级
- 启用集群模式,将数据分片到多个实例。
- 使用 Redis 6.0 的客户端缓存(Client-side Caching)减少服务端存储。
- 完善监控
- 设置
used_memory告警阈值(如 80% ofmaxmemory)。 - 定期采集
MEMORY STATS与慢查询日志。
- 设置
【版本差异】
- Redis 4.0+:支持
MEMORY命令族(USAGE、STATS、PURGE),提供更细粒度内存分析。 - Redis 6.0+:支持多线程 I/O,缓解客户端缓冲区压力;引入
RESP3协议优化内存效率。 - Redis 7.0+:改进内存碎片整理,支持
jemalloc主动碎片整理配置。
『面试官追问』
-
如何在不重启的情况下降低内存碎片率?
- 启用
activedefrag配置(Redis 4.0+),设置active-defrag-ignore-bytes与active-defrag-threshold-lower触发自动整理。 - 手动执行
MEMORY PURGE(需 jemalloc 支持)。
- 启用
-
allkeys-lru与volatile-lru在实际业务中如何选择?- 若所有数据均可淘汰,用
allkeys-lru。 - 若部分数据必须持久化(如用户会话),为其设置 TTL 并使用
volatile-lru,无 TTL 键永不淘汰。
- 若所有数据均可淘汰,用
-
Redis 内存溢出会影响持久化吗?
- 会。AOF 重写需要写时复制内存,若
maxmemory设置过低,重写可能因 OOM 失败。 - 建议:
maxmemory留出 20%-30% 缓冲区供持久化操作。
- 会。AOF 重写需要写时复制内存,若
-
如何预估合理的
maxmemory值?- 公式:
maxmemory = 物理内存 * 80% - 系统预留。 - 基于业务数据量模拟压测,观察
used_memory_peak并留出 30% 余量。
- 公式:
-
大Key除了内存问题还会引发什么风险?
- 网络阻塞:单次传输耗时高。
- 阻塞命令:
DEL大Key 会阻塞线程,建议用UNLINK(异步删除)。 - 数据倾斜:在集群中导致分片负载不均。