如何触发 Redis 的 OOM(Out of Memory)错误
【摘要】 Redis 的 OOM(Out of Memory)错误通常发生在内存使用超过配置限制(maxmemory)且没有有效的淘汰策略(Eviction Policy)释放内存时。以下是触发 OOM 错误的场景、原理及防范方法,帮助你理解并避免此类问题。 一、OOM 错误的触发条件Redis 触发 OOM 需满足以下两个核心条件:内存使用超过 maxmemory 限制在 redis.conf 中通...
Redis 的 OOM(Out of Memory)错误通常发生在内存使用超过配置限制(maxmemory
)且没有有效的淘汰策略(Eviction Policy)释放内存时。以下是触发 OOM 错误的场景、原理及防范方法,帮助你理解并避免此类问题。
一、OOM 错误的触发条件
Redis 触发 OOM 需满足以下两个核心条件:
-
内存使用超过
maxmemory
限制- 在
redis.conf
中通过maxmemory
参数设置内存上限(如maxmemory 1gb
)。 - 当
used_memory
(Redis 实际使用内存) ≥maxmemory
时,进入内存限制状态。
- 在
-
未配置或禁用淘汰策略
- 如果
maxmemory-policy
设置为noeviction
(默认值),Redis 会拒绝所有写入操作并返回 OOM 错误。 - 其他策略(如
volatile-lru
、allkeys-lru
)会主动淘汰键以释放内存,避免 OOM。
- 如果
二、触发 OOM 的常见场景
1. 配置 noeviction
策略且内存耗尽
操作步骤:
- 修改
redis.conf
:maxmemory 100mb # 设置较小的内存限制 maxmemory-policy noeviction # 禁用淘汰策略
- 重启 Redis 或动态加载配置:
redis-cli CONFIG SET maxmemory 100mb redis-cli CONFIG SET maxmemory-policy noeviction
- 持续写入数据直到内存耗尽:
for i in {1..100000}; do redis-cli SET "key:$i" "$(head -c 1024 /dev/urandom)" # 写入 1KB 数据 done
结果:
当内存超过 100MB 时,Redis 返回错误:
(error) OOM command not allowed when used memory > 'maxmemory'.
2. 大量数据写入且淘汰策略失效
场景:
- 配置了淘汰策略(如
volatile-lru
),但所有键均未设置过期时间(EXPIRE
),导致无法淘汰。
操作步骤:
- 设置策略为
volatile-lru
(需键有过期时间才能生效):redis-cli CONFIG SET maxmemory-policy volatile-lru
- 写入大量无过期时间的键:
for i in {1..500000}; do redis-cli SET "key:$i" "value" # 无过期时间 done
- 继续写入新键:
redis-cli SET "new_key" "data" # 触发 OOM(无键可淘汰)
结果:
Redis 返回 OOM 错误,因为所有键均未过期,volatile-lru
无法淘汰。
3. 内存碎片化导致实际可用内存不足
场景:
- 内存碎片率(
mem_fragmentation_ratio
)过高(如 >2.0),即使used_memory
未达maxmemory
,系统也可能因物理内存不足触发 OOM。
操作步骤:
- 模拟内存碎片化:
- 频繁写入/删除大键(如 1MB 的键):
for i in {1..1000}; do redis-cli SET "large_key:$i" "$(head -c 1048576 /dev/urandom)" redis-cli DEL "large_key:$i" done
- 频繁写入/删除大键(如 1MB 的键):
- 持续写入数据直到系统 OOM(需结合系统内存限制)。
结果:
Redis 或系统内核可能终止 Redis 进程(取决于系统 OOM Killer 配置)。
三、OOM 错误的底层原理
1. Redis 的内存管理流程
- 客户端发送写入命令(如
SET
)。 - Redis 检查当前内存使用:
- 若
used_memory < maxmemory
,执行写入。 - 若
used_memory ≥ maxmemory
,根据maxmemory-policy
决定行为:- 非
noeviction
:淘汰符合策略的键,腾出空间后写入。 noeviction
:拒绝写入并返回 OOM 错误。
- 非
- 若
2. 系统级 OOM Killer
- 当 Redis 申请的内存超过系统可用物理内存 + Swap 时,Linux 内核的 OOM Killer 可能终止 Redis 进程。
- 触发条件:
- 系统
oom_score_adj
较高(Redis 默认值通常为 0)。 - 无足够 Swap 空间。
- 系统
检查方法:
# 查看 Redis 进程的 OOM 分数
cat /proc/$(pidof redis-server)/oom_score_adj
# 查看系统内存状态
free -h
四、如何模拟与测试 OOM
1. 使用 redis-benchmark
快速触发
# 限制内存为 100MB,策略为 noeviction
redis-cli CONFIG SET maxmemory 100mb
redis-cli CONFIG SET maxmemory-policy noeviction
# 用 benchmark 持续写入(键大小 1KB)
redis-benchmark -t set -n 1000000 -r 1000000 -d 1024
预期结果:
部分写入命令会返回 OOM 错误。
2. 结合 memtier_benchmark
(更灵活)
# 安装 memtier_benchmark(Ubuntu)
sudo apt-get install memtier_benchmark
# 运行测试(100 线程,100万请求,键大小 1KB)
memtier_benchmark --server=127.0.0.1 --port=6379 --protocol=redis \
--clients=100 --threads=10 --test-time=30 --key-pattern=S:S \
--key-minimum=1 --key-maximum=1000000 --data-size=1024 \
--pipeline=1 --command="SET __key__ __data__"
五、防范与处理 OOM 的方法
1. 合理配置 maxmemory
和淘汰策略
# 示例:设置内存上限为 4GB,使用 LRU 淘汰策略
maxmemory 4gb
maxmemory-policy allkeys-lru
策略选择:
volatile-lru
:优先淘汰有过期时间的键(适合缓存场景)。allkeys-lru
:淘汰所有键中的最近最少使用键(适合无过期时间的键)。volatile-ttl
:淘汰剩余 TTL 最短的键(适合短过期键)。
2. 监控内存使用
# 实时监控内存和碎片率
watch -n 1 "redis-cli info memory | grep -E 'used_memory|mem_fragmentation_ratio|maxmemory'"
关键指标:
used_memory_rss
:系统实际分配内存(含碎片)。mem_fragmentation_ratio
:碎片率(>1.5 需关注)。
3. 优化数据结构与键设计
- 避免大键(如单个哈希包含数万字段)。
- 对大键使用分片(如
user:1000:profile
、user:1000:stats
)。 - 启用压缩列表(调整
hash-max-ziplist-entries
等参数)。
4. 启用内存碎片整理
# Redis 4.0+ 配置
activedefrag yes
active-defrag-threshold-lower 10 # 碎片率 >10% 时启动整理
5. 系统级防护
- 限制 Redis 进程的 OOM 优先级:
# 降低 Redis 的 OOM 分数(避免被内核终止) echo -1000 > /proc/$(pidof redis-server)/oom_score_adj
- 增加 Swap 空间(临时缓解方案):
sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile
六、总结
触发方式 | 条件 | 后果 |
---|---|---|
noeviction + 内存耗尽 |
maxmemory-policy=noeviction ,写入数据超过 maxmemory |
返回 OOM command not allowed |
淘汰策略失效 | 策略需依赖过期键(如 volatile-lru ),但所有键均无过期时间 |
返回 OOM 错误 |
系统级 OOM Killer | Redis 申请内存超过系统物理内存 + Swap | Redis 进程被终止 |
最佳实践:
- 生产环境禁用
noeviction
:根据业务选择volatile-lru
或allkeys-lru
。 - 设置合理的
maxmemory
:通常为物理内存的 70%~80%。 - 监控碎片率:>1.5 时启用整理或优化数据结构。
- 测试环境模拟 OOM:验证系统的容错能力(如集群是否自动故障转移)。
通过以上方法,可有效避免 Redis OOM 错误,保障服务稳定性。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)