Apache kafka 在事件驱动体系结构中使用变更数据捕获和Debezium导致的不一致性

Apache kafka 在事件驱动体系结构中使用变更数据捕获和Debezium导致的不一致性,apache-kafka,debezium,change-data-capture,event-driven-design,Apache Kafka,Debezium,Change Data Capture,Event Driven Design,我们一直在使用更改数据捕获和发件箱模式,通过使用Debezuim和Kafka在我们的事件驱动架构中保持不同微服务之间的数据库同步。我们在早期阶段面临的一个挑战是,如果Kafka不能跨多个分区保持秩序,我们如何确保数据库不会失去同步。处理这种情况的方法是明智地选择分区键,这样与相同实体相关的所有事件都应该基于分区键转到相同的分区。因此,可以为同一实体保留顺序。一开始这似乎很简单,但解决涉及两个不同实体的情况似乎是一个根本性的挑战。由于我们只能有一个分区键,因此我们需要决定在选择分区键时可以考虑哪个

我们一直在使用更改数据捕获发件箱模式,通过使用DebezuimKafka在我们的事件驱动架构中保持不同微服务之间的数据库同步。我们在早期阶段面临的一个挑战是,如果Kafka不能跨多个分区保持秩序,我们如何确保数据库不会失去同步。处理这种情况的方法是明智地选择分区键,这样与相同实体相关的所有事件都应该基于分区键转到相同的分区。因此,可以为同一实体保留顺序。一开始这似乎很简单,但解决涉及两个不同实体的情况似乎是一个根本性的挑战。由于我们只能有一个分区键,因此我们需要决定在选择分区键时可以考虑哪个实体。下面是一个可能出错的实际示例:

假设有两个实体<代码>用户和具有MxN关系的工作区。每个
用户
可以访问多个
工作区
s,每个
工作区
可以被多个
用户
s访问。因此,定义了三组不同的事件来处理
用户
工作区
之间的关系:

  • 用户
    事件(
    创建
    更新
    删除
  • 工作区
    事件(
    创建
    更新
    删除
  • 用户工作区
    事件(
    创建
    删除
因此,当
工作区
分配给
用户
时,可以生成以下三种类型的事件:

  • 更新
    用户
  • 更新
    工作区
  • 创建
    用户工作区
如果我们想为这些事件定义模式,将有两种方法:

1-当我们为关系事件定义模式时,我们需要使用两个事件的所有属性来保持其自包含性。这意味着
USER-WORKSPACE
包含
USER
WORKSPACE
的所有属性

2-仅使用
用户-工作区
用户ID
工作区ID
架构中每个实体的ID

第一种方法的问题是它非常冗余,我们需要创建太多重复记录

另一方面,,第二种方法的问题是,我们无法保证在不同类型的事件之间保持顺序,因此我们需要以一种特殊的方式实现消费者,假设在消费
USER
WORKSPACE
实体之前消费了
USER-WORKSPACE
,我们需要创建一个占位符在消费者服务方面。因此,如果相应的实体不存在,则可以为
用户
工作区
创建空实体

只有当我们能够保证相同类型事件的顺序时,此解决方案才有效。但是,当涉及到
用户-工作区
事件时,如果选择
用户id
,则
工作区
可能会失去同步,如果选择
工作区id
,则
用户
可能会失去同步

下面是一个事件序列的示例,如果使用user_id作为
user-WORKSPACE
事件的分区键,则可能会导致不一致。这是生成的事件的顺序:

1-
USER
U1已创建

2-
工作区
W1已创建

3-
USER-WORKSPACE
U1-W1已创建

4-
工作区
W1被删除

5-
USER-WORKSPACE
U1-W1被删除

快照:

  • USER
    U1
这些事件按以下顺序使用:

1-
工作区
W1已创建

2-
工作区
W1被删除

3-
USER
U1已创建

4-
USER-WORKSAPCE
U1-W1已创建(应创建
工作区的占位符

5-
USER-WORKSPACE
U1-W1被删除(无法删除
WORKSPACE
的占位符,因为我们不知道这是否是删除
WORKSPACE
实体或相应关系的副作用)

快照:

  • USER
    U1
  • WORKSPACE
    W1(占位符)
如您所见,这可能会导致不一致。在CDC的发件箱模式中如何管理关系类型事件的情况,我是否遗漏了什么?这是否意味着唯一的方法是为每个关系定义一个fat事件并使其完全独立