使用 Kafka 和每个实体类型的主题进行事件溯源,外键会发生什么情况?

Dav*_*nez 1 domain-driven-design event-sourcing apache-kafka

我正在尝试使用 Kafka 设计一个事件源系统。假设我们有一个非常简单的事件源应用程序,由四个聚合根组成:用户、类别、产品和购买。

遵循confluence的一些指导,我创建了 4 个主题(为简单起见,我们假设每个主题 1 个分区),每个聚合一个:

  • 为用户提供一个主题
  • 类别的一个主题
  • 产品的一个主题
  • 购买的一个主题

我的投影是 PostgresSQL 投影,它从 Kafka 读取事件,然后将每个事件转换为 SQL 查询(根据事件类型插入、更新或删除)。

问题是数据库模型大约是这样的:

在此输入图像描述

鉴于主题之间的事件顺序无法保证,如果我尝试将产品添加到没有其类别的数据库中,我很可能会收到来自数据库的foreignkey错误。同样,如果我尝试在用户或产品尚未处理的情况下添加购买,我很可能会收到另一个外键错误。

我必须使用哪些分区选项来解决读取模型中的外键问题,并允许我的系统随着更多实体和更多事件而增长,而不必依赖将所有内容放入单个主题来避免外键问题?

我想到的一件事是,虽然我可以独立处理用户和产品而不会发生冲突,但我仍然需要对购买做一些事情(以某种方式延迟该主题的事件处理,直到确保用户和产品存在于数据库)。

Lev*_*sey 6

如果您的目标数据模型使用外键,则从根本上来说您必须延迟成功插入,直到满足约束为止。

可以想象,要做到这一点(假设您同时运行消费流),就是让查询在失败时重试直到成功,尽管这通常会阻止处理来自受影响分区的更多消息。它还取决于事件的含义(例如,是否可能发生删除或更新某些列),可能会因不确定的消费顺序而引发各种死锁和数据争用。

考虑到外键约束之类的目的是验证和拒绝写入,它们通常在读取模型中没有太多用途,其中写入已经由写入模型验证:将产品与类别应被视为产品和类别各自存在的无可争议的证据,无论读取模型的状态如何。这表明至少其中之一:i)从读取模型中删除外键约束,ii)让投影在读取模型中创建最少的记录,以便允许外键验证,iii)有一些“待处理”您知道存在但尚未完成的记录的表(您的预测可能会检查待处理的表以查看更新是否是完成待处理记录所需的内容),或者 iv) 重新考虑您的聚合。