必须显式设置maxmemory,否则淘汰策略完全不生效;默认值0表示不限制内存,策略形同虚设,容器中易致oom killer杀进程,需在redis.conf或启动时固化配置并与cgroup协同。

maxmemory必须显式设置,否则淘汰策略完全不生效
很多人在Docker里跑Redis,配了maxmemory-policy allkeys-lru却始终没看到淘汰日志——根本原因是maxmemory默认为0(不限制),此时策略形同虚设。容器环境尤其容易忽略这点,因为镜像启动时不会报错,但内存会一路涨到OOM Killer干掉进程。
必须在启动时就定死上限,不能依赖“先跑起来再调”。常见错误写法:redis-cli CONFIG SET maxmemory 512mb——这在容器重启后丢失,且可能因初始内存已超限而失败。
- 推荐用
docker run参数传入:-e REDIS_MAXMEMORY=512mb,配合自定义entrypoint脚本自动注入配置 - 或直接挂载配置文件,确保
maxmemory和maxmemory-policy都在redis.conf里取消注释 - 绝对不要设成宿主机内存的80%:Docker容器有cgroup限制,还要给AOF rewrite、复制缓冲区、jemalloc碎片留余量
容器内存限制(--memory)和Redis maxmemory必须协同设置
只设Docker的--memory=1g而不设maxmemory,Redis会无视cgroup硬限,持续分配直到被OOM Killer杀;反之只设maxmemory=1g但Docker没设内存限制,宿主机其他进程可能被挤爆。两者必须套牢。
安全配比是:maxmemory = 容器内存限制 × 0.7~0.8。例如--memory=2g,则maxmemory 1536mb。预留的20%~30%用于:
- AOF重写时的临时内存(可能瞬时翻倍)
- Redis内部结构开销(dict、ziplist等)
- jemalloc内存碎片(
mem_fragmentation_ratio超过1.5就要警惕) - 避免因cgroup统计延迟导致的OOM误杀
volatile-lru和allkeys-lru在容器化缓存场景怎么选
容器常用于部署无状态服务,缓存数据往往混着两类key:带TTL的业务缓存(如user:123:profile)和不带TTL的运行时配置(如app:config:feature_flags)。这时候选错策略会出事。
volatile-lru只扫带EXPIRE的key,看似安全,但一旦漏设一个TTL(比如忘了给新接口加缓存过期),这个key就永远进不了淘汰池,最终撑爆内存;allkeys-lru能兜底,但冷配置可能被误踢——得靠业务层保证关键配置有足够访问频次。
- 如果你所有缓存都走
SETEX/SET key val EX 3600,且确认没有长期有效key,用volatile-lru - 如果用了
SET key val存配置、又懒得改代码,必须上allkeys-lru,并监控evicted_keys指标看是否误删 - 别碰
volatile-ttl:容器扩缩容时TTL重置不一致,会导致刚写入的热点key(如登录token)因剩余TTL短被优先清掉
动态调整要避开容器生命周期陷阱
用CONFIG SET热调maxmemory在容器里风险极高:如果当前内存已超新阈值,命令会失败并返回(error) ERR invalid argument;更糟的是,K8s滚动更新时旧Pod可能还在用老配置,新Pod用新配置,造成集群内策略不一致。
真正安全的做法是把配置固化进镜像或ConfigMap,每次变更都触发镜像重建或ConfigMap版本升级,强制全量同步。临时调试可用redis-cli --raw CONFIG GET maxmemory快速验证,但线上严禁靠CONFIG SET救火。
最容易被忽略的一点:容器健康检查(healthcheck)里必须包含INFO memory解析,监控used_memory_human和mem_fragmentation_ratio,而不是只看容器RSS——因为jemalloc的内存归还延迟会让RSS虚高,实际Redis已开始淘汰。











