CQRS 完整闭环架构 · 商品读写分离

命令 → 聚合(事件溯源 + 不变量)→ 事件存储(Outbox)→ 投影 → 读模型 → 多级缓存 → 查询 · Go 1.24 标准库 · 零外部依赖 · 双部署形态:make run(单进程) / make up(分布式 6 进程)

命令 CAS 轮询 投影 失效:L2 删除 + 广播 + 延迟双删(500ms) 广播 GET ReadThrough 编排:L1 → L2 → SWR → 回源 → 降级 singleflight 回源 · 熔断监督 · 未命中负缓存 wait_for_version 读己之文(绕过缓存直读) 命令平面 · 意图 → 事实(聚合不变量 · 事件溯源 · 乐观并发 · Outbox 至少一次) 查询平面 · 事实 → 视图(多级缓存 · SWR · 熔断降级 · 读己之文) 写 API X-Idempotency-Key 命令总线 幂等键 · 日志/指标/超时 商品聚合 事件溯源重建 · 业务不变量 不超卖 · 调价≤50% · 归档锁 事件存储 + Outbox 乐观并发 Append · 全局 Seq published 标记 · 至少一次 Outbox 分发器 顺序投递 · 原地重试 投影器 Seq vs Version 幂等 先落库后失效 · lag 水位 读模型(反范式宽表) product_read_model · keyset 索引 Version 版本戳 → ETag 客户端 App / Web / CDN If-None-Match → 304 读/写 HTTP API 请求ID · 日志 · 指标 panic 兜底 · IP 限流 · 优雅关停 400/404/409/503 语义映射 X-Cache-Source · ETag · 游标分页 查询总线 泛型注册 / 类型安全分发 日志/指标/超时/恢复 单查询预算 800ms get_detail(+wait_version) · search 读服务 详情/检索两个 ReadThrough 检索指纹 key · 命名空间失效 读己之文:轮询版本后直读 熔断器(三态 · 就绪联动) 多级缓存 · Entry 双死线(FreshUntil 软过期 / ExpiresAt 硬过期 + 降级宽限期) L1 本地缓存 LRU 8192 + TTL + 抖动 新鲜 10s / 兜底 20s 订阅失效广播 → 本地淘汰 L2 分布式缓存 Redis 语义(可替换) 新鲜 5min / 兜底 2min 负缓存 30s(防穿透) 并发防护 击穿 → singleflight 穿透 → 空值缓存 雪崩 → TTL 抖动 SWR + 降级兜底 Legend 入口/客户端 应用/领域组件 存储(事件/读模型) 缓存基础设施 事件投递 失效/一致性流 回源(singleflight 合并) 读己之文(wait_for_version) 命令/读路径

写侧:一致性从源头保证

  • • 聚合是唯一守门人:不超卖 / 调价≤50% / 归档锁
  • • 乐观并发 Append:并发写同一聚合,一方 409
  • • Outbox 至少一次 + 投影幂等 = 崩溃不丢事件
  • • X-Idempotency-Key:客户端重发不重复执行

读侧:吞吐与韧性

  • • L1→L2→SWR→singleflight 回源→降级兜底
  • • 穿透/击穿/雪崩三防:负缓存/合并/抖动
  • • 先落库后失效 + 延迟双删 + 失效广播
  • • 熔断三态联动就绪探针;分层超时预算

缝合两侧:可观测的最终一致

  • • 全局 Seq = 投影版本 = ETag,一处时钟
  • • wait_for_version:写完立即一致地读回
  • • projection_lag Gauge:写/投影水位差实时告警
  • • X-Cache-Source 透出命中来源,行为可验收