CQRS 架构优化和变体

CQRS architecture optimizations and variations

命令查询责任分离/事件溯源架构非常适合我正在启动的项目,该项目每年将处理大约 10 亿笔与人们的健康保险相关的金融交易。主要好处是审计历史记录、可扩展性、在多个团队之间实施异步兼容 UI、将这些事务从读取数据库中分离出来、通过事件队列简化状态到间歇性连接的现场办公室的传输,以及应对在整个系统生命周期内发生重大业务逻辑变化。

然而,有些地方 CQRS/ES 会出现问题,例如为 1 亿人分配一个数字 ID,最终一致性不可接受的用户安全。系统中还有一些区域本质上是 CRUD,无法从 CQRS/ES 中受益。最后,我们将在不同的团队和公司拥有大量的开发人员,并且拥有不需要 CQRS/ES 能力的领域会很好。是否可以采用混合方法,其中某些区域不是事件源?我们可以只同步读写端的相关表吗?

CQRS 架构的聚合实体是否简化了快照缓存失效?任何更新可能被缓存的聚合实体的事件都可以被无效器侦听,并且给定聚合实体比关系实体更粗粒度,我们可以区分写入事件这个问题是否可以解决?

我预计每年会发生大约 10 亿次事件,并且需要跟踪大约 4 年的历史。我们可以快照并存档旧事件吗?

是否有的事件溯源?例如,一个在线商店系统 AddLineItem 事件可能包括每单位订单项价格,但依赖读取端提取并在发票上呈现产品名称。另一个在线商店可能会在事件数据中包含该名称。您如何选择活动中包含的内容?在健康保险中,它可能会限制 'what if' 分析的内容 运行 - 如果我们没有包括被保险人的年龄,我们就不能切实可行地模拟需要它的保单吗?

是否有一种有趣的方式来为关于事件的事件建模?例如,管理员在系统中输入产品价格将在未来某个日期发生变化。我想快照将是价格时间表。我们能否改为添加日期为 post 的 ProductPriceChanged 事件?我们可以在 运行ning 'what if' 场景中伪造此类事件吗? (此类聚合必须很少更改,以避免版本号和并发检测问题。)

CQRS/ES 通常声称可以使系统更容易适应未来业务流程的变化。我理解以下论点:以通用语言列出事件的命令使讨论和重新配置它们变得更加容易,而事件溯源消除了 RDBMS 模型的一些僵化。但是 事件中的任何更改不会中断事件的重播吗?随着系统不断变化,您最终不会遇到许多版本化的事件吗?例如,在一家在线商店中,通过更改标准来评估客户是否是金卡持有人?你能拍下一切吗?您如何 post 确定这些变化的日期?同样,您是否必须小心依赖项注入,none 项注入的依赖项会影响业务逻辑,否则会中断重放?

知道为什么它与 .NET 世界相关联,而在行业的其他领域却不太受欢迎吗?

非常感谢即使只是阅读也非常感谢。

Is it possible to employ a hybrid approach, where some areas are not event sourced?

当然可以。

Could we just synchronize the relevant tables on both read and write sides?

在很多情况下这听起来像是个坏主意。

Do CQRS-architected aggregate entities simplify snapshot cache invalidation?

不多?有一个事件表明记录簿已发生写入,可用于使缓存无效,这并不是一个特别的 CQRS 想法。它并没有更简单——只是额外的工作无论如何都在范围内。

Can we snapshot and archive older events?

是的,但是......通常更容易考虑一个长期存在的实体被分解成较短情节的历史,并将状态从一个情节滚动到下一个情节 - 例如,考虑滚动财务期末的分类帐。然后,您将生命周期结束的任何聚合的历史记录存档。

How do you choose what to include in the event?

查看此聚合所需的状态以 establish/maintain/restore 业务不变。其他一切都可以洗掉。这通常意味着报告(读取模型)是从多个聚合中组装而成的,也可能是文档。

Is there an interesting way to model events about events?

关于事件的事件是混乱的。关于 进程 的事件很棒。

Could we instead add a post-dated ProductPriceChanged event?

拼写错误 -- 试试 PriceChangeScheduled。注意:建模时间很重要;领域模型不应该注意到时间的流逝,除非外界提到它。

But won't any changes within an event will break the replay of events?

不,但是您需要遵守有关事件表示的纪律以确保如此。 Greg Young 将 Versioning in an Event Sourced System 写作 e-book。

快速而肮脏的 -- 模式中的字段是可选的;您可以添加或删除它们,但您永远不会改变它们的含义。消费者为他们想要阅读的任何内容提供默认值,并为他们不理解的 "must ignore" 个条目提供默认值。

With systems subject to change won't you end up with many versioned events? Eg, in an online store assessing whether a client is a Gold Card Holder by changing criteria?

我不清楚这是哪个问题。一个事件可能有多种表示形式(取决于预期的模式和考虑的默认值),但它仍然只是一个事件。系统做出的决定由事件记录,因此随着时间的推移版本控制并没有真正进入它。

Similarly do you have to be careful with dependency injection that none of the dependencies injected can affect business logic, as otherwise you break replay?

业务逻辑都在领域模型中,领域模型在洋葱的中心;脱离现实世界。所以你不应该注入任何在现实世界中引入副作用的依赖项。这些通常是异步处理的(我们成功保存了这些事件,因此可以安排副作用)。

Any idea why it is associated with the .NET world, with less popularity in other areas of the industry?

人们。 Udi Dahan 和 Greg Young 都有 .NET 背景。 PHP 也很受欢迎,因为 Mathias Verraes 有这样的背景。

how would you suggest I persist non-ES aggregate entities?

文档存储?数据库管理系统?平面文件?多语言持久性很好。

I might miss how this answers this question - if the business invariant is an order line item, does this include product name or just price?

产品编号和数量可能就足够了。也许是报价单,如果您从事的业务报价可能与目录中列出的不同。

I mean if an aggregate's business logic changes but past events still need processing the old way.

一个关键的想法是事件的意义不应该改变;他们描述了状态的变化。因此,如果您发现 "new version of an event" 的含义有所不同,那么您确实遇到了一个新事件。参见 Young 的书。

聚合业务逻辑——决定如何从一种状态发展到另一种状态;那确实改变了。但它不会改变给定聚合实际处于的状态。

例如,您可能发现某些状态不应该到达。这是业务逻辑——聚合不应写入新事件以结束该状态。这不会以任何方式影响当前处于无法访问状态的聚合;他们仍然在那里,因为那是历史把他们放在那里的地方。你可以通过给他们更多的事件来让他们脱离那个状态。