2. Redis 基础回顾:核心数据结构与内存管理

在深入缓存一致性方案之前,必须牢固掌握 Redis 的数据结构、过期策略与内存淘汰机制。这些基础能力直接决定了缓存系统的性能边界与数据安全合规基线。本节将逐一拆解五大核心数据结构的使用场景与底层特性,并系统梳理过期与淘汰策略的选型逻辑。

2.1 五大核心数据结构

Redis 提供了丰富的数据结构,每种结构都针对特定操作场景做了极致优化。下表从存储单位、常用命令、时间复杂度与典型业务场景四个维度进行对比。

数据结构 存储单位 常用命令 操作时间复杂度 典型场景
String 字符串 / 数值 / 二进制 SET / GET / INCR / DECR / MSET O(1) 缓存对象、计数器、分布式锁
Hash field-value 映射表 HSET / HGET / HGETALL / HINCRBY O(1) 单 field;O(N) 全量 对象属性存储、用户信息、配置项
List 双向链表 LPUSH / RPUSH / LPOP / RPOP / LRANGE 头尾 O(1);索引 O(N) 消息队列、时间线、最新消息
Set 无序字符串集合 SADD / SREM / SMEMBERS / SISMEMBER / SUNION 增删查 O(1);聚合 O(N) 标签系统、去重、共同好友
Sorted Set 有序集合(score 排序) ZADD / ZRANGE / ZREVRANGE / ZRANK / ZSCORE 增删改 O(log N);范围 O(log N + M) 排行榜、延时队列、限流滑动窗口
合规提示:在安全合规场景下,Hash 结构比 String 更适合存储敏感字段(如用户手机号、身份证号),因为可以按 field 单独设置过期时间(通过 TTL 或主动删除),避免整条记录泄露。Sorted Set 的 score 字段不应存储明文敏感数据,建议使用脱敏后的哈希值。

2.2 数据结构选型决策流程

以下 SVG 图展示了从业务需求出发,如何快速选择最合适的 Redis 数据结构。该流程覆盖了缓存一致性场景中最常见的判断分支。

Redis 数据结构选型决策流程 业务数据需求 是否需要按 score 排序? Sorted Set 是否需要去重? Set 是否需要字段级操作? Hash 是否需要队列特性? List String 提示:缓存一致性场景优先考虑 Hash(字段级更新)与 String(简单键值),避免在 List/Set 中存储大对象

2.3 过期策略

Redis 的过期策略决定了已过期的 key 何时被物理删除。理解这一机制对缓存一致性至关重要——如果过期 key 未能及时清理,可能导致客户端读到脏数据。

2.3.1 三种过期删除策略

策略名称 工作原理 CPU 开销 内存开销 延迟风险
定时删除 创建 key 时启动定时器,到期立即删除 高(大量定时器) 低 低
惰性删除 访问 key 时检查是否过期,过期则删除 低 高(过期 key 堆积) 高(访问时触发)
定期删除 每隔 100ms 随机抽查一批 key,删除过期 key 中 中 中
实际组合策略:Redis 默认采用 惰性删除 + 定期删除 的组合方案。定期删除作为主动清理手段,惰性删除作为兜底机制。这种组合在大多数场景下能平衡 CPU 与内存开销,但在高并发缓存一致性场景中,建议配合主动淘汰或显式 DEL 命令,避免过期 key 在定期删除间隙被读取。

2.3.2 过期策略对缓存一致性的影响

  • 读扩散问题:惰性删除下,大量过期 key 未被访问时长期占用内存,可能导致内存不足触发淘汰,间接影响正常 key 的可用性。
  • 时间精度:定期删除的 100ms 间隔意味着 key 过期后最多有 100ms 的“残留窗口”,在此期间客户端可能读到过期数据。对于强一致性要求的场景,应在应用层做二次校验。
  • 合规建议:存储个人敏感信息的 key 应设置合理的 TTL,并在业务逻辑中主动删除(DEL / UNLINK),避免依赖被动过期。

2.4 内存淘汰机制

当 Redis 内存使用量达到 maxmemory 限制时,淘汰机制开始工作。淘汰策略的选择直接影响缓存命中率与数据一致性。

2.4.1 八种淘汰策略对比

策略 淘汰范围 淘汰依据 适用场景 一致性风险
noeviction 不淘汰 — 纯内存数据库,禁止丢失 写入失败
allkeys-lru 所有 key 最近最少使用 通用缓存,热点数据优先 低
volatile-lru 设置了 TTL 的 key 最近最少使用 有时效要求的缓存 中
allkeys-lfu 所有 key 最不经常使用 访问频率差异大的场景 低
volatile-lfu 设置了 TTL 的 key 最不经常使用 有时效 + 频率差异 中
volatile-ttl 设置了 TTL 的 key 剩余 TTL 最短 优先淘汰即将过期的 key 高
allkeys-random 所有 key 随机 均匀分布,无热点 高
volatile-random 设置了 TTL 的 key 随机 有时效 + 均匀分布 高
合规红线:在安全合规场景下,禁止使用 volatile-ttl 和 volatile-random 作为主要淘汰策略。这两种策略可能淘汰掉尚未过期的敏感数据 key,导致缓存穿透或数据不一致。推荐使用 allkeys-lru 或 volatile-lru,并配合合理的 maxmemory-policy 预留 buffer。

2.4.2 淘汰机制工作流程

以下 SVG 图展示了从内存超限到淘汰完成的完整链路,帮助理解淘汰机制对缓存一致性的影响节点。

Redis 内存淘汰执行流程 客户端写入请求 检查 used_memory > maxmemory 是否超过 maxmemory? 直接写入 执行淘汰策略 释放内存后写入 淘汰阶段可能删除未过期 key,导致缓存穿透或数据不一致

2.5 过期与淘汰的协同关系

过期策略和淘汰机制并非独立运行,它们在内存压力下会产生复杂的交互。理解这种协同关系,是设计缓存一致性方案的前提。

  • 优先级:过期删除优先于内存淘汰。Redis 会先尝试通过定期删除和惰性删除释放内存,如果释放后仍不足,再触发淘汰策略。
  • 淘汰对象:当使用 volatile-* 系列策略时,淘汰范围仅限于设置了 TTL 的 key。如果所有 volatile key 都被淘汰后内存仍不足,Redis 会回退到 noeviction 行为(返回错误)。
  • 数据一致性风险:淘汰机制可能删除尚未过期的 key,导致缓存 miss 后回源数据库。如果回源逻辑存在并发写,可能引发缓存与数据库的不一致。建议在淘汰策略之上叠加 主动过期 + 延迟双删 模式。
生产配置建议:对于缓存一致性要求高的业务,推荐配置 maxmemory-policy allkeys-lru,并设置 maxmemory 为物理内存的 70%~80%,预留足够空间给过期 key 的惰性删除。同时开启 activedefrag yes 减少内存碎片,降低淘汰触发频率。

2.6 本章小结

Redis 的五大核心数据结构各有专长:String 适合简单键值,Hash 适合对象字段级操作,List 适合队列,Set 适合去重,Sorted Set 适合排序场景。过期策略采用惰性+定期组合,淘汰机制推荐 allkeys-lru 作为缓存一致性场景的首选。掌握这些基础,才能在后继章节中正确设计缓存更新、删除与一致性保障方案。