Redis内存回收-内存淘汰策略

一、引言:当内存"爆仓"时,Redis如何抉择?

作为一款基于内存的高性能数据库,Redis 的速度令人惊叹。但内存是有限且昂贵的资源。当你的业务数据持续增长,最终触碰到 Redis 配置的 maxmemory 上限时,会发生什么?

是直接拒绝所有新写入请求?还是智能地删除一些"不那么重要"的旧数据来为新数据腾出空间?

这就是 Redis 内存淘汰策略(Eviction Policy) 要解决的核心问题。它定义了在内存不足时,Redis 应该如何做出取舍,以保证服务的持续可用性。理解并正确配置这些策略,是每一位 Redis 使用者的必修课。

💡 核心价值
本文将带你全面了解 Redis 的 8 大内存淘汰策略,深入其工作原理,并提供清晰的选型指南,助你避免线上 OOM 事故


二、前置知识:maxmemory 与淘汰触发时机

在讨论策略之前,必须明确两个前提:

  1. maxmemory 配置 :这是 Redis 内存使用的上限。你可以通过 CONFIG SET maxmemory <bytes> 动态设置,或在 redis.conf 中永久配置

    bash 复制代码
    # 设置最大内存为 2GB
    maxmemory 2gb
  2. 触发时机 :只有当 Redis 的已用内存达到或超过 maxmemory 时,才会根据配置的淘汰策略来决定如何处理新的写命令(如 SET, LPUSH 等)。读命令(如 GET)不受影响。


三、八大内存淘汰策略详解

Redis 提供了 8 种不同的淘汰策略,可通过 maxmemory-policy 参数进行配置。它们大致可分为三大类:

第一类:不淘汰任何数据 (noeviction)

  • 策略名 : noeviction
  • 行为 : 这是 Redis 的默认策略 。当内存达到上限时,拒绝所有会增加内存占用的写命令 ,并向客户端返回一个错误信息:(error) OOM command not allowed when used memory > 'maxmemory'
  • 适用场景 : 适用于那些不能容忍任何数据丢失的场景,或者你希望由应用程序层来处理内存不足的情况。但在生产环境中,这通常不是一个好选择,因为它会导致服务不可用。

第二类:仅从设置了过期时间(TTL)的 Key 中淘汰

这类策略只会在那些已经设置了过期时间的 Key 中进行筛选和淘汰,不会动那些永不过期的 Key。

  1. volatile-lru (Least Recently Used - 最近最少使用)

    • 行为 : 从设置了 TTL 的 Key 中,优先淘汰最近最久未被访问的 Key。
    • 原理: 利用近似 LRU 算法(见下文"实现细节")。
    • 适用场景: 经典的缓存场景,其中大部分数据都有明确的过期时间,且访问模式符合"热点数据常被访问"的局部性原理。
  2. volatile-lfu (Least Frequently Used - 最不经常使用)

    • 行为 : 从设置了 TTL 的 Key 中,优先淘汰访问频率最低的 Key。
    • 原理: 利用近似 LFU 算法(见下文"实现细节")。
    • 适用场景: 数据访问频率差异巨大,存在大量"一次性"或"低频"访问的数据。相比 LRU,更能识别出真正的冷数据。
  3. volatile-random

    • 行为 : 从设置了 TTL 的 Key 中,随机选择一个 Key 进行淘汰。
    • 适用场景: 当你认为所有带 TTL 的 Key 价值相当,或者无法预测访问模式时,可以作为一种简单粗暴的选择。
  4. volatile-ttl

    • 行为 : 从设置了 TTL 的 Key 中,优先淘汰剩余存活时间(TTL)最短的 Key。
    • 适用场景: 你希望尽快清理掉那些"即将过期"的数据,为新数据腾出空间。

第三类:从所有 Key 中淘汰(无论是否设置了 TTL)

当你的 Redis 实例中混合存储了有 TTL 和无 TTL 的 Key,或者所有 Key 都没有设置 TTL 时,就需要使用这类策略。

  1. allkeys-lru

    • 行为 : 从所有 Key 中,优先淘汰最近最久未被访问的 Key。
    • 适用场景 : 这是最常用的通用缓存策略。无论 Key 是否有 TTL,都将其视为缓存项,用 LRU 原则进行管理。
  2. allkeys-lfu

    • 行为 : 从所有 Key 中,优先淘汰访问频率最低的 Key。
    • 适用场景: 通用缓存场景,但数据访问模式更倾向于区分高频和低频,而非近期访问。
  3. allkeys-random

    • 行为 : 从所有 Key 中,随机选择一个 Key 进行淘汰。
    • 适用场景: 所有 Key 被认为具有同等价值,或者作为性能测试时的基准策略。

四、核心算法揭秘:LRU 与 LFU 的实现

Redis 并未使用传统的、精确的 LRU/LFU 算法,因为它们需要额外的数据结构(如链表、计数器),会带来巨大的内存和 CPU 开销。Redis 采用的是高效的近似算法

4.1 近似 LRU (Approximated LRU)

  • 原理 : Redis 在每个 RedisObject 结构体中用 24 位(3字节)来记录该对象最后一次被访问的时间戳(秒级精度)。
  • 淘汰过程 : 当需要淘汰时,Redis 会随机采样一小部分 Key(默认 5 个),然后比较它们的 LRU 时间戳,淘汰其中最旧的一个。这个过程会重复,直到释放出足够的内存。
  • 优点: 内存开销极小(每个 Key 只需 3 字节),性能极高。
  • 缺点 : 是一种概率性的近似,并非全局最优。

4.2 近似 LFU (Approximated LFU) - Redis 4.0+

  • 原理 : 同样利用 RedisObject 中的 24 位字段,但将其拆分为两部分:
    • 高 16 位: 记录最近一次递减计数器的时间(分钟级)。
    • 低 8 位: 一个 8 位的访问计数器。
  • 计数器更新 : 采用对数计数器概率性递增机制。访问越频繁,计数器增长越慢,防止其过快饱和。同时,计数器会随着时间缓慢衰减,以反映数据热度的变化。
  • 优点: 能有效区分高频和低频数据,且能适应数据访问模式随时间变化的情况。
  • 缺点: 配置相对复杂,需要理解其衰减逻辑。

五、如何选择合适的淘汰策略?

场景 推荐策略 理由
纯缓存,所有数据都有 TTL volatile-lruvolatile-lfu 只清理缓存数据,保护非缓存数据(如果有的话)。LFU 适合访问频率差异大的场景。
纯缓存,数据无 TTL 或混合 TTL allkeys-lru (首选) 或 allkeys-lfu 将所有数据都视为可淘汰的缓存项。LRU 简单高效,是通用首选。
不能接受任何数据丢失 noeviction 由应用层处理内存不足,但可能导致服务中断。
无法预测访问模式 allkeys-randomvolatile-random 作为兜底方案,简单直接。
希望尽快清理快过期的数据 volatile-ttl 专注于 TTL 维度进行淘汰。

📌 黄金法则 :对于绝大多数缓存场景,allkeys-lru 是最安全、最通用的选择


六、配置与验证

6.1 配置方法

bash 复制代码
# 临时生效
127.0.0.1:6379> CONFIG SET maxmemory-policy allkeys-lru
OK

# 永久生效 (修改 redis.conf)
maxmemory-policy allkeys-lru

6.2 查看当前配置

bash 复制代码
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"

6.3 监控淘汰情况

通过 INFO 命令可以监控淘汰的详细信息:

bash 复制代码
127.0.0.1:6379> INFO memory
# Memory
...
evicted_keys:12345  # 自启动以来被淘汰的Key总数
...

七、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
小雨下雨的雨2 小时前
井字棋AI机器人实现详解 - Minimax算法实战-鸿蒙PC Electron框架完成
前端·人工智能·算法·华为·electron·鸿蒙
睡不醒男孩0308232 小时前
第二篇:深入探索开源数据库高可用:构建基于CLup的PostgreSQL生产级高可用与读写分离架构
数据库·postgresql·开源·clup
Micro麦可乐5 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
码农阿豪5 小时前
从零到一:Spring Boot快速接入金仓数据库实战
数据库·spring boot·后端
鼎讯信通5 小时前
风电光缆运维提质增效:G-4000A 光缆故障追踪仪破解风场巡检难题
运维·网络·数据库
ZC跨境爬虫6 小时前
跟着 MDN 学JavaScript day_7:数学运算与逻辑判断实战测试
开发语言·前端·javascript·学习·ecmascript
三十..6 小时前
MySQL 从入门到高可用架构实战精要
运维·数据库·mysql
fangdengfu1236 小时前
ES分析系统各个服务日志占用量
java·前端·elasticsearch
cfm_29146 小时前
Redis五大基本数据结构底层了解
数据结构·数据库·redis
真实的菜7 小时前
Redis 从入门到精通(十二):典型业务场景实战 —— 排行榜、限流器、秒杀系统、Session 共享
数据库·redis·python