Kafka 事件承载状态传输系统是否应该使用 GlobalKTable 来实现本地查询?
Should Kafka event carried state transfer systems be implemented using a GlobalKTable for local queries?
让我们假设一个实际案例:
我们有一个客户服务将 CustomerCreated/CustomerUpdated
事件发布到客户 Kafka 主题。
送货服务监听订单主题
当运输服务读取 OrderCreated
事件时,它需要访问客户地址。运输服务将已经在本地提供用户信息,而不是向客户服务发出 REST 调用。它保存在具有持久存储的 KTable
/GlobalKTable
中。
我的问题是关于我们应该如何实现这一点:我们希望这个系统具有弹性和可扩展性,因此会有多个客户和运输服务实例,这意味着也会有多个分区用于客户和订单主题。
我们可以找到这样的场景:运输服务读取了一个 OrderCreated(orderId=1, userId=7, ...)
事件,但是如果它使用 KTable
来保存和访问本地用户信息,userId=7
可能不在那里,因为处理该 userId 的分区可能已分配给其他运输服务实例。
这个问题可以使用 GlobalKTable
解决,这样所有运输服务实例都可以访问所有客户。
这是(GlobalKTable
)实现该模式的推荐方法吗?
当客户数量非常大时,在每个运输服务实例中复制整个客户数据集是否有问题?
this/should这个案例可以用KTable
以某种方式实现吗?
你可以用 GKTable
和 KTable
来解决这个问题。之前的数据结构被复制,因此整个 table 在每个节点上都可用(并占用更多存储空间)。后者是分区的,因此数据分布在各个节点上。正如您所说,这有副作用,处理 userId 的分区可能不会处理相应的客户。您可以通过重新分区其中一个流来解决此问题,以便它们共同分区。
因此,在您的示例中,您需要使用运输服务中的客户信息来丰富订单事件。您可以:
a) 使用 GlobalKTable
的客户信息并在每个节点上加入该信息
b) 使用客户信息的 KTable
并执行相同的操作,但在进行扩充之前,您必须使用 selectKey()
运算符重新加密以确保数据是共同分区的(即相同的键将在同一个节点)。您还必须在 Customer 和 Orders 主题中拥有相同数量的分区。
Confluent Microservices Examples 中的 Inventory Service Example 做了类似的事情。它重新键入订单流,以便它们按 productId 分区,然后加入 KTable
的库存(也按 productId 键入)。
关于您的个人问题:
GlobalKTable
是实施该模式的推荐方法吗?
两者都有效。如果您的服务因任何原因丢失存储空间,GKTable
有更长的最坏情况重新加载时间。 KTable
会有稍长的延迟,因为数据必须重新分区,这意味着将数据写出到 Kafka 并再次读回。
当客户量很大时,在每个运输服务实例中复制整个客户数据集是否有问题?
主要区别在于前面提到的最坏情况下的重新加载时间。尽管技术上 GKTable
和 KTable
的语义略有不同(GKTable
在启动时完全加载,KTable
根据事件时间增量加载,但这与这个问题并不严格相关)
this/should这个案例可以用KTable
以某种方式实现吗?
见上。
让我们假设一个实际案例:
我们有一个客户服务将
CustomerCreated/CustomerUpdated
事件发布到客户 Kafka 主题。送货服务监听订单主题
当运输服务读取
OrderCreated
事件时,它需要访问客户地址。运输服务将已经在本地提供用户信息,而不是向客户服务发出 REST 调用。它保存在具有持久存储的KTable
/GlobalKTable
中。
我的问题是关于我们应该如何实现这一点:我们希望这个系统具有弹性和可扩展性,因此会有多个客户和运输服务实例,这意味着也会有多个分区用于客户和订单主题。
我们可以找到这样的场景:运输服务读取了一个 OrderCreated(orderId=1, userId=7, ...)
事件,但是如果它使用 KTable
来保存和访问本地用户信息,userId=7
可能不在那里,因为处理该 userId 的分区可能已分配给其他运输服务实例。
这个问题可以使用 GlobalKTable
解决,这样所有运输服务实例都可以访问所有客户。
这是(
GlobalKTable
)实现该模式的推荐方法吗?当客户数量非常大时,在每个运输服务实例中复制整个客户数据集是否有问题?
this/should这个案例可以用
KTable
以某种方式实现吗?
你可以用 GKTable
和 KTable
来解决这个问题。之前的数据结构被复制,因此整个 table 在每个节点上都可用(并占用更多存储空间)。后者是分区的,因此数据分布在各个节点上。正如您所说,这有副作用,处理 userId 的分区可能不会处理相应的客户。您可以通过重新分区其中一个流来解决此问题,以便它们共同分区。
因此,在您的示例中,您需要使用运输服务中的客户信息来丰富订单事件。您可以:
a) 使用 GlobalKTable
的客户信息并在每个节点上加入该信息
b) 使用客户信息的 KTable
并执行相同的操作,但在进行扩充之前,您必须使用 selectKey()
运算符重新加密以确保数据是共同分区的(即相同的键将在同一个节点)。您还必须在 Customer 和 Orders 主题中拥有相同数量的分区。
Confluent Microservices Examples 中的 Inventory Service Example 做了类似的事情。它重新键入订单流,以便它们按 productId 分区,然后加入 KTable
的库存(也按 productId 键入)。
关于您的个人问题:
GlobalKTable
是实施该模式的推荐方法吗? 两者都有效。如果您的服务因任何原因丢失存储空间,GKTable
有更长的最坏情况重新加载时间。KTable
会有稍长的延迟,因为数据必须重新分区,这意味着将数据写出到 Kafka 并再次读回。当客户量很大时,在每个运输服务实例中复制整个客户数据集是否有问题? 主要区别在于前面提到的最坏情况下的重新加载时间。尽管技术上
GKTable
和KTable
的语义略有不同(GKTable
在启动时完全加载,KTable
根据事件时间增量加载,但这与这个问题并不严格相关)this/should这个案例可以用
KTable
以某种方式实现吗? 见上。