跳到主要内容

CQRS 读写职责分离

CQRS 为什么把命令与查询分开?​

  • CQRS: 命令查询职责分离,为改变状态和读取信息建立不同职责或模型;
  • 命令: 表达要执行的业务操作,返回提交结果或操作标识,不把任意数据查询混入修改职责;
  • 查询: 返回信息,按业务语义不改变领域状态,可以围绕呈现形状优化;
  • 原文边界: “命令不返回值”是严格 CQS 表达,工程中的命令可以返回结果标识,核心仍是读写职责清楚;

分离的读写模型怎样协作?​

命令 → 写模型:校验业务规则并修改状态
↓ 变更传播
查询 ← 读模型:适合展示的投影视图
  • 写模型: 优先维护业务不变量、权限与状态转换,不为了页面查询牺牲写规则;
  • 读模型: 可以使用反规范化结构,减少页面查询时的联接和组装;
  • 部署边界: 读写模型可以在同一个数据库,也可以分开存储,CQRS 不强制拆成两台服务器;
  • 扩展收益: 可以分别优化读吞吐与写事务,而不要求两种负载使用同一套结构;

CQRS 怎样与事件溯源组合?​

  • 组合方式: 写侧保存事件事实,读侧消费事件构建一个或多个物化投影;
  • 恢复: 读模型损坏时可以依据事件重建,重建完成前需定义查询可用性;
  • 依赖边界: CQRS 不要求事件溯源,事件溯源也不要求独立读库,二者分别解决不同问题;

读模型延迟会怎样影响用户体验?​

  • 最终一致: 异步投影可能暂时落后于写模型,用户刚完成操作却还看不到结果;
  • 应对: 返回已确认结果、等待目标版本可见或显示处理中状态,选择取决于业务容忍度;
  • 消费故障: 消息可能重复、失败或乱序,投影需要幂等更新和进度追踪;
  • 权限边界: 查询侧可以简化数据结构,但不能遗漏访问控制或暴露写模型中的私密字段;

什么时候采用 CQRS 才值得?​

  • 适用条件: 读写负载差异明显、复杂领域规则持续演进、多个展示模型或系统集成确实需要独立优化;
  • 安全收益: 写入职责集中后更容易控制哪些业务实体有权修改状态;
  • 代价: 模型数量、同步逻辑和运维工作增加,简单 CRUD 场景通常难以获得相应收益;