如何写出高效的 CQRS 代码?
CQRS 模式可以创造奇迹:它可以将可扩展性、性能、安全性最大化,甚至可以打破 CAP 定理 (1)。尽管如此,CQRS 还是因为其引入的复杂性而获得了一个有争议的名字。例如,Martin Fowler 在其 CQRS 文章 (2) 中认为,应该少用甚至谨慎地应用该模式。 对大多数系统来说,CQRS 增加了风险的复杂性 你应该非常谨慎地使用 CQRS 虽然 CQRS 是工具箱中的一种模式,但要注意的是,它很难用得好,如果处理不当,很容易搞坏你重要的部件。 从我的观点来看,CQRS 带来的复杂性在很大程度上是偶然的,也是可避免的。为了说明我的观点,我想先讨论一下 CQRS 的目标,然后分析一下基于CQRS 系统中常见的三个复杂性的来源。 CQRS 的目标 CQRS 的目标是使用多种模型来表示相同的数据,与可扩展性、可用性、安全性、性能都没有关系。在多个模型中表示相同的数据,这就是目标,剩下的都是副产品。不信?听听 Greg Young 在 DDDEU2016 大会上的演讲 (3) ,他说 CQRS 是为了支持 Event Sourcing (事件溯源)实现而发明的。而且大家可能都知道,Event Sourcing 模型对于写数据来说很强大,但是对于读数据来说却很糟糕,这就是当年他需要 CQRS 的原因:用多个模型来表示相同的数据。 CQRS 是如何实现这个目标的?通过确保只有一个模型作为数据的源头,所有的修改都通过这个模型来达到。 让我们来看看这个解读如何帮助我们解决一些复杂的问题。 复杂性陷阱一:单向命令,或者说过度的隔离 据我所知,所有的 CQRS 的定义都遵循这个模式。 CQRS 是基于 CQS 原则,它指出,操作应该被分为两组:改变数据的命令和查询数据的命令。一旦我们将这一原则提升到架构层面,我们就会得到一个系统,用例被隔离成相同的两组:命令和查询。每个用例既可以是命令,也可以是查询,但绝对不能同时是命令和查询。 一旦用例被隔离,我们会得到很多好处:多种模型、不同的持久化机制、独立的可扩展性等。 你是否感觉到这里有什么问题?这个问题很微妙:所有的 CQRS 定义通常都是从解决方案 — 隔离开始,之后才定义问题 — 多模型。这就导致了对隔离太过热衷:甚至将命令定义为单向的,操作服务器只返回 Ack/Nack 响应,必须轮询一些读模型存储的实际命令才能返回结果。换句话说,复杂度如地狱式的释放。 (编辑:52站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |