Redis无淘汰策略引发服务中断排查指南
时间:2026-03-20 09:03:43 190浏览 收藏
本文深入剖析了Redis在启用noeviction内存淘汰策略时因内存达上限而突然拒绝所有写操作的典型故障现象,揭示其“能读不能写”的本质是策略设计的硬性保护机制而非系统异常;通过精准命令快速验证OOM事件、内存碎片、隐性内存占用(如客户端输出缓冲区、主从复制积压)等关键诱因,并提供分优先级的应急恢复路径——从清理临时数据、动态调高maxmemory、安全切换淘汰策略到终结异常连接;更直击常见误区,指出单纯修改策略却仍报错的三大深层原因:maxmemory设置严重不足、bigkey同步删除阻塞、从节点缓冲区耗尽,强调根治需回归容量规划与长期运维治理,而非仅依赖配置救火。

noeviction 触发后为什么写操作直接报错
noeviction 是 Redis 最保守的内存淘汰策略:当实例内存达到 maxmemory 后,所有写命令(如 SET、LPUSH、HSET)会立即返回 (error) OOM command not allowed when used memory > 'maxmemory'。它不尝试释放任何 key,也不阻塞等待,而是硬性拒绝——所以业务侧看到的是“服务突然不可写”,而非延迟升高。
这不是 bug,是策略设计使然。关键点在于:noeviction 不影响读命令(GET、HGETALL 等照常执行),所以你可能观察到“能读不能写”这种不对称现象。
- 检查是否真被触发:运行
redis-cli info memory | grep -E "(used_memory_human|maxmemory_human|mem_oom_events)",若mem_oom_events值在增长,说明已多次触发 OOM 拒绝 used_memory_human接近甚至略超maxmemory_human是典型信号(注意:Redis 允许短暂小幅超限,但后续写入必拒)- 别只看
used_memory_human,还要对比used_memory_peak_human:如果峰值远高于当前值,说明之前有过大 key 删除或批量过期,但内存未及时归还(可能因内存碎片或 lazy-free 未完成)
如何快速确认是不是 noeviction 在“背锅”
别一上来就改配置。先做三件事,5 分钟内定位根源:
- 查当前策略:
redis-cli config get maxmemory-policy—— 输出必须是noeviction才是它的问题 - 查实时内存压力:
redis-cli info memory | grep -E "used_memory|maxmemory|mem_fragmentation_ratio",若mem_fragmentation_ratio > 1.5,说明内存碎片严重,即使used_memory没满,实际可分配空间也可能不足 - 查有没有“假满”:
redis-cli memory doctor,它会提示是否存在bigkey、client-output-buffer过载、或slave缓冲区堆积等隐性内存占用,这些不会体现在used_memory里,但会挤占可用内存
常见陷阱:有人看到 used_memory_human: 980M、maxmemory_human: 1G 就觉得“还有 20M 缓冲”,但忘了 client-output-buffer-limit slave 可能已占用 300M(尤其主从同步卡住时),真实可用内存早已为负。
临时恢复写入的实操路径
生产环境不能停,得边保服务边排查。以下操作按优先级排序,每步都可单独生效:
- 立刻释放非核心内存:
redis-cli eval "return redis.call('flushdb')" 0(仅限单库无重要数据场景);更安全的是用redis-cli --scan --pattern "tmp:*" | xargs -r redis-cli del清理临时前缀 - 调高内存上限(需确保系统有余量):
redis-cli config set maxmemory 2gb,注意:该设置重启失效,需同步改/etc/redis/redis.conf中的maxmemory - 紧急切换淘汰策略(治标):
redis-cli config set maxmemory-policy allkeys-lru,让 Redis 自动踢旧数据保写入;但要立刻跟进查evicted_keys是否突增,防止误删关键缓存 - 检查客户端连接:
redis-cli client list | grep -v "idle=0",找出空闲连接过多的客户端,它们的 output buffer 可能长期累积未清,用redis-cli client kill id=xxx主动断开
切记:config set 修改不持久,且某些策略(如 volatile-lfu)要求 Redis ≥ 4.0,线上版本不匹配会静默失败,执行后务必再 config get 确认。
为什么改了策略还是写不进去
改完 maxmemory-policy 却依然报 OOM,大概率掉进了这三个坑:
maxmemory本身设得太小,比如只配了 128MB,而一个zset就占 150MB —— 淘汰策略再激进也救不了,因为没东西可淘汰(allkeys-*类策略对单个超大 key 无效,它只能删 key,不能删 key 里的部分元素)- 存在阻塞型 bigkey 删除:比如刚执行了
DEL huge_list,Redis 正在同步释放内存,此时新写入仍会被拒绝,直到释放完成;可通过redis-cli info stats | grep expired_keys和evicted_keys对比判断是否处于“释放中抖动期” - 从节点缓冲区爆了:
redis-cli info replication | grep "slave[0-9]:"若看到state=online但lag持续为 0 或负数,说明从节点同步异常,主节点的repl-backlog和slaveoutput buffer 可能已吃光内存,此时需先修复主从链路
真正棘手的 case 往往不是策略选错,而是 maxmemory 和业务数据规模根本对不上,或者线上长期积累的 bigkey + 集中过期 + 客户端连接池泄漏,四者叠加压垮了内存水位线——这时候改配置只是把报错时间往后推了几分钟。
今天关于《Redis无淘汰策略引发服务中断排查指南》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
186 收藏
-
366 收藏
-
459 收藏
-
185 收藏
-
165 收藏
-
479 收藏
-
288 收藏
-
357 收藏
-
270 收藏
-
289 收藏
-
343 收藏
-
466 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习