redis在k8s中被oomkilled的根本原因是maxmemory未显式设置或未与容器limits.memory对齐,需设为limits的70%–80%(如2gi→1536mb),并预留fork缓冲(maxmemory-reserved)、禁用noeviction策略。

Redis 在 K8s 里被 OOMKilled,不是因为“内存用太多”,而是因为 maxmemory 没对齐容器 limits.memory,且没预留 fork 和缓冲开销 —— 这是硬性约束,不是可选项。
为什么 maxmemory 必须显式设为 limits.memory 的 70%~80%
Redis 完全不感知 cgroup 限制,limits.memory: 2Gi 对它毫无意义。它只认自己配置的 maxmemory。设成 2gb 就等于告诉 Redis:“你可以用满 2GB 数据内存”,但实际 RSS(含 AOF 缓冲、复制积压、连接对象、fork 子进程所需空间)轻松突破 2.4GB,Kubelet 立刻触发 OOMKilled。
实测中,maxmemory: 1gb 对应 RSS 常达 1.2–1.4gb;若 limits.memory 设为 1Gi,Pod 几乎必被驱逐。
-
maxmemory单位必须小写(mb/gb),2g或2GB会被 Redis 忽略 - 集群模式下,所有 Pod 的 ConfigMap 或启动命令必须统一该值,否则节点淘汰行为不一致,引发 failover 失败
- 用 Helm/Kustomize 时,避免硬编码;推荐通过环境变量注入:
command: ["sh", "-c", "redis-server /etc/redis.conf --maxmemory $REDIS_MAXMEMORY"]
maxmemory-policy 选错会放大 OOM 风险
noeviction 是默认策略,但它在内存满时直接返回 OOM 错误,不淘汰任何 key —— 这会让上游客户端反复重试,堆积请求缓冲,反而推高 RSS,加速触碰容器 limit。
生产环境必须禁用 noeviction,改用:
-
allkeys-lru:适合通用缓存场景,保留热点数据 -
volatile-lfu:适合带 TTL 的缓存,按访问频次淘汰过期 key - 配合
maxmemory-samples 5提高 LRU/LFU 抽样精度,降低误删概率
别用 allkeys-random 或 volatile-random,随机淘汰无法保障缓存有效性,可能刚淘汰热 key 又要重建。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
容器内 ulimit -n 显示 1048576 并不真实
你在容器里执行 ulimit -n 看到的值,其实是宿主机的 fs.file-max,不是容器进程实际能打开的文件描述符上限。真正起作用的是 cgroup 的 pids.max 和 fs.file-max 双重限制。
Redis 日志出现 WARNING overcommit_memory is set to 0! 或频繁 OOM killer enabled,往往就卡在这儿。
- 宿主机需执行:
sysctl -w fs.file-max=2097152并写入/etc/sysctl.conf - K8s Pod
securityContext中加 ulimits:ulimits: - name: nofile soft: 65535 hard: 65535 - 启动命令中显式传参:
redis-server /etc/redis.conf --maxclients 20000,该值不能超过ulimit软限制
maxmemory-reserved 是 fork 安全缓冲,不是可有可无的参数
这个参数从 Redis 6.0+ 引入,仅在 fork 子进程(RDB 生成、AOF rewrite)时起作用,单位是字节(不支持 mb 后缀),默认为 0 —— 这在容器环境下极易导致 fork 失败:Fork operation failed: Cannot allocate memory。
它和 maxmemory 完全独立,不参与淘汰逻辑,只影响子进程内存预估。
- 若开启 AOF + RDB,建议设为
maxmemory-reserved 268435456(256MB) - 该参数仅在
vm.overcommit_memory=0或1时生效;设为2时被忽略 - 必须显式配置,不能依赖默认值
最常被忽略的点是:即使 maxmemory 和 limits 对齐了,maxmemory-reserved 没设,RDB 备份失败后 Redis 会退回到只用 AOF,而 AOF rewrite 同样需要 fork —— 死循环就开始了。










