CQRS:更新读模型而不使用事件溯源

6
我们使用了基于CQRS的系统,域部分采用关系型数据库,读取部分采用NoSQL数据库,域部分采用传统的关系性方法,而读取部分则是非规范化的。数据复制和转换是通过命令处理器所发出的事件来完成的。
我有两个关于读取端同步的问题:
1.怎样使用域部分的关系数据完全重建读模型是最好的方法?
假设读模型不同步。但即使它总是同步的,我们也可能想要导入一个测试数据库或进行一些批量操作。因此,我们可能希望从一个现有的写模型运行系统,而没有相应的同步的读模型。由于我们不使用事件溯源,因此没有办法重播所有事件。
我目前在考虑一个ReadModelBuilder,它基本上对每个表执行SELECT * FROM,并将每个实体转换为读取端表示。但这会引入冗余。ReadModelBuilder需要知道如何进行转换。因此,事件处理程序也需要知道这一点,它们通常在命令处理程序执行一些写操作后进行读取端同步。
我想过放弃事件处理程序,用每个类级别的同步机制来代替它们。例如,FooRenamedEventHandler不再重命名foo.name,而是调用FooReadModelBuilder来重新编写整个Foo实例。但我认为这种方法有缺点。FooRenamedEventHandler可以更好地处理读模型中foo.name的冗余使用。
更新:另一种方法是让ReadModelBuilder通过将域实例分为事件来创建读取模型实体,当按顺序执行时,事件将构建完整的读取端实体。例如:
Article域实体有一个Name和一个Price。为了构建读取端模型,ReadModelBuilder可以检查域实体并发出ArticleCreatedEvent、ArticleRenamedEvent和ArticlePriceChangedEvent。这样,转换逻辑就会留在事件处理程序中,但仍然可以从某种批量复制机制中调用。
例如,ReadModelBuilders可能如下所示:
interface IReadModelBuilder<TEntity>
{
    //// Returns a sequence of events which replicate the read-model 
    //// when executed by the event handlers.
    Event[] GetReplicationSequence(TEntity instance);
}

更新结束

_

  • 你通常如何检测不同步的读模型?有通用的最佳实践吗?

我猜任何一个严肃软件系统的生产使用都会遇到需要交换或批量转换数据库的情况。这可能是由软件漏洞引起的,也可能是由总线系统中的错误引起的,或者是由操作失败引起的。这可能是因为有人想部署测试数据库,或者因为需要部署旧备份。当然,可以将两个数据库都保留为备份,但是想象一下,如果读取侧备份丢失或损坏了。 - mbnx
我明白。如果你不坚持事件驱动架构(即不使用事件溯源),那么你就不能轻松地重建一个读模型。你的“重建者”必须以某种方式尝试反向工程写模型并制造一些事件,这很奇怪,因为写模型甚至可能不包含所有信息,因为它不需要这样才能完成工作。 - Constantin Galbenu
因此,我的结论是,如果没有事件存储或至少有一个事件日志,则无法重建读模型。如果您有这样的真相来源,那么您可以重建它,甚至可以通过使用某些持久性中所有已处理事件ID的列表来检测不同步的情况。 - Constantin Galbenu
谢谢,那是一个很好的观点。我们可以存储所有事件但仍不依赖事件溯源。然而,在互联网上可以找到CQRS完全正交于事件溯源的说法可能需要一些现实检验。也许在构建学术级别的hello world应用程序时它们是完全正交的。 - mbnx
确实,也许它们只有89%,而不是90度 :) 然而,没有事件溯源的CQRS存在你所面临的这个问题。一个适用于所有情况的100%解决方案并不存在;如果你试图找到一个,最终会使用事件溯源。也许CQRS + 事件日志记录对你有用。 - Constantin Galbenu
显示剩余2条评论
1个回答

1
如果您不持久化事件(即不使用“事件溯源”),那么您就不能轻松地重建“读模型”。您的“重建器”必须以某种方式尝试反向工程写模型并制造一些事件,这很奇怪,因为“写模型”甚至可能不包含所有信息,因为它不需要这样做才能完成其工作。
因此,我的结论是,如果没有“事件存储”或至少有一个“事件日志”,那么您无法重建您的“读模型”。如果您有这样的真相来源,那么您可以重新构建它,甚至可以通过使用某些持久性中所有已处理事件ID列表来检测不同步的情况。

谢谢。我考虑使用事件生成器来反向工程领域的建议。你是对的,事件可能包含领域模型中没有包含的数据。即使可以使用领域数据计算它,也会在事件生成器和命令处理程序之间引入冗余逻辑。此外,数据模式更改的实现复杂性增加,因为每个新属性都意味着扩展事件生成器。似乎只有拥有某种事件日志才是唯一的选择。 - mbnx

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