4. 典型架构模式:读多写少场景下的Cache-Aside模式,写多读少场景下的Write-Through模式

在服务边界划分的微服务架构中,缓存层与数据库之间的数据一致性策略直接决定了系统的吞吐能力与故障恢复效率。针对不同的读写比例,业界形成了两种经典的缓存架构模式:Cache-Aside(旁路缓存) 与 Write-Through(穿透写入)。理解这两种模式在PostgreSQL生态下的适用边界与一致性风险,是进行故障排查的前提。

4.1 读多写少场景:Cache-Aside 模式

Cache-Aside 是当前微服务架构中最主流的缓存策略,尤其适用于读请求远高于写请求的场景(如商品详情、用户画像、配置中心)。应用层负责同时管理缓存与数据库,读取时优先查询缓存,未命中则回源数据库并回填缓存;写入时直接更新数据库,并主动失效或更新缓存。

核心原则: 缓存只作为加速层,不承担数据持久化责任;写入操作始终以数据库为准,缓存仅通过失效或更新来保持最终一致性。

Cache-Aside 读写流程

操作 步骤 缓存状态 数据库状态
读请求 ① 查询缓存 → ② 命中则返回 → ③ 未命中则查询DB → ④ 回填缓存 按需加载,逐步预热 作为数据权威源
写请求 ① 更新数据库 → ② 失效或更新缓存 写入后立即失效/更新 实时写入
PostgreSQL 适配建议: 在 Cache-Aside 模式下,建议为 PostgreSQL 开启 track_io_timing 和 pg_stat_statements,以便在缓存未命中时快速定位慢查询。同时,利用 PostgreSQL 的 LISTEN/NOTIFY 机制可以实现缓存失效的异步推送,减少轮询开销。

Cache-Aside 模式下的典型故障点

  • 缓存击穿: 热点 key 在失效瞬间,大量并发请求同时回源数据库,导致 PostgreSQL 连接池耗尽或 CPU 飙升。
  • 缓存雪崩: 大量缓存同时过期,数据库瞬时负载激增,引发级联故障。
  • 数据不一致窗口: 写操作更新数据库后,缓存失效操作因网络延迟或进程崩溃未执行,导致后续读请求命中旧数据。
Cache-Aside 模式:读多写少场景 应用服务 Redis / 本地缓存 PostgreSQL ① 读缓存 ② 未命中,回源DB ③ 回填缓存 ④ 写DB ⑤ 失效/更新缓存 ⚠ 一致性风险窗口 步骤④与步骤⑤之间:数据库已更新,但缓存尚未失效,并发读可能命中旧数据

4.2 写多读少场景:Write-Through 模式

当系统以写入操作为主(如日志采集、订单流水、物联网数据上报),且对读取的实时性要求不高时,Write-Through 模式能够有效减少数据库的直接写入压力。在该模式下,所有写入操作首先经过缓存层,由缓存层负责将数据同步写入数据库,应用层只与缓存交互。

关键约束: Write-Through 模式要求缓存层具备高可用与持久化能力(如 Redis AOF/RDB 或本地 WAL)。一旦缓存宕机且数据未落盘,将导致写入数据丢失。在 PostgreSQL 场景中,通常配合 pg_prewarm 或连接池预热来降低缓存重建成本。

Write-Through 与 Cache-Aside 的核心差异

对比维度 Cache-Aside Write-Through
适用场景 读多写少(读占比 > 80%) 写多读少(写占比 > 60%)
写入路径 应用 → 数据库 → 缓存失效 应用 → 缓存 → 缓存同步写入数据库
读取路径 应用 → 缓存(未命中则回源DB) 应用 → 缓存(缓存始终包含最新数据)
一致性保证 最终一致性,存在短暂不一致窗口 强一致性(缓存与数据库同步写入)
缓存依赖 缓存不可用时,系统仍可降级回源DB 缓存不可用时,写入操作阻塞或失败
PostgreSQL 负载 读峰值时回源压力大,写操作直接落库 写入合并后批量落库,减少随机写

Write-Through 模式下的典型故障点

  • 缓存层写放大: 缓存同步写入数据库时,若批量合并策略不当,可能导致 PostgreSQL 产生大量死元组,触发频繁的 autovacuum。
  • 缓存与数据库写顺序不一致: 在分布式缓存集群中,若部分节点写入成功但数据库写入失败,会导致数据永久丢失或状态分裂。
  • 缓存崩溃后的数据重建: 缓存重启后,需要从 PostgreSQL 全量或增量加载数据,期间写入操作需排队或拒绝,影响系统可用性。
Write-Through 模式:写多读少场景 应用服务 缓存层(写代理) PostgreSQL ① 写入缓存 ② 缓存同步写入数据库 ③ 读缓存(始终命中最新数据) ⚠ 关键依赖 缓存层必须支持持久化(AOF/RDB)与高可用,否则缓存宕机将导致写入数据丢失

4.3 模式选择与一致性故障排查要点

在服务边界划分的背景下,选择哪种模式不仅取决于读写比例,还取决于服务对一致性的容忍度以及缓存层的可靠性。以下为故障排查时的关键检查清单:

故障排查速查表:
  • Cache-Aside 场景: 优先检查缓存失效操作的原子性(是否使用 Lua 脚本或分布式锁),以及缓存过期时间的随机化配置(防止雪崩)。
  • Write-Through 场景: 优先检查缓存层的持久化配置与同步写入的超时重试机制,以及 PostgreSQL 的 max_connections 是否被缓存层的批量写入耗尽。
  • 通用检查: 确认 PostgreSQL 的 vacuum 与 autovacuum 配置是否适配写入模式,避免死元组堆积导致查询性能骤降。

两种模式并非互斥,在同一个微服务系统中,不同的服务边界可以根据自身读写特征独立选择缓存策略。例如,用户服务(读多写少)采用 Cache-Aside,而订单流水服务(写多读少)采用 Write-Through。这种混合架构在提升整体吞吐的同时,也增加了故障排查的复杂度——需要针对每个服务边界的缓存一致性策略单独建立监控与告警规则。