CQRS、事件溯源和Web应用程序

4
当我阅读一些CQRS资源时,有一个经常出现的问题我不太明白。例如,假设客户端发出一个命令。该命令被领域接受,因此可以更新其领域模型(DM)。另一方面,该命令被持久化在事件存储中。这是最常见的情况。
1) 当我们说DM被更新后,我想数据应该被持久化在底层数据库中(如果有的话)。我是对的吗?否则,我们将处理一个内存瞬态模型,我想这不是一个好事情?(状态不应该在服务器端保留在客户端请求之外)。
2) 如果数据被持久化,我想依赖它的读模型会自动更新,因为每个请求它的客户端都会在应用程序中生成一个新的“状态/上下文”(在Web应用程序或RESTful架构的情况下)?
3) 如果命令被持久化,是否意味着我们正在处理事件溯源(当使用CQRS时构造)?事件溯源是否使数据库更新流程失效?(因为如果状态从事件存储重建,保持数据库似乎没有用处)?
CQRS只适用于多数据库系统(当数据在不同的数据库中传播时),如果处理内存瞬态模型,那是否能很好地适用于Web应用程序或RESTful服务?

2
我建议你进一步了解CQRS和事件溯源、命令和事件,因为它们是完全不同的东西。你的问题混淆了它们,并在此基础上加入了持久化,使得问题更加模糊不清。在DDD、CQRS和事件溯源中,持久化只是一个实现细节,你应该首先将这些技术视为所有事情都发生在内存中。 - guillaume31
1
谢谢,我问题的另一个要点是:您是否使用ASP.NET应用程序体验过CQRS?由于在ASP.NET应用程序之间无法维护上下文,它们是否很好地配合使用? - Rénald
我不是想在生产环境中这样做 ;)只是试图理解CQRS或ES的基本原则,而不考虑将其持久化到磁盘。如果您想原型化它,在ASP.NET中您可以使用静态变量--它们会持续存在于应用程序域的生命周期内。再次说明,我不建议在实际应用程序中使用它(内存易失性,应用程序域可以在更多或更少有记录的情况下重新启动)。 - guillaume31
感谢您的反馈,Guillaume... :-) - Rénald
3个回答

4

1) 如前所述,真正存储的只有事件。命令执行的唯一作用是在触发事件之前进行一致性检查。伪代码如下:

public void BorrowBook(BorrowableBook dto){
    if (dto is valid)
        RaiseEvent(new BookBorrowedEvent(dto))
    else
        throw exception
}

public void Apply(BookBorrowedEvent evt) {
    this.aProperty = evt.aProperty;
    ...
}

当前状态是通过顺序的应用来检索的。因此,在设计阶段,您必须非常注意,因为有常见的陷阱需要避免(也许您已经阅读过了,但我建议您阅读Martin Fowler的这篇文章)。

到目前为止,这只是事件溯源。如果您决定使用不同的数据库来持久化聚合的状态,则需要使用CQRS。 在我的项目中,我们有一个投影,每隔x分钟将新事件(来自事件存储)应用于聚合并将结果保存在MongoDB的单独实例中(演示层将访问此数据库以进行读取)。此模型显然是最终一致的,但以这种方式确实将Command(写入)与Query(读取)分开。

2)如果您决定将写模型从读模型中分离出来,则有各种选项可用于使它们同步:

  • 每个x秒钟应用从上一个检查点开始的事件(某些解决方案提供快照以避免重新应用重命令)
  • 订阅事件并在事件被引发时立即更新读模型的投影

3)存储的唯一内容是事件。实际上,我们有一个事件存储,而不是命令存储 :)

数据库是否无用?取决于!您需要重新应用多少个事件才能将聚合带到当前状态? 三个?也许您不需要为读模型拥有数据库。


3
重点在于,唯一存储的是事件*。领域模型是从事件中重建的。
所以,是的,领域模型在内存中是短暂的,因为没有存储领域模型的表示方式*,只有发生在领域中的事件,将模型置于当前状态。
当加载领域模型中的元素时,会创建该元素的新实例,然后按正确顺序逐个重放影响该实例的事件,以将元素置于正确状态。
您可以保留领域对象的实例,并订阅新事件,以便在不每次从所有事件中加载它们的情况下使其保持最新状态。但通常,只需从数据库加载所有事件并每次应用它们即可快速完成,就像您可能会在每次调用Web服务时从数据库加载实例一样。
*除非您拥有领域对象的快照来减少需要加载/处理的事件数量

2

数据的持久性并不是必须的。在足够多的不同位置(GigaSpaces)有足够多的副本可能已经足够了。因此,不需要数据库。荷兰的eBay等价物至少在几年前就在生产中使用了这种方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接