CQRS 解决了哪些持久性问题?
What persistence problems are solved with CQRS?
我已经阅读了一些与此相关的帖子,但我仍然不太明白它是如何工作的。
举例来说,我正在构建一个像 Stack Overflow 这样的网站,有两个页面 => 一个列出所有问题,另一个是你 ask/edit 一个问题。一个简单的、基于 CRUD 的 Web 应用程序。
如果我使用 CQRS,我会为 read/writes、单独的数据库等提供一个单独的系统。太棒了。
现在,我的问题是如何更新 read 状态(毕竟是在它自己的数据库中)。
我假设的流程是这样的:
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
假设这是正确的,这与来自同一数据库的 CRUD 系统 read/writing 有何显着不同?撇开 CQRS 的优势,如单独 read/write 系统 缩放、重建状态、域边界分离等, 解决了 坚持立场?避免了锁争用?
我可以通过使用队列在多线程 Web 应用程序中实现单线程保存,或者简单地在 read/write 数据库之间复制数据来实现类似的优势,不是吗?
基本上,我只是想了解如果我正在构建一个基于 CRUD 的 Web 应用程序,为什么我会从务实的角度关心 CQRS。
谢谢!
这取决于您的应用需求。
这里有一个很好的概述和指向更多资源的链接:https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs
何时使用此模式:
在以下情况下使用此模式:
Collaborative domains where multiple operations are performed in parallel on the same data. CQRS allows you to define commands with
enough granularity to minimize merge conflicts at the domain level
(any conflicts that do arise can be merged by the command), even when
updating what appears to be the same type of data.
Task-based user interfaces where users are guided through a complex process as a series of steps or with complex domain models.
Also, useful for teams already familiar with domain-driven design
(DDD) techniques. The write model has a full command-processing stack
with business logic, input validation, and business validation to
ensure that everything is always consistent for each of the aggregates
(each cluster of associated objects treated as a unit for data
changes) in the write model. The read model has no business logic or
validation stack and just returns a DTO for use in a view model. The
read model is eventually consistent with the write model.
Scenarios where performance of data reads must be fine tuned separately from performance of data writes, especially when the
read/write ratio is very high, and when horizontal scaling is
required. For example, in many systems the number of read operations
is many times greater that the number of write operations. To
accommodate this, consider scaling out the read model, but running the
write model on only one or a few instances. A small number of write
model instances also helps to minimize the occurrence of merge
conflicts.
Scenarios where one team of developers can focus on the complex domain model that is part of the write model, and another team can
focus on the read model and the user interfaces.
Scenarios where the system is expected to evolve over time and might contain multiple versions of the model, or where business rules
change regularly.
Integration with other systems, especially in combination with event sourcing, where the temporal failure of one subsystem shouldn't
affect the availability of the others.
在以下情况下不推荐使用此模式:
Where the domain or the business rules are simple.
Where a simple CRUD-style user interface and the related data access operations are sufficient.
For implementation across the whole system. There are specific components of an overall data management scenario where CQRS can be
useful, but it can add considerable and unnecessary complexity when it
isn't required.
一个好的起点是回顾 Greg Young's 2010 essay,他在其中试图阐明 CQRS 模式的有限范围。
CQRS is simply the creation of two objects where there was previously only one.... This separation however enables us to do many interesting things architecturally, the largest is that it forces a break of the mental retardation that because the two use the same data they should also use the same data model.
多个数据模型的想法是关键,因为您现在可以开始考虑使用适合目的的数据模型,而不是尝试针对您需要支持的每种情况调整单个数据模型。
一旦我们认为这两个对象在逻辑上是分开的,我们就可以开始考虑它们在物理上是否分开了。这开启了一个有趣的权衡世界。
what problems are solved from a persistence standpoint?
有机会选择适合用途的存储。您不是在单个 read/write 持久性存储中支持所有用例,而是从键值存储中提取文档,从图形数据库中提取 运行 图形查询,并从数据库中提取全文搜索文档存储,事件流中的事件....
还是不行!如果成本效益分析告诉您这项工作不会得到回报,您可以选择从一家商店为您的所有案例提供服务。
Assuming this is correct, how is this significantly different to a CRUD system read/writing from same DB? Putting aside CQRS advantages like seperate read/write system scaling, rebuilding state, seperation of domain boundaries etc, what problems are solved from a persistence standpoint? Lock contention avoided?
这里的问题是:
"Putting aside CQRS advantages …"
如果你拿掉它的优点,就很难争论它解决了什么问题;-)
理解 CQRS 的关键是将读取数据与写入数据分开。这样您就可以根据需要优化数据库:您的写入数据库是高度规范化的,因此您可以轻松确保一致性。相比之下,您的读取数据库是非规范化的,这使您的读取非常简单和快速:它们都有效地变为 SELECT * FROM …
。
假设像 Whosebug 这样的网站的读取次数多于写入次数,这很有意义,因为它允许您优化系统以实现快速响应和良好的用户体验,而不会牺牲一致性同时。
此外,如果与事件溯源相结合,这种方法还有其他好处,但仅对于 CQRS 而言,仅此而已。
无耻插件:我和我的团队创建了对 CQRS、DDD 和事件溯源的全面介绍,也许这也有助于提高理解。有关详细信息,请参阅 this website。
我已经阅读了一些与此相关的帖子,但我仍然不太明白它是如何工作的。
举例来说,我正在构建一个像 Stack Overflow 这样的网站,有两个页面 => 一个列出所有问题,另一个是你 ask/edit 一个问题。一个简单的、基于 CRUD 的 Web 应用程序。
如果我使用 CQRS,我会为 read/writes、单独的数据库等提供一个单独的系统。太棒了。
现在,我的问题是如何更新 read 状态(毕竟是在它自己的数据库中)。
我假设的流程是这样的:
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
假设这是正确的,这与来自同一数据库的 CRUD 系统 read/writing 有何显着不同?撇开 CQRS 的优势,如单独 read/write 系统 缩放、重建状态、域边界分离等, 解决了 坚持立场?避免了锁争用?
我可以通过使用队列在多线程 Web 应用程序中实现单线程保存,或者简单地在 read/write 数据库之间复制数据来实现类似的优势,不是吗?
基本上,我只是想了解如果我正在构建一个基于 CRUD 的 Web 应用程序,为什么我会从务实的角度关心 CQRS。
谢谢!
这取决于您的应用需求。
这里有一个很好的概述和指向更多资源的链接:https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs
何时使用此模式:
在以下情况下使用此模式:
Collaborative domains where multiple operations are performed in parallel on the same data. CQRS allows you to define commands with enough granularity to minimize merge conflicts at the domain level (any conflicts that do arise can be merged by the command), even when updating what appears to be the same type of data.
Task-based user interfaces where users are guided through a complex process as a series of steps or with complex domain models. Also, useful for teams already familiar with domain-driven design (DDD) techniques. The write model has a full command-processing stack with business logic, input validation, and business validation to ensure that everything is always consistent for each of the aggregates (each cluster of associated objects treated as a unit for data changes) in the write model. The read model has no business logic or validation stack and just returns a DTO for use in a view model. The read model is eventually consistent with the write model.
Scenarios where performance of data reads must be fine tuned separately from performance of data writes, especially when the read/write ratio is very high, and when horizontal scaling is required. For example, in many systems the number of read operations is many times greater that the number of write operations. To accommodate this, consider scaling out the read model, but running the write model on only one or a few instances. A small number of write model instances also helps to minimize the occurrence of merge conflicts.
Scenarios where one team of developers can focus on the complex domain model that is part of the write model, and another team can focus on the read model and the user interfaces.
Scenarios where the system is expected to evolve over time and might contain multiple versions of the model, or where business rules change regularly.
Integration with other systems, especially in combination with event sourcing, where the temporal failure of one subsystem shouldn't affect the availability of the others.
在以下情况下不推荐使用此模式:
Where the domain or the business rules are simple.
Where a simple CRUD-style user interface and the related data access operations are sufficient.
For implementation across the whole system. There are specific components of an overall data management scenario where CQRS can be useful, but it can add considerable and unnecessary complexity when it isn't required.
一个好的起点是回顾 Greg Young's 2010 essay,他在其中试图阐明 CQRS 模式的有限范围。
CQRS is simply the creation of two objects where there was previously only one.... This separation however enables us to do many interesting things architecturally, the largest is that it forces a break of the mental retardation that because the two use the same data they should also use the same data model.
多个数据模型的想法是关键,因为您现在可以开始考虑使用适合目的的数据模型,而不是尝试针对您需要支持的每种情况调整单个数据模型。
一旦我们认为这两个对象在逻辑上是分开的,我们就可以开始考虑它们在物理上是否分开了。这开启了一个有趣的权衡世界。
what problems are solved from a persistence standpoint?
有机会选择适合用途的存储。您不是在单个 read/write 持久性存储中支持所有用例,而是从键值存储中提取文档,从图形数据库中提取 运行 图形查询,并从数据库中提取全文搜索文档存储,事件流中的事件....
还是不行!如果成本效益分析告诉您这项工作不会得到回报,您可以选择从一家商店为您的所有案例提供服务。
Assuming this is correct, how is this significantly different to a CRUD system read/writing from same DB? Putting aside CQRS advantages like seperate read/write system scaling, rebuilding state, seperation of domain boundaries etc, what problems are solved from a persistence standpoint? Lock contention avoided?
这里的问题是:
"Putting aside CQRS advantages …"
如果你拿掉它的优点,就很难争论它解决了什么问题;-)
理解 CQRS 的关键是将读取数据与写入数据分开。这样您就可以根据需要优化数据库:您的写入数据库是高度规范化的,因此您可以轻松确保一致性。相比之下,您的读取数据库是非规范化的,这使您的读取非常简单和快速:它们都有效地变为 SELECT * FROM …
。
假设像 Whosebug 这样的网站的读取次数多于写入次数,这很有意义,因为它允许您优化系统以实现快速响应和良好的用户体验,而不会牺牲一致性同时。
此外,如果与事件溯源相结合,这种方法还有其他好处,但仅对于 CQRS 而言,仅此而已。
无耻插件:我和我的团队创建了对 CQRS、DDD 和事件溯源的全面介绍,也许这也有助于提高理解。有关详细信息,请参阅 this website。