CQRS解决了哪些持久性问题?

时间:2017-06-27 23:46:25

标签: domain-driven-design cqrs read-write

我已经阅读了一些与此相关的帖子,但我仍然无法理解它是如何运作的。

让我们说例如我正在构建一个类似Stack Overflow的网站,其中有两个页面=>一个列出所有问题,另一个列出你提问/编辑问题。一个简单的基于CRUD的Web应用程序。

如果我使用CQRS,我会有一个单独的系统用于读/写,单独的DB等等。

现在,我的问题是如何更新读取状态(毕竟是在它自己的数据库中)。

我假设的流程是这样的:

WebApp => User submits question WebApp => System raises 'Write' event WriteSystem => 'Write' event is picked up and saves to 'WriteDb' WriteSystem => 'UpdateState' event raised ReadSystem => 'UpdateState' event is picked up ReadSystem => System updates it's own state ('ReadDb') WebApp => Index page reads data from 'Read' system

假设这是正确的,那么从同一个DB读取/写入的CRUD系统有何不同?抛开CQRS的优势,例如单独的读/写系统扩展,重建状态,域边界分离等,从持久性角度来看已解决的问题?避免锁争用?

通过使用队列在多线程Web应用程序中实现单线程保存,或者只是在读/写DB之间复制数据,我可以获得类似的优势,不是吗?

基本上,我只是试图了解我是否正在构建基于CRUD的Web应用程序,为什么我会从务实的角度关注CQRS。

谢谢!

3 个答案:

答案 0 :(得分:3)

  

假设这是正确的,那么从同一个DB读取/写入的CRUD系统有何不同?抛开CQRS的优势,如单独的读/写系统扩展,重建状态,域边界分离等,从持久性角度解决了哪些问题?避免锁争用?

这里的问题是:

  

"放弃CQRS的优势......"

如果你剥夺了它的优势,那么它有点难以说明它解决了什么问题; - )

理解CQRS的关键是将读取数据与写入数据分开。这样您就可以根据需要优化数据库:您的写入数据库高度标准化,因此您可以轻松确保一致性。相反,您的读取数据库是非规范化的,这使得您的读取非常简单和快速:它们都有效地成为SELECT * FROM …

假设作为StackOverflow的网站比写入更容易读取,这很有意义,因为它允许您优化系统以获得快速响应和出色的用户体验,同时不会牺牲一致性时间。

此外,如果与事件采购相结合,这种方法还有其他好处,但仅对CQRS来说就是这样。

无耻插件:我和我的团队已经全面介绍了CQRS,DDD和事件采购,也许这有助于提高理解力。有关详细信息,请参阅this website

答案 1 :(得分:2)

一个好的起点是审查Greg Young's 2010 essay,他试图澄清CQRS模式的有限范围。

  

CQRS只是创造了两个对象,其中只有一个......这种分离使我们能够在建筑上做很多有趣的事情,最大的是它会强制打破精神发育迟滞,因为两者使用相同的数据也应该使用相同的数据模型。

多数据模型的概念是关键,因为您现在可以开始考虑使用适合目的的数据模型,而不是尝试将单个数据模型调整为您需要支持的每种情况。

一旦我们认为这两个对象在逻辑上是分开的,我们就可以开始考虑它们是否在物理上是分开的。这开辟了一个有趣的权衡世界。

  

从持久性角度解决了哪些问题?

选择适合存储的机会。您不必在单个读/写持久性存储中支持所有用例,而是从密钥值存储中提取文档,从图形数据库中运行图形查询,并从文档存储中搜索全文,从事件流......

或不!如果成本效益分析告诉您工作无法获得回报,您可以选择从单个商店提供所有案例。

答案 2 :(得分:0)

这取决于您的应用需求。

这里有一个很好的概述和更多资源的链接:https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs

何时使用此模式:

在以下情况下使用此模式:

  

在同一数据上并行执行多个操作的协作域。 CQRS允许您使用定义命令   足够的粒度以最小化域级别的合并冲突   (任何确实发生的冲突都可以通过命令合并),即使是   更新看似相同类型的数据。

     

基于任务的用户界面,用户通过一系列步骤或复杂的域模型引导复杂流程。   此外,对于已经熟悉域驱动设计的团队非常有用   (DDD)技术。写模型具有完整的命令处理堆栈   具有业务逻辑,输入验证和业务验证   确保每个聚合的所有内容始终一致   (每个关联对象簇作为数据单元处理   写模型中的变化)。读取模型没有业务逻辑或   验证堆栈,只返回一个DTO,用于视图模型。该   read模型最终与写模型一致。

     

必须根据数据写入的性能分别微调数据读取性能的情况,尤其是在数据写入时   读/写比率非常高,并且在水平缩放时   需要。例如,在许多系统中读取操作的次数   写入操作的数量是许多倍。至   考虑到这一点,考虑缩小读取模型,但运行   仅在一个或几个实例上编写模型。少量写   模型实例还有助于最小化合并的发生   冲突。

     

一个开发团队可以专注于作为写模型一部分的复杂域模型的场景,另一个团队可以   专注于阅读模型和用户界面。

     

预计系统会随着时间的推移而发展并且可能包含模型的多个版本或业务规则的场景   经常变化。

     

与其他系统集成,特别是与事件源相结合,其中一个子系统的时间故障不应该是   影响其他人的可用性。

在以下情况下不推荐使用此模式:

  

域名或业务规则很简单。

     

简单的CRUD风格的用户界面和相关的数据访问操作就足够了。

     

用于整个系统的实施。 CQRS可以是整体数据管理场景的特定组件   有用,但它可以增加相当多和不必要的复杂性   不是必需的。