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 数据结构。该流程覆盖了缓存一致性场景中最常见的判断分支。
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 图展示了从内存超限到淘汰完成的完整链路,帮助理解淘汰机制对缓存一致性的影响节点。
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 作为缓存一致性场景的首选。掌握这些基础,才能在后继章节中正确设计缓存更新、删除与一致性保障方案。