Redis 内存模型基础

Redis 作为内存数据库,其性能与内存管理息息相关。理解 Redis 的内存数据结构、消耗构成以及碎片化机制,是进行缓存容量规划、性能调优和故障排查的前提。本章将深入剖析 Redis 的内存模型,为后续的淘汰策略与命中率测试奠定理论基础。

2.1 Redis 内存数据结构

Redis 对外暴露了五种核心数据类型,但底层实际使用了 8 种不同的高效数据结构来实现。这些底层结构的选择直接影响内存占用和操作时间复杂度。

外部类型 底层编码(数据结构) 触发条件 内存效率
String int / embstr / raw 整数 / 短字符串(≤44字节) / 长字符串 极高(int 无额外开销)
List quicklist(ziplist + linkedlist) 默认使用,兼顾内存与性能 高(节点压缩存储)
Hash ziplist / hashtable 字段数 < 512 且每个字段值 < 64 字节时用 ziplist 极高(ziplist 连续内存)
Set intset / hashtable 所有元素为整数且数量 < 512 时用 intset 极高(intset 有序紧凑数组)
Sorted Set ziplist / skiplist + dict 元素数 < 128 且每个元素 < 64 字节时用 ziplist 高(ziplist 节省指针开销)
面试高频点: 当 Hash 或 Sorted Set 使用 ziplist 编码时,内存占用可降低 60% 以上,但修改操作会触发编码转换(升级为 hashtable 或 skiplist),转换过程是 O(n) 的,需注意大 Key 的突发延迟。

2.2 内存消耗构成

Redis 进程的内存消耗并非仅由存储的数据决定,还包括大量辅助结构。一个完整的 Redis 实例内存占用由以下四部分构成:

  • 数据内存(主体): 存储键值对、过期字典、主从复制缓冲区等。通常占总内存的 70%–90%。
  • 进程自身内存: Redis 主进程代码、共享对象(如整数池 0–9999)、Jemalloc 分配器元数据。
  • 缓冲区内存: 客户端输入/输出缓冲区(client query buffer / output buffer)、复制积压缓冲区(repl_backlog)、AOF 重写缓冲区。
  • 内存碎片: 由于内存分配器(Jemalloc)与数据生命周期不匹配导致的不可用空闲空间。
实战经验: 使用 INFO memory 命令查看 used_memory(数据内存)、used_memory_rss(实际物理内存)、mem_fragmentation_ratio(碎片率)。当碎片率 > 1.5 时,建议重启或使用 MEMORY PURGE 命令。
Redis 内存消耗构成 Redis 内存消耗构成 数据内存 键值对 + 过期字典 进程自身内存 代码 + 共享对象 缓冲区内存 客户端 / 复制 / AOF 内存碎片 分配器不可用空间 内存消耗比例(典型生产实例) 数据内存 70%–90% | 进程自身 5%–10% | 缓冲区 2%–5% | 碎片 3%–15% 碎片率 = used_memory_rss / used_memory,正常范围 1.0–1.5

2.3 内存碎片与优化

内存碎片是 Redis 内存管理中不可忽视的问题。碎片产生的主要原因是 数据频繁增删 导致内存分配器无法有效复用释放的内存块。Jemalloc 分配器按固定大小类(如 8、16、32、64 字节等)分配内存,当存储的数据大小与分配器大小类不匹配时,就会产生内部碎片。

碎片产生场景

  • 频繁更新 String 类型: 每次 SET 新值可能改变底层编码(int → raw),导致旧内存释放、新内存申请,产生碎片。
  • 大量过期 Key 删除: 惰性删除或定时删除释放的内存块大小不一,难以被后续分配完全复用。
  • 主从切换或 AOF 重写: 子进程退出后,父进程的内存布局可能被打乱,碎片率短期上升。

碎片优化策略

策略 操作方式 适用场景 风险
重启实例 SAVE + SHUTDOWN + 启动 碎片率 > 1.8 且无法自动回收 停机时间,需主从切换
MEMORY PURGE 执行 MEMORY PURGE 命令 碎片率 1.5–1.8,在线操作 短暂阻塞(毫秒级)
调整 Jemalloc 配置 启动参数 --jemalloc-bg-thread 后台线程异步整理碎片 增加少量 CPU 开销
数据对齐写入 尽量使用固定大小(如 64 字节)的 Value 缓存场景,Value 长度可控 灵活性降低
注意: 不要频繁执行 MEMORY PURGE,它本质上是强制内存分配器进行合并操作,在高并发写入场景下可能引起性能抖动。建议监控碎片率,仅在超过阈值时手动触发。
内存碎片产生与回收流程 内存碎片产生与回收流程 频繁数据增删 内存释放不连续 碎片率上升 MEMORY PURGE 重启实例 数据对齐写入 碎片回收建议 碎片率 1.0–1.3:正常,无需处理 碎片率 1.3–1.8:优先 MEMORY PURGE 或数据对齐 碎片率 > 1.8:计划内重启,配合主从切换

2.4 内存模型与淘汰策略的关联

Redis 的内存淘汰策略(如 allkeys-lru、volatile-ttl)直接作用于数据内存部分。理解内存模型有助于:

  • 容量规划: 根据数据结构编码和碎片率估算实际可用内存,设置合理的 maxmemory。
  • 淘汰效率: 使用 ziplist 编码的 Hash 在淘汰时需遍历整个列表,性能低于 hashtable;大 Key 会阻塞淘汰线程。
  • 命中率优化: 碎片率过高会导致有效缓存空间减少,间接降低命中率。定期整理碎片可释放 5%–15% 的可用内存。
测试建议: 在性能测试前,先通过 MEMORY STATS 命令获取详细的内存分配情况,重点关注 allocator.allocated、allocator.active、allocator.resident 三个指标,它们分别代表分配器已分配、已使用、已驻留的内存,差值即为碎片。