CQRS 与 Saga:复杂业务的读写分离与最终一致
读写模型分家之后,复杂长事务如何用 Saga 串起来,又如何在不牺牲对账能力的前提下接受最终一致。
很多团队把 CQRS 当成「加个 MQ 同步数据」就完事,结果读模型对了、写模型乱了,长事务更无从下手。CQRS 解决「读写诉求不同」,Saga 解决「业务跨多个聚合却不能开大事务」,两者常一起出现但职责不同。
读写为什么要分家
写模型关心一致性与不变量,是一组小而强的聚合;读模型关心展示与组装,最好能直接查出前端要的 DTO。诉求冲突时强行共用一个模型,两边都不讨好。
不要为了 CQRS 而 CQRS。单表就能满足读写、流量不大的模块,分家只会制造延迟和负担。
Saga 管理长事务
转账、跨境汇款天然跨账户跨系统,不可能用本地事务锁住。Saga 把大事务拆成一串本地事务,每步都有补偿。
| 模式 | 思路 | 适用 |
|---|---|---|
| 编排 | 中心协调器逐步调用并补偿 | 需强管控 |
| 协同 | 各服务靠事件触发 | 去中心低耦合 |
补偿与幂等
Saga 最怕「补偿自己也失败」,所以每步都要幂等:用业务流水号去重,重试不重复扣款。每步记录状态机 PENDING -> DONE / COMPENSATED,补偿顺序与正向相反,对账做兜底而非第一道防线。
最终一致不是「不管了」,而是把一致性从「即时」换成「可验证」:允许短暂中间态,但必须能收敛到正确态。
落地上,CQRS 让读写各取所需,Saga 让长流程可回退,再加独立对账,复杂业务才算立得住。