让我们假设一个实际案例:
我们有一个客户服务,该服务向客户Kafka主题发布CustomerCreated/CustomerUpdated
个事件。
运输服务监听订单主题
运输服务读取OrderCreated
事件时,将需要访问客户地址。运送服务将不再具有对客户服务的REST调用,而已在本地提供用户信息。它保存在KTable
/ GlobalKTable
中,具有持久性存储。
我的问题是关于如何实现这一目标的:我们希望该系统具有弹性和可扩展性,因此将有一个以上的客户和运输服务实例,这意味着该客户和运输服务也将有多个分区。订购主题。
我们可以找到以下情况:运送服务读取了OrderCreated(orderId=1, userId=7, ...)
事件,但是如果事件使用KTable
来保留和访问本地用户信息,则userId=7
可能不会因为可以将处理该userId的分区分配给其他运输服务实例。
可以使用GlobalKTable
解决此问题,以便所有运输服务实例都可以访问整个客户范围。
这是(GlobalKTable
)实施该模式的推荐方法吗?
当客户数量很大时,在每个运输服务实例中复制整个客户数据集是否有问题?
可以/以某种方式使用KTable
来实现这种情况吗?
答案 0 :(得分:2)
您可以使用GKTable
和KTable
来解决此问题。复制了以前的数据结构,因此整个表可在每个节点上使用(并占用更多存储空间)。后者是分区的,因此数据分布在各个节点上。正如您所说,这具有副作用,即处理userId的分区也可能无法处理相应的客户。您可以通过对流之一进行重新分区来解决此问题,以便对它们进行共分区。
因此,在您的示例中,您需要在“运送服务”中为“订单”事件添加“客户”信息。您可以:
a)使用GlobalKTable
的客户信息,并在每个节点上加入
b)使用KTable
的客户信息并执行相同的操作,但是在进行充实之前,您必须使用selectKey()
运算符重新输入密钥以确保数据被共同分区(即,相同的密钥将处于打开状态)同一节点)。在“客户和订单”主题中,您还必须具有相同数量的分区。
Confluent微服务示例中的Inventory Service Example做类似的事情。它为订单流重新设置密钥,以便它们按productId进行分区,然后加入到KTable
的库存中(也由productId进行键控)。
关于您的个人问题:
GlobalKTable
是实现该模式的推荐方法吗?
两者都可以。如果您的服务由于任何原因而失去存储空间,则GKTable
的重载情况将更长。 KTable
的延迟会稍长一些,因为必须对数据进行重新分区,这意味着将数据写到Kafka并再次读回。
当客户数量很大时,在每个运输服务实例中复制整个客户数据集是否存在问题?
主要区别在于上述最坏情况的重新加载时间。尽管从技术上讲GKTable
和KTable
的语义略有不同(GKTable
在启动时完全加载,KTable
根据事件时间递增加载,但这与该问题并不严格相关)
可以/可以通过KTable
来实现这种情况吗?
见上文。