是否应该使用GlobalKTable实施Kafka事件携带状态转移系统以进行本地查询?

时间:2019-04-06 11:26:52

标签: apache-kafka apache-kafka-streams event-driven event-driven-design

The event carried state transfer removes the need to make remote calls to query information from other services

让我们假设一个实际案例:

  1. 我们有一个客户服务,该服务向客户Kafka主题发布CustomerCreated/CustomerUpdated个事件。

  2. 运输服务监听订单主题

  3. 运输服务读取OrderCreated事件时,将需要访问客户地址。运送服务将不再具有对客户服务的REST调用,而已在本地提供用户信息。它保存在KTable / GlobalKTable中,具有持久性存储。

我的问题是关于如何实现这一目标的:我们希望该系统具有弹性和可扩展性,因此将有一个以上的客户和运输服务实例,这意味着该客户和运输服务也将有多个分区。订购主题。

我们可以找到以下情况:运送服务读取了OrderCreated(orderId=1, userId=7, ...)事件,但是如果事件使用KTable来保留和访问本地用户信息,则userId=7可能不会因为可以将处理该userId的分区分配给其他运输服务实例。

可以使用GlobalKTable解决此问题,以便所有运输服务实例都可以访问整个客户范围。

  1. 这是(GlobalKTable)实施该模式的推荐方法吗?

  2. 当客户数量很大时,在每个运输服务实例中复制整个客户数据集是否有问题?

  3. 可以/以某种方式使用KTable来实现这种情况吗?

1 个答案:

答案 0 :(得分:2)

您可以使用GKTableKTable来解决此问题。复制了以前的数据结构,因此整个表可在每个节点上使用(并占用更多存储空间)。后者是分区的,因此数据分布在各个节点上。正如您所说,这具有副作用,即处理userId的分区也可能无法处理相应的客户。您可以通过对流之一进行重新分区来解决此问题,以便对它们进行共分区。

因此,在您的示例中,您需要在“运送服务”中为“订单”事件添加“客户”信息。您可以: a)使用GlobalKTable的客户信息,并在每个节点上加入 b)使用KTable的客户信息并执行相同的操作,但是在进行充实之前,您必须使用selectKey()运算符重新输入密钥以确保数据被共同分区(即,相同的密钥将处于打开状态)同一节点)。在“客户和订单”主题中,您还必须具有相同数量的分区。

Confluent微服务示例中的Inventory Service Example做类似的事情。它为订单流重新设置密钥,以便它们按productId进行分区,然后加入到KTable的库存中(也由productId进行键控)。

关于您的个人问题:

  1. GlobalKTable是实现该模式的推荐方法吗? 两者都可以。如果您的服务由于任何原因而失去存储空间,则GKTable的重载情况将更长。 KTable的延迟会稍长一些,因为必须对数据进行重新分区,这意味着将数据写到Kafka并再次读回。

  2. 当客户数量很大时,在每个运输服务实例中复制整个客户数据集是否存在问题? 主要区别在于上述最坏情况的重新加载时间。尽管从技术上讲GKTableKTable的语义略有不同(GKTable在启动时完全加载,KTable根据事件时间递增加载,但这与该问题并不严格相关)

  3. 可以/可以通过KTable来实现这种情况吗? 见上文。

另请参阅:Microservice ExamplesQuick startBlog Post