让我们假设一个实际案例:
我们的客户服务将
CustomerCreated/CustomerUpdated
事件发布到客户 Kafka 主题。运输服务监听订单主题
当运输服务读取
OrderCreated
事件时,它将需要访问客户地址。运输服务将已经在本地提供可用的用户信息,而不是向客户服务进行 REST 调用。它保存在具有持久存储的KTable
/GlobalKTable
中。
我的问题是我们应该如何实现这一点:我们希望这个系统具有弹性和可扩展性,因此将有多个客户和运输服务实例,这意味着也将有多个客户和运输分区订购主题。
我们可以找到这样的场景:运输服务读取 OrderCreated(orderId=1, userId=7, ...)
事件,但如果它使用 KTable
为了保存和访问本地用户信息,userId=7
可能不存在,因为处理该 userId 的分区可能已分配给其他运输服务实例。
可以使用 GlobalKTable
临时解决此问题,以便所有运输服务实例都可以访问整个客户范围。
这是实现该模式的推荐方法(
GlobalKTable
)吗?当客户数量非常大时,在每个运输服务实例中复制整个客户数据集是否会出现问题?
这个/应该这个案例以某种方式使用
KTable
来实现吗?
最佳答案
您可以使用 GKTable
和 KTable
来解决此问题。以前的数据结构被复制,因此整个表在每个节点上都可用(并占用更多存储空间)。后者被分区,因此数据分布在各个节点上。这有一个副作用,正如您所说,处理 userId 的分区可能无法同时处理相应的客户。您可以通过重新分区其中一个流来解决此问题,使它们共同分区。
因此,在您的示例中,您需要使用运输服务中的客户信息来丰富订单事件。您可以:
a) 使用客户信息的 GlobalKTable
并连接到每个节点上的该信息
b) 使用客户信息的 KTable
并执行相同的操作,但在进行丰富之前,您必须使用 selectKey()
运算符重新生成 key ,以确保数据共同分区(即相同的 key 将位于同一节点上)。您还必须在 Customer 和 Orders 主题中拥有相同数量的分区。
Inventory Service Example在 Confluence Microservices Examples 中做了类似的事情。它重新设置订单流的 key ,以便它们按 ProductId 分区,然后连接到 Inventory 的 KTable
(也按 ProductId 键入)。
关于您的个人问题:
GlobalKTable
是实现该模式的推荐方法吗? 两者都有效。如果您的服务因某种原因丢失存储空间,GKTable
在最坏情况下的重新加载时间会更长。由于数据必须重新分区,KTable 的延迟会稍大一些,这意味着将数据写入 Kafka 并再次读回。当客户数量非常大时,在每个运输服务实例中复制整个客户数据集是否会出现问题? 主要区别在于前面提到的最坏情况重新加载时间。尽管从技术上讲,
GKTable
和KTable
的语义略有不同(GKTable
在启动时完全加载,KTable
根据事件增量加载-时间,但这与这个问题并不严格相关)这个/应该这个案例以某种方式使用
KTable
来实现吗? 见上文。
另请参阅:Microservice Examples , Quick start , Blog Post .
关于apache-kafka - Kafka 事件携带的状态传输系统是否应该使用 GlobalKTable 进行本地查询来实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55548618/