必须显式设置maxmemory-policy为noeviction才能拒绝写入;仅设maxmemory不生效,且需各集群节点单独配置,拼写准确、CONFIG REWRITE持久化,否则仍可能触发默认淘汰。

redis.conf 里必须设 maxmemory-policy 为 noeviction
Redis 默认不启用内存淘汰策略,一旦 maxmemory 被触发,它会按配置的淘汰策略踢数据。但你要的是“拒绝写入”,不是“自动删旧数据”。唯一能达成这个效果的策略就是 noeviction —— 它会让所有写命令(SET、LPUSH、HSET 等)直接返回错误,读操作照常。
常见错误是只配了 maxmemory 却没设 maxmemory-policy,此时 Redis 会用默认策略 noeviction 吗?不会。4.0 之前默认是 volatile-lru,4.0+ 是 noeviction,但你不能赌版本——显式声明才可靠。
-
maxmemory必须设具体值(如2gb),单位支持b/kb/mb/gb,不设或设为0表示不限制 - 策略必须拼写准确:
noeviction(注意没有空格、大小写敏感) - 改完要
redis-cli CONFIG REWRITE或重启生效;仅CONFIG SET临时生效,但进程重启后丢失
写命令失败时返回 (error) OOM command not allowed when used memory > 'maxmemory'
这是 noeviction 生效后的标准报错。不是 bug,是预期行为。客户端看到这个错误,就得自己处理:重试、降级、告警,或者切到只读逻辑。
容易踩的坑是误以为连接断了或命令写错了。比如用 redis-py 执行 set("k", "v") 报 ResponseError,实际就是这个 OOM 错误;Node.js 的 ioredis 会抛出 ReplyError,message 字段含上述字符串。
- 别在应用层吞掉这个错误,否则数据会静默丢失(你以为写成功了,其实没写)
- 监控要抓这个错误率,而不是只看 Redis 的
evicted_keys指标(它在noeviction下恒为 0) -
INFO memory中的used_memory和maxmemory要持续比对,提前预警比等报错更主动
注意 maxmemory 统计范围不含 Lua 脚本内存和连接缓冲区
Redis 的 used_memory 主要统计键值对占用,但不包括:Lua 脚本执行时的临时对象、客户端输出缓冲区(尤其 pub/sub 或 big key scan)、AOF rewrite 时的子进程内存副本。这些可能让实际物理内存远超 maxmemory,导致系统 OOM killer 干掉 Redis 进程。
所以 maxmemory 不是“给 Redis 的总内存上限”,只是它的内部键值存储水位线。真实部署时,建议把 maxmemory 设为机器总内存的 45%~60%,留足余量给其他开销。
- 用
INFO clients查client_longest_output_list和client_biggest_input_buf,判断是否有客户端积压 - 禁用
lua-time-limit或调高它,避免长脚本被强制中断后残留对象 - 如果用了 AOF,确保
auto-aof-rewrite-percentage不设得过高,减少 rewrite 频率
集群模式下每个节点都要单独配 noeviction
Redis Cluster 没有全局内存策略。每个 master 节点独立计算自己的 used_memory,并按本地 maxmemory + maxmemory-policy 决定是否拒绝写入。一个节点爆了,只影响它负责的 slot,其他节点照常服务。
问题在于客户端可能不知道哪个 slot 在哪个节点,盲目重试可能反复打到同一个已满节点。这时候靠客户端的重试逻辑或代理层(如 Twemproxy、Codis)做 failover 就很关键。
- 别指望 cluster nodes 返回的
maxmemory一致——各节点可差异化配置 -
CLUSTER INFO里的cluster_state仍是ok,即使部分节点已拒绝写入 - 运维巡检要逐节点
redis-cli -h {host} -p {port} INFO memory,不能只查一个
noeviction,且所有节点都不能漏。很多人调完发现还是在删数据,八成是策略拼错了,或者根本没 reload 配置。

















