2. Redis缓存基础
在构建缓存一致性接口契约之前,必须扎实掌握 Redis 作为缓存层的三大基础支柱:数据结构决定了能缓存什么形态的数据;读写模式决定了应用与缓存之间的交互范式;过期策略决定了缓存数据的生命周期与自动清理机制。三者共同构成了缓存一致性设计的底层约束。
2.1 Redis 核心数据结构回顾
Redis 提供了多种数据结构,但在缓存场景中,最常用的五种结构及其适用场景如下表所示。选择正确的数据结构,能显著降低缓存一致性维护的复杂度。
| 数据结构 | 底层编码 | 典型缓存场景 | 一致性关注点 |
|---|---|---|---|
| String | int / embstr / raw | 会话 Token、对象 JSON 快照、计数器 | 全量覆盖,更新需原子性 |
| Hash | ziplist / hashtable | 用户属性、商品详情(字段级缓存) | 部分更新,避免整条覆盖 |
| List | quicklist | 消息队列、最新动态列表 | 顺序保证,防止重复消费 |
| Set | intset / hashtable | 标签系统、去重白名单 | 集合运算的原子性 |
| Sorted Set | ziplist / skiplist | 排行榜、延时队列、限流窗口 | 分数与成员的一致性 |
接口契约启示:在定义缓存接口时,应明确指定使用哪种数据结构。例如,用户信息缓存应声明为
Hash 而非 String,以便下游只更新部分字段时不会破坏整个缓存对象。
2.2 缓存读写模式
缓存读写模式决定了数据在 Redis 与数据库之间的流动路径。不同的模式对一致性保证的强度、实现复杂度、性能开销有直接影响。以下是三种主流模式的对比。
| 模式 | 读路径 | 写路径 | 一致性强度 | 典型场景 |
|---|---|---|---|---|
| Cache-Aside | 读缓存 → 未命中读 DB → 回填缓存 | 写 DB → 删除缓存 | 最终一致性(有窗口期) | 通用业务缓存 |
| Read-Through | 缓存组件自动回填(应用无感) | 写 DB → 缓存失效 | 最终一致性 | 数据访问层封装 |
| Write-Through | 同 Read-Through | 写缓存 → 同步写 DB | 强一致性(写路径) | 金融、配置中心 |
接口契约关键决策:在 Cache-Aside 模式下,写操作必须“先写数据库,后删缓存”,这是避免脏数据的基础规则。接口契约应强制要求调用方遵循此顺序,并提供幂等删除接口。
以下 SVG 展示了 Cache-Aside 模式的完整读写流程,这是本课程后续所有一致性方案的基础参考模型。
2.3 缓存过期策略
Redis 的过期策略决定了键值对在何时以及如何被淘汰。理解这些策略对于设计缓存一致性接口至关重要——过期策略直接影响缓存与数据库之间数据不一致的窗口大小。
2.3.1 三种过期删除策略
| 策略名称 | 工作机制 | CPU 开销 | 内存开销 | 一致性影响 |
|---|---|---|---|---|
| 定时删除 | 设置 TTL 时创建定时器,到期立即删除 | 高(每个键一个定时器) | 低 | 窗口期最短 |
| 惰性删除 | 访问键时检查是否过期,过期则删除 | 低(仅访问时触发) | 高(过期键可能长期驻留) | 窗口期最长 |
| 定期删除 | 每秒执行有限次扫描,随机抽查并删除过期键 | 中(可配置频率) | 中 | 窗口期可控 |
接口契约陷阱:Redis 实际采用“定期删除 + 惰性删除”的组合策略。这意味着一个已过期的键可能不会立即被删除。如果接口契约依赖“过期即不可见”的语义,必须考虑这个时间窗口。建议在业务层面增加逻辑过期时间(在 value 中嵌入过期时间戳),由应用主动校验。
2.3.2 内存淘汰策略(maxmemory-policy)
当 Redis 内存达到上限时,淘汰策略决定哪些键被移除。以下是与缓存一致性最相关的四种策略。
| 策略 | 淘汰范围 | 适用场景 | 一致性风险 |
|---|---|---|---|
| allkeys-lru | 所有键 | 通用缓存,热点数据优先保留 | 低(淘汰最近最少使用) |
| volatile-lru | 仅设置了 TTL 的键 | 混合存储(持久键 + 缓存键) | 中(持久键永不淘汰) |
| allkeys-lfu | 所有键 | 访问频率差异极大的场景 | 低(淘汰最不经常使用) |
| volatile-ttl | 仅设置了 TTL 的键 | 优先淘汰即将过期的键 | 中(TTL 短的键先被淘汰) |
接口契约建议:对于缓存一致性要求高的接口,应使用
allkeys-lru 策略,并确保所有缓存键都设置了合理的 TTL。避免使用 noeviction(不淘汰,写操作直接报错),否则在内存满时会导致缓存写入失败,进而引发缓存雪崩。
以下 SVG 展示了 Redis 过期策略与内存淘汰策略的协同工作流程,帮助理解键的生命周期管理。
2.4 基础总结与接口契约映射
本章的三个基础知识点直接映射到缓存一致性接口契约的设计决策:
- 数据结构选择 → 接口应声明缓存的数据结构类型,避免调用方误用。例如:
@CacheStore(type=Hash, key="user:{id}")。 - 读写模式约定 → 接口契约必须明确写操作的顺序(先 DB 后缓存),并提供缓存删除/更新的幂等接口。
- 过期策略配置 → 接口应约定 TTL 的最小值、最大值以及默认值,并告知调用方“过期后数据不可用”的精确语义。
实践检查清单:在定义缓存接口契约前,请确认以下问题:
1. 缓存的数据结构是否与业务字段结构匹配?
2. 写操作是否严格遵循“先 DB 后缓存”的顺序?
3. 是否所有缓存键都设置了合理的 TTL?
4. 是否配置了
5. 是否在应用层实现了逻辑过期时间作为兜底?
1. 缓存的数据结构是否与业务字段结构匹配?
2. 写操作是否严格遵循“先 DB 后缓存”的顺序?
3. 是否所有缓存键都设置了合理的 TTL?
4. 是否配置了
allkeys-lru 淘汰策略?5. 是否在应用层实现了逻辑过期时间作为兜底?