一句话结论
Redis 不会"凭空崩溃",但也不会"永远自己清理"
取决于 maxmemory 配置:
- 设了 maxmemory + 非 noeviction 策略 → Redis 自动清理(按策略淘汰旧键),服务继续跑,不崩溃。
- 设了 maxmemory + 默认 noeviction → Redis 不清理,但只是写命令返回 OOM 错误,进程不崩溃,读命令照常。
- 没设 maxmemory(=0,默认不限制) → Redis 一直吃内存,直到宿主机内存耗尽,被 Linux OOM Killer 杀掉或系统卡死——这才是"崩溃"的真实来源。
所以记住一句话:Redis 内存满 ≠ 崩溃。"崩溃"几乎都来自「没给 Redis 设上限」或「设了上限但缓存/副本缓冲把内存撑爆」。下面逐层拆开。
两种根本局面:看 maxmemory 这道分水岭
Redis 判定"内存满"的唯一标准是:当前数据占用的内存 ≥ maxmemory。而 maxmemory 默认是 0,意思是"不限制"。这就分出两条完全不同的命运。
图 1:内存满后的两条命运,由 maxmemory 这道分水岭决定
✅ 情形 A:设了 maxmemory
Redis 知道自己的"红线"在哪,数据内存触顶时会主动介入:要么按淘汰策略删旧键腾空间,要么(默认策略下)拒绝再写入但保住进程。无论哪种,进程不会崩。
💥 情形 B:没设 maxmemory
Redis 认为"内存无限大",来者不拒。直到把整台机器的物理内存吃光,由操作系统来决定谁去死——通常是 Redis 这个大内存户被 OOM Killer 优先干掉。这个崩溃锅不在 Redis 逻辑,在配置缺失。
设了 maxmemory 后:8 种淘汰策略怎么选
maxmemory-policy 决定 Redis 触顶时"淘汰谁"。8 种策略可分成 4 个家族,关键看两点:候选范围(所有键 vs 仅带 TTL 的键)和选择算法(LRU / LFU / TTL / Random)。
图 2:8 种策略的两大分类维度——候选范围(allkeys / volatile)与算法(LRU/LFU/TTL/Random),外加"谁都不淘汰"的 noeviction
8 种策略一览表
| 策略 | 候选范围 | 选择算法 | 行为 | 典型用途 |
noeviction | — | 不淘汰 | 默认 写命令报错,不删数据 | 当缓存用时不选它;用于"数据神圣不可丢" |
allkeys-lru | 全部键 | 近似 LRU | 最常用 删最久未用 | 纯缓存,所有键都可再生 |
allkeys-lfu | 全部键 | LFU 频率 | 删访问频次最低 | 热点明显、需长期保留热键 |
allkeys-random | 全部键 | 随机 | 随机删 | 几乎不用,仅特殊测试 |
volatile-lru | 仅带 TTL 键 | 近似 LRU | 在有过期键里删最久未用 | 缓存+持久数据混存,只淘汰临时键 |
volatile-lfu | 仅带 TTL 键 | LFU 频率 | 在过期键里删最不常用 | 同上,但更重频率 |
volatile-random | 仅带 TTL 键 | 随机 | 在过期键里随机删 | 极少用 |
volatile-ttl | 仅带 TTL 键 | 剩余寿命 | 删"最快过期"的键 | 希望尽量留长生数据 |
关键区分:allkeys-* vs volatile-*
- allkeys-*:候选是所有键。哪怕你设置了 TTL 的持久数据,也可能被淘汰。适合"Redis 就是缓存"的场景。
- volatile-*:候选只限带 TTL 的键。没设过期时间的键(持久数据)永远安全。适合"缓存和持久数据放同一个 Redis"的场景。
- ⚠️ 坑:用
volatile-* 时,如果所有键都没设 TTL,候选集为空 → Redis 退化为 noeviction,写命令直接报错!
noeviction(默认策略)的真相:报错,不是崩溃
很多人以为"内存满了 Redis 就崩",其实默认配置下它最温和:宁可报错也不删你的数据。
内存满 + noeviction 时
- 所有写类命令(SET、LPUSH、HSET、EXPIRE…)返回错误
OOM command not allowed when used memory > 'maxmemory'
- 读类命令(GET、HGET、LRANGE…)完全正常,能继续服务
- 删除类命令(DEL、EXPIRE 后自然过期)正常,可手动腾空间
- Redis 进程不崩溃、不重启
这意味着什么
- 你的已存数据完好无损——这是 noeviction 的设计初衷:宁可写不进,也不乱删
- 适合把 Redis 当数据库/消息队列而非纯缓存的场景
- 代价是:应用层的写会批量失败,需要业务侧做好降级/重试/告警
- 这不是崩溃,但体验上像"服务不可写",必须被监控到
⚠ 所以"会崩溃吗"的准确答案是
配置了 maxmemory(无论什么策略),Redis 进程都不会自己崩溃。崩溃只发生在「完全没配 maxmemory」导致被系统 OOM Killer 干掉,或「配了 maxmemory 但缓冲/副本把内存撑爆」的边界情况(见下文)。
自动清理靠什么算法:LRU / LFU / TTL / Random
当策略决定"要淘汰"时,具体挑哪个键?四类算法各有取舍。
LRU(最近最少使用)——最经典
淘汰"最久没被访问"的键。Redis 实现的是近似 LRU:不维护精确链表,而是随机采样 maxmemory-samples(默认 5)个键,从中挑最久未用的淘汰。牺牲一点精度换 CPU。
LFU(最不频繁使用)——Redis 4.0+ 更聪明
淘汰"访问频次最低"的键。每个键维护一个 8 位对数计数器(morris counter),访问时概率自增、随时间衰减。比 LRU 更能识别"曾经热但已冷"的键,适合长期热点场景。两个旋钮:lfu-log-factor(增长快慢,默认 10)、lfu-decay-time(衰减分钟数,默认 1)。
图 3:近似 LRU(采样挑最久未用)与 LFU(按访问计数器挑最低)两种核心算法的对比
TTL 与 Random
- volatile-ttl:在带 TTL 的键里,淘汰剩余寿命最短的(越快过期越先走)。简单但不管访问热度。
- random(allkeys / volatile):随机挑一个淘汰。几乎只用于测试,生产不推荐——会误删热键。
✅ 工程选型直觉
纯缓存首选 allkeys-lru;有明显长期热点的选 allkeys-lfu;缓存与持久数据混存的选 volatile-lru/lfu;永远别用 random 当生产策略。
情形 B 的崩溃真相:不是 Redis 崩,是系统杀了它
当 maxmemory = 0(默认),Redis 不限制自己。内存使用会一路上涨,直到宿主机 RAM 耗尽。
图 4:未设 maxmemory 时,Redis 内存曲线一路逼近物理上限,越线后被操作系统 OOM Killer 终结
Redis 不设上限:客户端持续写入,used_memory 单调上升,Redis 自身不报警、不拦截。
逼近物理内存:系统可用内存见底,开始用 swap,Redis 响应变慢(磁盘 IO)。
内存耗尽:内核 OOM(Out-Of-Memory)子系统启动,按 oom_score 挑"最该死"的进程。
Redis 被 Kill:占用大内存的 Redis 通常是首选目标,进程直接被杀,表现为"突然崩溃/失联",日志里常见 Out Of Memory 或进程直接消失。
恢复:若开了持久化(RDB/AOF)可重启加载;若是纯缓存则丢失全部热数据,瞬间击穿到后端 DB。
⚠ 第二大坑:配了 maxmemory 也可能 OOM
maxmemory 只计算数据内存,不包括:客户端输出缓冲、副本同步缓冲、AOF 重写缓冲、内存碎片。这些都会让 used_memory_rss(实际物理占用)超过 maxmemory。所以「设了 maxmemory 仍被 OOM」很常见——根因是缓冲/碎片,不是数据本身。
内存满时,Redis 到底走哪条路(完整决策流)
图 5:从"内存触顶"到"最终走向"的完整决策链路——核心分叉是 maxmemory 配没配、以及 policy 是不是 noeviction
一句话串起来:配了 maxmemory,Redis 永远不崩(要么自清、要么报错);没配 maxmemory,崩溃风险来自操作系统,不在 Redis 自身逻辑。
怎么配置、怎么监控:把崩溃挡在门外
1. 设置上限与策略(推荐生产)
# 临时生效(重启后失效)
CONFIG SET maxmemory 2gb
CONFIG SET maxmemory-policy allkeys-lru
CONFIG SET maxmemory-samples 5 # LRU/LFU 采样精度
# 永久生效:写进 redis.conf
maxmemory 2gb
maxmemory-policy allkeys-lru
2. 监控这几个指标(核心)
| 指标 / 命令 | 看什么 | 异常信号 |
INFO memory → used_memory / maxmemory | 数据内存 vs 上限 | 两者接近 → 即将触顶 |
INFO memory → mem_fragmentation_ratio | 碎片率 (rss/used) | >1.5 碎片严重,rss 远超上限 |
INFO stats → evicted_keys | 累计淘汰数 | 持续增长 → 在频繁淘汰 |
INFO stats → expired_keys | 自然过期数 | 过低却频繁淘汰 → 策略不当 |
CONFIG GET maxmemory-policy | 当前策略 | 是 noeviction 且写报错 → 需调 |
INFO clients → client_recent_max_output_buffer | 客户端缓冲 | 大缓冲 → rss 超上限隐患 |
3. 排查"明明配了 maxmemory 还崩"的思路
- 先看
used_memory 是否真超 maxmemory:若没超,说明崩在缓冲/碎片(rss 超了)。
- 看
mem_fragmentation_ratio:高碎片 → 考虑 activedefrag 主动碎片整理。
- 看
client_recent_max_output_buffer 和副本偏移:大查询/慢副本会撑爆 rss。
- 设
maxmemory 时留出缓冲(如机器 8G,maxmemory 设 4~5G),给缓冲与碎片留空间。
- 若是纯缓存,崩溃后重建可接受;若是数据源,必须开持久化 + 副本,并避免用会丢数据的策略。
6 个常见误区,一次说清
❌ 误区 1:内存满了 Redis 就会崩
错。只要设了 maxmemory,Redis 要么自动淘汰(其他策略),要么拒绝写入(noeviction),进程都不会崩。崩几乎都因没设上限。
✅ 真相 1
崩溃的源头是操作系统 OOM,不是 Redis 逻辑。配置到位,Redis 极稳。
❌ 误区 2:noeviction 会崩溃
错。noeviction 只是让写命令返回 OOM 错误,读照常,进程不死,数据不丢。
✅ 真相 2
它是"最安全但不自动清理"的策略,适合数据不可丢场景,代价是写失败要业务兜底。
❌ 误区 3:设了 maxmemory 就绝不会 OOM
错。缓冲、副本同步、AOF 重写、碎片都不计入 maxmemory,rss 仍可能撑爆内存。
✅ 真相 3
maxmemory 限的是数据,不是进程总占用。要留缓冲 + 监控 rss。
❌ 误区 4:LRU 是精确 LRU
错。Redis 用近似 LRU(采样)换性能,精度靠 maxmemory-samples 调。
✅ 真相 4
想要更准用 LFU;想要更精确可调高 samples,但会更耗 CPU。
❌ 误区 5:volatile-* 一定安全
不一定。若所有键都没设 TTL,候选集为空 → 退化为 noeviction,写直接报错。
✅ 真相 5
用 volatile-* 前,确保要淘汰的键确实设了过期时间。
❌ 误区 6:淘汰影响读性能
基本不影响读。淘汰是后台/写时触发,读命令正常;除非内存压力导致整体 swap 变慢。
✅ 真相 6
真正拖慢的是"内存满→swap→磁盘 IO",不是淘汰本身。
实战配置清单:照着做
- 必设 maxmemory:生产环境永远不要留 0。按机器内存的 50%~70% 设,给缓冲和碎片留余地。
- 选对策略:纯缓存 →
allkeys-lru;长期热点 → allkeys-lfu;缓存+持久混存 → volatile-lru/lfu(且务必给缓存键设 TTL)。
- 别用 noeviction 当缓存:除非你明确要"写满即失败、数据不丢",并做好了业务降级。
- 监控 evicted_keys / used_memory / mem_fragmentation_ratio:设告警,触顶前介入。
- 给 rss 留缓冲:maxmemory 别顶满物理内存,防止缓冲/碎片导致系统 OOM。
- 大查询 & 慢副本是隐形杀手:监控 client output buffer 与副本延迟,避免它们把内存撑爆。
- 纯缓存可丢 → 崩溃可接受;若 Redis 是数据源 → 必须开 AOF/RDB + 副本,且避免会误删持久数据的策略。
- 压测验证:刻意灌满内存,观察是"平滑淘汰"还是"写报错",确认符合预期再上线。
✅ 终极一句话
Redis 内存满了不会自己崩溃:设了 maxmemory 就自动清理或优雅报错;没设才可能被系统 OOM 杀掉。把 maxmemory 配好、策略选对、监控到位,崩溃这个话题就和你没关系了。