maxmemory 0 是生产环境高危配置,它不限制内存使用,导致redis耗尽ram后占用swap,最终触发oom killer杀死进程;此时maxmemory-policy失效,evicted_keys为0,容器可能因突破cgroup限制而被强制终止。

maxmemory 0 是生产环境的高危配置,它不等于“不限制”,而是等于“放弃内存治理权”——系统会先耗尽 RAM,再吃 Swap,最终触发 OOM Killer 杀死 Redis 或其它关键进程。
maxmemory 0 时 Redis 真实行为:不是“无限”,而是“放任”
Redis 默认 maxmemory 值为 0,表示不主动限制自身内存使用。但操作系统不会配合演戏:当 used_memory 持续上涨,used_memory_rss 超过物理内存后,内核开始将 Redis 的匿名页换出到 Swap;一旦 Swap 也打满,dmesg | grep -i "killed process" 就会出现 redis-server 被标记为 OOM victim 的记录。
常见错误现象:
- Redis 进程 RSS 内存显示 16GB,但
free -h显示可用内存仅剩 200MB,Swap 使用率 95%+ - 日志里没有
OOM command not allowed,却频繁出现连接超时、READONLY You can't write against a read only slave(主节点已挂) - K8s 中 pod 状态为
OOMKilled,但redis-cli info memory里的used_memory还不到 8GB——说明问题出在 RSS 层,不是 Redis 自身逻辑内存
为什么 maxmemory-policy 在 maxmemory=0 时完全失效
maxmemory-policy(如 allkeys-lru)只在 Redis 主动检测到 used_memory >= maxmemory > 0 时才触发键淘汰。当 maxmemory 为 0,Redis 根本不进入驱逐判断路径,所有写操作照常执行,直到操作系统层面强制干预。
这意味着:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
evicted_keys指标永远为 0,监控告警完全失灵 - 你配置了
volatile-ttl,但实际一个 key 都没被淘汰——因为策略压根没运行 - RDB/AOF fork、复制缓冲区膨胀、客户端输出缓冲区堆积等副作用全部失去约束,放大内存峰值
容器环境下更危险:cgroup 限制被绕过
在 K8s 或 Docker 中,即使你给容器设置了 memory.limit_in_bytes=4Gi,Redis 仍可能因 maxmemory=0 导致:used_memory_rss 突破 cgroup 上限,触发内核 OOM Killer。此时容器 runtime 不会优雅终止容器,而是直接 kill 进程,pod 进入 CrashLoopBackOff。
验证方式:
- 进容器执行
cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes,对比redis-cli info memory | grep used_memory_rss - 若后者明显大于前者,且
maxmemory为 0,就是典型越界行为 - 注意:
used_memory_rss包含内存碎片和 fork 子进程的 COW 内存,不是单纯数据体积
正确配置 maxmemory 的三个硬性条件
不能只写个数字,必须满足业务真实水位 + 系统开销 + 安全余量:
- 用
redis-cli --bigkeys和MEMORY USAGE估算当前数据集真实内存占用(不是used_memory,是used_memory_rss峰值) - 预留至少 20% 缓冲:用于 RDB fork(瞬时 ×2)、复制积压缓冲区(
repl-backlog-size)、客户端输出缓冲(client-output-buffer-limit) - 设置必须匹配部署环境:K8s 中
maxmemory应 ≤ 容器 memory limit × 0.8;裸机上应 ≤ 总内存 × 0.7,给系统和其他进程留空间
最易被忽略的一点:maxmemory 是字节单位,不是 MB 或 GB——写成 maxmemory 2g 会被 Redis 忽略(日志报 Bad directive or wrong number of arguments),必须用 2gb 或 2147483648。










