4. 契约概念详解:API契约 vs 缓存契约、契约的组成要素

在缓存版本校验体系中,“契约”是连接业务逻辑与缓存存储的核心约束。它定义了数据在缓存中如何组织、如何识别、以及如何失效。理解契约的本质,是设计可校验、可演进缓存系统的前提。

4.1 API契约 vs 缓存契约

许多团队熟悉API契约(如OpenAPI、gRPC Proto),但容易混淆它与缓存契约的职责边界。两者虽然都用于约定数据格式,但关注点截然不同:

对比维度 API契约 缓存契约
核心目标 定义服务间通信的接口规范 定义缓存中数据的存储与校验规则
作用阶段 请求/响应时 缓存写入、读取、版本校验时
版本载体 URL路径、Header、Schema版本号 Key后缀、Value内嵌版本字段、TTL策略
校验时机 编译期或运行时请求校验 缓存命中后、反序列化前
变更影响 可能导致客户端调用失败 可能导致缓存穿透、数据错乱
典型工具 OpenAPI、gRPC、Thrift 自定义版本号、序列化Schema、TTL策略
关键认知:API契约解决的是“接口兼容性”,缓存契约解决的是“数据兼容性”。一个服务升级API版本时,如果不同步更新缓存契约,旧缓存数据可能被新代码错误解析,导致静默数据损坏。

4.2 缓存契约的三大组成要素

一个完整的缓存契约由三个要素构成,缺一不可:Key模式、Value结构、TTL策略。三者共同决定了缓存数据的可识别性、可解析性和时效性。

4.2.1 Key模式:缓存数据的“身份证”

Key模式定义了缓存键的命名规则,是缓存契约的入口。它必须包含足够的信息来唯一标识一条缓存数据,同时支持版本路由。

推荐结构:

{业务域}:{实体类型}:{版本标识}:{业务主键}

# 示例
user:profile:v2:9527
product:detail:v3:sku_10086
order:list:v1:20240101

Key模式设计原则:

  • 版本前置:将版本标识放在业务主键之前,便于按版本前缀批量扫描或删除。
  • 命名空间隔离:使用业务域作为前缀,避免不同模块Key冲突。
  • 可读性:使用冒号分隔,符合Redis官方最佳实践。
  • 版本号编码:推荐使用整数递增(v1、v2)或语义化版本(v2_1_0),避免特殊字符。

4.2.2 Value结构:缓存数据的“骨架”

Value结构定义了缓存数据的序列化格式和字段约束。它是版本校验的核心战场——不同版本的数据可能字段不同、类型不同、甚至序列化方式不同。

常见Value结构方案:

方案 描述 版本校验方式 适用场景
内嵌版本字段 在Value中增加version字段 读取时比对version值 JSON/Map结构,灵活
Schema ID 使用Avro/Protobuf Schema ID 反序列化时匹配Schema 强类型、高性能场景
包装对象 Value外层包裹版本+数据+校验和 先解析外层,再校验版本 多版本共存、灰度发布
无版本 纯业务数据,无版本标记 依赖Key中的版本标识 简单场景,不推荐
推荐实践:采用“Key版本 + Value内嵌版本”双保险策略。Key版本用于快速路由,Value内嵌版本用于防御性校验,防止错误写入或缓存污染。

4.2.3 TTL策略:缓存数据的“保质期”

TTL(Time To Live)是缓存契约中容易被忽视但至关重要的要素。它决定了缓存数据的有效时长,直接影响版本切换的平滑度。

TTL策略设计要点:

  • 版本切换窗口:新版本上线后,旧版本缓存仍在TTL内存活。TTL越长,新旧数据共存期越长。
  • 渐进式过期:大版本升级时,可主动缩短旧版本Key的TTL,加速数据淘汰。
  • 热点数据保护:对于高频访问数据,TTL不宜过短,否则缓存穿透压力大。
  • 版本回滚:TTL策略需支持快速回滚——回滚后旧版本数据应能立即被新请求使用。
# TTL策略示例
# 新版本上线时,旧版本TTL从3600s缩短至300s
SET user:profile:v1:9527 "{...}" EX 300
SET user:profile:v2:9527 "{...}" EX 3600

4.3 契约组成要素关系图

下图展示了缓存契约三大要素如何协同工作,构成完整的版本校验闭环:

缓存契约三大要素协同关系 缓存契约 Key模式 版本路由 + 唯一标识 Value结构 序列化 + 版本字段 TTL策略 过期时间 + 切换窗口 协同工作流程 1. 请求到达 → 按Key模式生成缓存Key(含版本标识) 2. 缓存命中 → 按Value结构反序列化,校验内嵌版本 3. 版本匹配 → 返回数据;版本不匹配 → 回源并更新缓存 4. TTL到期 → 自动淘汰旧版本数据,完成版本切换

4.4 契约版本校验的完整流程

将三大要素串联起来,就形成了缓存契约版本校验的完整闭环:

  1. 写入阶段:根据当前业务版本,生成带版本标识的Key,序列化Value(内嵌版本号),设置合理的TTL。
  2. 读取阶段:按Key模式构造查询Key,命中后反序列化Value,提取版本号与期望版本比对。
  3. 版本匹配:版本一致 → 直接返回;版本不一致 → 触发缓存重建。
  4. 缓存重建:回源数据库,按新版本契约重新写入缓存,更新TTL。
  5. 版本切换:新版本上线后,旧版本Key自然过期或被主动淘汰,完成平滑迁移。
常见陷阱:只关注Key模式而忽略Value结构校验。例如Key中携带v2,但Value实际是v1格式的数据(由旧版本代码写入)。此时必须通过Value内嵌版本进行二次校验,否则会导致反序列化异常。

4.5 契约版本演进策略

随着业务迭代,缓存契约需要不断演进。以下是三种常见的版本演进策略:

策略 Key模式变化 Value结构变化 TTL策略 推荐场景
原地升级 Key不变 兼容新增字段 TTL不变 小版本、字段追加
版本分流 Key增加版本后缀 可完全不兼容 旧版本TTL缩短 大版本、字段删除/类型变更
双写双读 新旧Key同时存在 两套结构共存 新版本TTL更长 灰度发布、A/B测试