事件溯源和处理数据依赖关系

Posted

技术标签:

【中文标题】事件溯源和处理数据依赖关系【英文标题】:Event Sourcing and dealing with data dependencies 【发布时间】:2018-06-24 14:43:24 【问题描述】:

给定一个具有以下操作的 REST API,导致事件发布到 Kafka:

添加类别 更新类别 删除类别 AddItem(通过某个标识符引用一个类别) 更新项目 删除项目

以及多个用户可能同时使用 REST API 的环境,并且消费者必须都获得相同的事件。消费者可能会长时间离线(超过一天)。可以添加新的消费者,也可以删除其他消费者。

问题:

事件排序(仅解决单个主题/分区?)
    AddCategory 之前的 AddItem,类别引用无效。 AddCategory 之前的UpdateItem,以前是有效的引用,现在无效。 AddItem 之前的RemoveCategory,类别引用无效。 ....无数其他并发问题。
用于快速重新同步重新启动的消费者的事件存储快照
    是否应该为类别和项目建立一个压缩日志主题,每个实体都由其标识符作为关键字? 能否以某种方式将整个压缩日志主题标识为偏移量? 压缩日志主题中是否应该只有一个条目,并且它的数据包含所有类别和给定偏移量的项目的序列化 blob(需要单个主题/分区)。 如何处理从重播实体事件存储到命令/事件的“实时流”的切换?编码压缩日志视图中每个项目的偏移量,并将其传递到实时事件日志中重播?

还有其他系统更适合这个问题吗?

【问题讨论】:

【参考方案1】:

我会根据我在事件溯源方面的经验给你一个部分答案。

事件排序(仅解决单个主题/分区?)

    AddCategory 之前的 AddItem,类别引用无效。

    AddCategory 之前的UpdateItem,以前是有效引用,现在无效。

    AddItem 之前的RemoveCategory,类别引用无效。 ....无数其他并发问题。

我所知道的所有可扩展事件存储都仅在分区内保证事件排序。在DDD 术语中,事件存储通过按照事件生成的顺序重放事件来确保聚合正确地被重新水化。 Apache-kafka 主题似乎是一个不错的选择。虽然这对于应用程序的写入端来说已经足够了,但读取端使用它就更难了。更难但并非不可能。

鉴于事件已经由写入方验证(因为它们代表已经发生的事实),我们可以确定系统中出现的任何不一致都是由于事件的错误顺序造成的。此外,鉴于读取端最终与写入端一致,丢失的事件最终将到达我们的读取模型。

所以,首先,在你的情况下AddItem before AddCategory, invalid category reference,实际上应该是ItemAdded before CategoryAdded(术语是过去的)。

其次,当ItemAdded 到达时,您尝试按 ID 加载类别,如果它失败(因为 延迟 CategoryAdded 事件),那么您可以创建一个 NotYetAvailableCategory 具有ID 等于 ItemAdded 事件中引用的 ID,并且标题为“尚不可用,请稍等几毫秒”。然后,当CategoryAdded 事件到达时,您只需更新所有引用该类别ID 的Items因此,主要思想是创建临时实体,这些实体将在其事件最终到达时完成

CategoryRemoved before ItemAdded, category reference invalid 的情况下,当ItemAdded 事件到达时,您可以检查该类别是否已删除(通过ListOfCategoriesThatWereDeleted 读取模型),然后在您的Item 实体中采取适当的操作 -什么取决于您的业务。

【讨论】:

以上是关于事件溯源和处理数据依赖关系的主要内容,如果未能解决你的问题,请参考以下文章

使用事件溯源摆脱关系数据库?

避免具有异步数据依赖关系的事件链

如何在 Flux 中处理具有依赖关系的数据组合和检索?

基于代码驱动:处理有依赖关系接口

在生产数据库中减少列大小并修剪数据,处理同一列上的约束/依赖关系

React useEffect() 无限重新渲染以获取所有尽管有依赖关系