【问题标题】:CQRS architecture optimizations and variationsCQRS 架构优化和变化
【发布时间】:2017-06-29 07:19:19
【问题描述】:

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

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

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

我预计每年大约有 10 亿个事件,并且需要跟踪大约 4 年的历史。我们可以对旧事件进行快照和存档吗?

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

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

通常声称 CQRS/ES 可以使系统更容易适应未来的业务流程变化。我理解使用通用语言列出事件的命令使得讨论和重新配置它们变得更容易的论点,并且事件溯源消除了 RDBMS 模型的一些僵化。但是,一个事件的任何变化不会破坏事件的重播吗?随着系统的变化,您最终不会有许多版本化的事件吗?例如,在网上商店通过改变标准来评估客户是否是金卡持有者?你能把所有东西都拍下来吗?您将如何发布这些更改的日期?同样,您是否必须小心依赖注入,因为注入的任何依赖都不会影响业务逻辑,否则会破坏重放?

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

非常感谢即使只是阅读。

【问题讨论】:

    标签: architecture cqrs event-sourcing


    【解决方案1】:

    是否可以采用混合方法,其中某些区域不是事件来源?

    当然。

    我们可以在读写端同步相关表吗?

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

    CQRS 架构的聚合实体是否简化了快照缓存失效?

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

    我们可以对旧事件进行快照和存档吗?

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

    您如何选择要在活动中包含的内容?

    查看此聚合所需的状态以建立/维护/恢复业务不变量。其他所有东西都可以洗掉。这通常意味着报告(读取模型)由多个聚合组合而成,可能还有文档。

    有没有一种有趣的方式来为事件建模?

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

    我们可以改为添加一个过期的 ProductPriceChanged 事件吗?

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

    但是事件中的任何更改不会破坏事件的重播吗?

    不,但是您需要遵守有关事件表示的规则,以确保做到这一点。 Greg Young 正在将Versioning in an Event Sourced System 写成电子书。

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

    随着系统的变化,您最终不会有很多版本化的事件吗?例如,在在线商店中通过更改标准来评估客户是否是金卡持有者?

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

    同样,您是否必须小心依赖注入,以确保注入的任何依赖都不会影响业务逻辑,否则会中断重放?

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

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

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

    你会建议我如何持久化非 ES 聚合实体?

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

    我可能会错过这是如何回答这个问题的 - 如果业务不变量是订单行项目,这包括产品名称还是仅包括价格?

    产品 ID 和数量可能就足够了。如果您所在的企业报价可能与目录中列出的不同,则可能是报价。

    我的意思是,如果聚合的业务逻辑发生变化,但过去的事件仍需要以旧方式处理。

    一个关键的想法是事件的意义不应该改变;它们描述了状态的变化。因此,如果您发现“事件的新版本”意味着不同的东西,那么您就真的有了一个新事件。见杨的书。

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

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

    【讨论】:

    • That sounds like a bad idea - 你如何建议我坚持非 ES 聚合实体? in scope anyway说得好! archive the histories of any aggregate that is end of life - 不会有足够的,对我们来说,生命的终结是在某人真正死后 4 年。 state needed...to maintain the business invariant - 我可能会错过如何回答这个问题 - 如果业务不变量是订单行项目,这包括产品名称还是仅包括价格?
    • Wrong spelling - 我故意将事件从 PriceChangeScheduled 更改为 post-dated PriceChanged,只有在达到该日期后才会在回放中使用。 Decisions made by the system are documented by events - 你在我的理解中发现了一个空白,我的意思是如果聚合的业务逻辑发生变化,但过去的事件仍然需要以旧方式处理。我将(再次)重新阅读您的答案并阅读 Young 的书。获得了很多见解,非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2017-02-05
    • 2011-01-30
    • 1970-01-01
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多