Redis 的 maxmemory 和 maxmemory-policy 配置详解

Redis 作为内存数据库,内存管理是运维和面试中的高频考点。其中 maxmemorymaxmemory-policy 两个配置项直接决定了 Redis 在内存不足时的行为,理解它们的工作原理,是避免线上故障的关键。

为什么需要设置 maxmemory

Redis 默认对内存使用没有硬性限制(64 位系统下默认为 0,表示不限制),它会尽可能使用服务器上的空闲内存。这在生产环境中非常危险:一旦内存被耗尽,可能触发操作系统的 OOM Killer,导致 Redis 进程被强制杀死,或者引发 swap 交换,使性能急剧下降。

通过设置 maxmemory,我们可以为 Redis 指定一个内存使用上限。当已用内存达到该阈值时,Redis 会根据 maxmemory-policy 采取相应措施,比如淘汰部分键或拒绝写入请求。

配置方式有两种:

# redis.conf 中
maxmemory 4gb
maxmemory-policy allkeys-lru
# 运行时动态修改
redis-cli config set maxmemory 4gb
redis-cli config set maxmemory-policy allkeys-lru

需要注意,maxmemory 统计的是 Redis 实际使用的内存总量,包括数据、缓冲区、复制 backlog 等。如果只设置了 maxmemory 而没有设置合理的淘汰策略,当内存达到上限且策略为 noeviction 时,所有写命令都会返回错误。

maxmemory 的计量口径

很多面试题会追问:maxmemory 到底算的是什么内存?它对应 used_memory 这个指标,而不是 used_memory_rssused_memory 是 Redis 自身统计的分配器分配出去的内存,不含内存碎片和部分运行时开销。因此实际进程占用的物理内存(RSS)通常会略大于 maxmemory。在容器化环境中,如果给容器设置了内存 limit,建议 maxmemory 留出 20%~30% 的余量,避免因碎片或缓冲区导致容器被 OOM Kill。

八种 maxmemory-policy 详解

maxmemory-policy 决定了内存达到上限后的处理方式,共有八种取值,可分为“淘汰类”和“拒绝写入类”。

淘汰类策略

  • noeviction:不淘汰任何键,当内存不足时,写命令直接返回错误,读命令仍可执行。这是默认策略,适合数据不允许丢失的场景,但需要应用层处理写入失败。
  • allkeys-lru:从所有键中,淘汰最近最少使用的键(LRU)。这是最常用的策略,适合缓存场景。
  • allkeys-lfu:从所有键中,淘汰使用频率最低的键(LFU,Redis 4.0 引入)。相比 LRU,它更能抵抗偶发的一次性访问,适合热点数据明显的场景。
  • allkeys-random:从所有键中随机淘汰。适合访问分布均匀、无热点的情况。
  • volatile-lru:只从设置了过期时间的键中,淘汰最近最少使用的。
  • volatile-lfu:只从设置了过期时间的键中,淘汰使用频率最低的。
  • volatile-random:只从设置了过期时间的键中随机淘汰。
  • volatile-ttl:只从设置了过期时间的键中,优先淘汰剩余生存时间最短的键。

“volatile-” 前缀的策略有一个重要前提:如果没有任何键设置了过期时间,那么这些策略的行为等同于 noeviction,写命令会报错。这一点是面试中的常见陷阱。

LRU 与 LFU 的实现差异

Redis 的 LRU 并非精确实现,而是近似 LRU。它没有维护完整的链表,而是在每个对象的 redisObject 中记录一个 24 位的 lru 字段(时间戳)。淘汰时,Redis 随机采样 maxmemory-samples 个键(默认 5),从中选出最久未使用的那个淘汰。采样数越大,越接近真实 LRU,但 CPU 开销也越高。

LFU 则把 24 位字段拆成两部分:高 16 位记录访问时间(分钟级),低 8 位记录访问频率计数器(0~255)。计数器采用概率递增,访问越频繁增长越慢,并会随时间衰减。这样既能反映热度,又能让冷数据逐渐被淘汰。

可以这样理解:LRU 关注“多久没被访问”,LFU 关注“被访问了多少次”。对于突发的全表扫描,LRU 可能把热点数据挤出去,而 LFU 因为热点数据计数器高,更能守住阵地。

如何选择合适的策略

  • 纯缓存场景,数据可重建:优先 allkeys-lru;若热点集中且访问频率差异大,选 allkeys-lfu
  • 缓存 + 持久数据混合:用 volatile-lruvolatile-lfu,只淘汰有 TTL 的键,保护持久数据。
  • 数据绝对不能丢:用 noeviction,并在应用层做好写入失败的处理,同时监控内存。
  • 访问模式随机、无热点:allkeys-random 即可。

实践中的注意事项

第一,淘汰策略只在内存达到 maxmemory 时触发,平时不会主动清理。第二,主从架构下,从库的淘汰由主库同步的 DEL 命令驱动,从库自身不会独立淘汰(除非它自己的内存也超限)。第三,使用 volatile-* 策略时,要确保有足够的键设置了过期时间,否则会退化为 noeviction。第四,可以通过 INFO stats 中的 evicted_keys 观察淘汰数量,如果该值持续增长,说明内存吃紧,需要考虑扩容或优化数据结构。

建议的监控组合是:used_memorymaxmemoryevicted_keyskeyspace_hits/misses。当命中率下降且 evicted_keys 上升时,往往意味着需要调整策略或增加内存。

面试高频问题小结

  1. maxmemory 为 0 代表什么?——不限制内存。
  2. noeviction 下写命令会怎样?——返回 OOM 错误。
  3. volatile-lru 在没有 TTL 键时表现如何?——等同 noeviction
  4. LRU 是精确的吗?——不是,是采样近似。
  5. LRU 和 LFU 的核心区别?——时间维度 vs 频率维度。
  6. maxmemory-samples 的作用?——控制采样精度与 CPU 开销的平衡。

掌握这两个配置项,不仅能应对面试,更能在实际运维中避免因内存失控导致的服务不可用。合理设置上限、选对淘汰策略、持续监控关键指标,才是 Redis 内存管理的完整闭环。

未经允许不得转载:任鹏个人博客 » Redis 的 maxmemory 和 maxmemory-policy 配置详解

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏