21

我们目前正在评估 CQRS 和事件溯源架构。我试图了解使用这种设计的维护含义是什么。我正在努力寻找答案的两个问题是:

1) 如果在应用程序启动并运行了一段时间后,需要向 ReadModel 数据库上的 ViewModel 添加额外字段,会发生什么情况?比如说,在 CustomerList ViewModel 上需要客户邮政编码,而以前不需要。因此,可以轻松地将额外的列添加到 ViewModel 数据库中,但是如何填充呢?据我所知,唯一的方法是清除读取数据库,并从头开始重播所有事件以备份 ReadModel 数据库。但是,如果应用程序已经启动并运行了数月或数年(正如我们希望的那样)怎么办。这可能是要重播的数百万个事件,只是为邮政编码列添加数据。

如果出于某种技术原因,ReadModel 数据库不同步,或者我们想要添加一个新的 ReadModel 数据库,我也有同样的担忧。似乎应用程序越旧,使用得越多,获得最新的 readmodel 就越困难和昂贵。还是我在某个地方错过了一个技巧?ReadModel 快照之类的东西?

2) 如果在重播所有数百万个事件以备份读取数据库之后,一些数据与预期不符(即看起来错误),会发生什么情况。人们认为,可能是事件存储中的某个错误或非规范化例程可能导致了这种情况(似乎如果在编码中可以依赖一件事,那就是错误)。如何去调试这个!这似乎是一项不可能完成的任务。或者,也许,我又错过了一个窍门。

我很想听听任何已经运行这样的系统一段时间的人的意见,维护和升级路径是如何为您解决的。

感谢您的任何时间和投入。

4

4 回答 4

15

如前所述,将事件溯源与 CQRS 一起使用的美妙之处在于能够破坏读取模型并从头开始重建它。出于某种原因,人们有这样的想法,即在您超过任意数量的事件之后需要很长时间。如果您为读取模型使用关系数据库——而且很可能是——打开事务很容易,通过处理程序读取所有事件,然后提交事务。只有当事务提交时,我们才真正接触到磁盘。其他所有操作都在内存中执行,因此速度快如闪电。事实上,如果您的系统在短短几分钟内完成数百万个事件,我不会感到惊讶。

从头开始重建您的读取模型应该与您将事件非规范化为读取模型的日常方法完全相同。如果没有,您的读取模型非规范化代码中存在错误。这里的好处是,从您的消息处理程序的角度来看,在常规/生产场景和读取模型重建场景中接收和非规范化到读取模型中的事件没有区别。

如果您确实遇到错误,您可以通过将生产事件流式传输/复制到本地工作站,在处理程序中设置断点,然后通过读取模型处理代码运行这些事件来轻松调试。

于 2011-04-07T20:55:30.373 回答
2

我对 CQRS 有点陌生,所以这可能不是最可取的路线(但 iirc 我从 CQRS/DDDD 邮件列表之一中选择了它)。

我们创建一个命令和相应的处理程序,该处理程序特定于预期运行一次然后弃用的目的。

在处理程序中,我们使用任何方便的机制,因此在您添加邮政编码字段的情况下,我们可能会运行一次性查询,从另一个视图模型中提取当时的邮政编码并填充新列。我们不太担心这些场景中的架构纯度,因为它预计是一次性操作(Rob Conery 的 Massive已在这些情况下成功使用)。

于 2011-04-07T19:18:26.693 回答
1

我还没有使用带有事件源的 cqrs 的生产就绪应用程序,所以这只是我尝试构建一个的经验。

1) Read Model rebuild。是的,一旦其中的某些内容发生变化,您基本上必须重建整个读取模型数据库。如果有很多事件,这可能需要很长时间。所以读取模型重建必须高度优化(使用事件批处理等)。我觉得事件溯源最适合读写比率高的情况。因此,对于一些极易波动的数据,最好不要将其存储为域事件。但是关于存储容量的问题也不是那么遥远。在任何情况下,您都可以将 cqrs 应用于系统的一部分,即最适合的部分(例如,我可能不会将图形图像存储为事件的一部分)。

2) Debugging。事件存储中出现错误的可能性很小(这应该是框架的关注点),并且总是很容易检查存储中的事件。至于产生预期事件的命令,这里应该有测试,这些测试可能是系统中最有价值的测试。对于非规范化器,您也可以进行测试,但如果可以用肉眼看到它们的正确性,我就不会为琐碎的非规范化器编写测试。话虽如此,我使用调试器几次来发现一些更复杂的非规范化器中的问题;试图确定是哪个事件使事情出错并没有那么有趣。

于 2011-04-07T20:03:09.180 回答
0

也可以在模型中添加净额事件。这可以在收到 X 个事件后作为任意任务运行(比如 500 个)

To rebuild, you push your events onto a stack till you hit the netting event, this gets used as the baseline, from here you pop the events off your stack aggregating their values with your baseline event.

于 2011-04-14T23:26:32.530 回答