何时使用 CQRS 设计模式?

Posted

技术标签:

【中文标题】何时使用 CQRS 设计模式?【英文标题】:When to use the CQRS design pattern? 【发布时间】:2012-02-07 21:30:23 【问题描述】:

我和我的团队一直在讨论使用 CQRS(命令查询职责分离)设计模式,我们仍在尝试评估使用它的利弊。根据:http://martinfowler.com/bliki/CQRS.html

我们还没有在该领域看到足够多的 CQRS 用途 我们了解它的优缺点

那么你们怎么看,什么时候出现问题需要使用 CQRS?

【问题讨论】:

Darren Cauthon 对 CQRS 和事件溯源做了一个很好的介绍,包括缺点 - 谷歌说它可用 here,但我无法通过我们的防火墙验证。 他个人没在现场见过 【参考方案1】:

CQRL 批评者可能会说 CQRS 很复杂,这可能是真的。

当然,以 CQRS 样式开发一个简单的 CRUD 应用程序会增加开销,所以我会考虑仅在以下情况下使用 CQRS:

    大型团队 - 如果您选择了 CQRS 架构,您可以轻松地在人员之间拆分开发任务。您的***人员可以处理域逻辑,而将日常工作留给技能较低的开发人员。 复杂的业务逻辑 - CQRS 迫使您避免混合领域逻辑和基础设施操作。 可扩展性很重要 - 借助 CQRS,您可以获得出色的读写性能,命令处理可以在多个节点上横向扩展,并且由于查询是只读操作,因此可以对其进行优化以执行快速读取操作。李>

【讨论】:

在考虑 CQRS 时,我不太确定是否会有一个分布式团队。 任何分层/多层应用程序都可以分解为很好的隔离任务。 难以理解或复杂?你应该更清楚地区分这些批评者。 IMO 它在许多方面简化了你的生活,是的,这不是你在学校学到的东西,所以需要做一些额外的努力来理解它。【参考方案2】:

CQRS 不是包含整个应用程序的模式。

这是一个建立在领域驱动设计 (DDD) 之上的概念。而DDD的一个重要战略概念就是所谓的Bounded Context

在一个典型的应用程序中,有多个有界上下文,其中任何一个都可以按照有意义的方式实现。比如

用户管理 -> CRUD 发票 -> CRUD 保险单管理(核心域)-> CQRS ...

这可能无法回答您的问题,但它可能会更深入地了解该主题。老实说,如果不考虑项目的具体情况,我认为根本无法回答这个问题,即便如此,也很少有像明确的最佳实践这样的东西。

【讨论】:

不同意 CQRS 不是一种模式的说法,一旦你决定使用它,通常会涵盖整个应用程序。 CQRS 是一种架构模式,而不是***架构。因此,您必须评估是否将其应用于每个特定的有界上下文。请参阅cqrsjourney.github.com 并阅读第 2 参考章节。 @GrigoriMelnik 也许我回答的第一句话没有明确表述(我也不是母语人士)。据我所知,我说的和你一样。 CQRS 应该在有界上下文的基础上应用,而不是在整个应用程序中应用。 @DennisTraub 实际上,我认为您的句子表述正确,是 Grigori Melnik 错误地解释了它。 虽然很难定义这样的术语,但我不确定它在 DDD 上构建的部分来自哪里?对我来说,它们根本没有联系在一起 “保险政策管理(核心领域)-> CQRS”没有任何例子,并没有真正多说......【参考方案3】:

当您拥有复杂或困难的业务领域并且:

带有事件溯源;你想要一种测试逻辑的好方法 带有事件溯源;你想通过测试和推理来证明你的行为 您的域服务有多个客户端或消费者(不仅仅是单个 Web 服务器)

或者您有需要对公共数据采取行动的用户:

并且您希望将您领域的数据合并概念形式化 或者您想应用逻辑来合并事件

或者您有可扩展性要求:

您将该模式应用为消除瓶颈的非规范化模式 您想要水平而不是垂直缩放

或者您有性能问题(可扩展性的另一面):

例如您需要将架构迁移到事件驱动的架构 - CQRS 作为一种模式是一个很好的垫脚石。

或者你有一个物理分离的团队:

例如您的部分团队成员在另一个国家/地区 或者很难进行面对面的交流,因此您希望将读取模型与事物的写入端(sagas、域、CRUD)分离

不是 CQRS 过于复杂,而是计算机。

【讨论】:

查看@MairbekKhadikov 回答的评论【参考方案4】:

何时使用 CQRS 设计模式?

当难以从存储库中查询用户需要查看的所有数据时,可以使用 CQRS 架构模式。当 UX 设计创建跨越多个聚合类型和实例的数据视图时尤其如此。您的域越复杂,这就越容易发生。

当不适合在 UX 设计上妥协时,使用 CQRS 会尝试缓解与其他解决方案相关的问题,例如:

要求客户端使用多个存储库来检索所有聚合实例;或 在各种存储库上设计专门的查找器,以使用单个查询收集不连贯的数据。

总结:当难以从用户需要查看的存储库中查询数据时使用 CQRS,这往往会发生在您的域越复杂。

【讨论】:

你不一定需要CQRS,如果数据难以查询,物化视图通常就足够了。 @matino 具体化视图要求数据存储在同一个数据库中。在 CQRS 通常与事件溯源配对的微服务架构中,情况通常并非如此。【参考方案5】:

以下是使用 CQRS 的原因:

    可扩展性(读取超过写入,因此每个的扩展要求不同,可以更好地解决) 灵活性(单独的读/写模型) 降低复杂性(将复杂性转移到单独的关注点) 专注于领域/业务 有助于设计基于任务的直观 UI

【讨论】:

【参考方案6】:

在实际场景中,当您的前端/Web 服务客户端需要来自多个域的大量数据并且从数据库中检索这些数据需要很长时间时,CQRS 可能会很有用。

在这种情况下,您可能会考虑创建单独的读取模型,这将更快地开发并且可能具有更快的执行时间。

【讨论】:

【参考方案7】:

关于实现 CQRS,当您的前端/Web 服务客户端需要来自多个域的大量数据时,我喜欢分离读取模型的想法,我想尝试一下。我想尝试它的主要原因是开发和执行过程中的“缓慢”问题;特别是在处理大型数据集或“大数据”时。我正在研究可用于降低复杂性、增加混合架构的可扩展性、弹性和灵活性的所有各种选项。

【讨论】:

【参考方案8】:

如果您发现问题域不适合更通用的架构,或者您正在尝试域驱动设计,我建议您尝试 CQRS。

这是一种强大的模式,可以让您更好地了解问题领域并解决一些技术和基础设施挑战。但值得牢记的是,它会带来价格,并且由于与其他架构的概念差异,它需要心智模型的转变。

CQRS: Intro

【讨论】:

【参考方案9】:

在以下情况下使用它:

    领域复杂,需要通过命令理解领域 读取和写入的应用程序负载不同 希望在任何时间点扩展读取操作

https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs#when-to-use-this-pattern

【讨论】:

【参考方案10】:

以下是CQRS Pattern 非常适合的一些场景:

需要高性能且独立的大型项目 需要可扩展性。 在业务逻辑复杂的应用程序中。在这种情况下, 您可以将读取与写入分开,以使其更简单。 如果您想要一个团队可以进行并行开发的读取 模型和其他团队致力于编写模型。

阅读此Article 以了解有关CQRS Pattern 的更多信息。

【讨论】:

【参考方案11】:

好吧,您的问题没有直接的答案,但我想给您一些如何实现 CRQS 的真实示例,这可以帮助您弄清楚如何使用它在您的应用程序中,

1. Instagram

我们经常看到 Instagram 故事/卷轴等。这些商店是阅读密集型的,最好为此类数据建立一个单独的只读数据库。外部世界只能处理那个特定的数据库来渲染你朋友时间线中的故事,这样系统就不需要打扰存储主要业务密集型信息的主数据库。

2。亚马逊

下订单时,订单服务会发出一个事件,该事件被其他服务订阅,其中一个可以更新非规范化的只读数据库,而其他服务(比如说消息传递服务)可以简单地获取规范化信息比如来自只读数据库的 userId、ordered 等,并继续进行电子邮件处理以确认订单

【讨论】:

以上是关于何时使用 CQRS 设计模式?的主要内容,如果未能解决你的问题,请参考以下文章

浅谈CQRS

从横切到纵切,架构模式CQRS,提高系统进化能力

详解从横切到纵切,架构模式CQRS,提高系统进化能力

DDD领域驱动设计:CQRS架构模式

命令查询职责分离模式CQRS

通过Java学习与演示CQRS与事件溯源模式