首页 > 解决方案 > 回复并不总是传递到所需的回复侦听器容器

问题描述

我们使用 spring-kafka 和 ReplyingKafkaTemplate 应用请求/回复语义。但是,我们注意到有时回复并没有到达应有的位置。

以下是我们设置的粗略描述:

服务A

2 个使用消息的实例,topic-a其中有 2 个分区。(每个实例分配 1 个分区)。服务 A 是发起者。

服务乙:

2 个实例,使用来自 的消息topic-b,它也有 2 个分区。对来自 A 的传入消息做出反应,并使用@SendTo注释返回回复消息。

观察到的行为:

当服务 A 的实例(例如 A1)正在向服务 B 发送消息时,发送失败并出现回复超时。该请求被 B 成功消费,并且正在返回一个回复,但是它被另一个实例消费了,例如 A2。从日志中我可以看到 A1 分配了 topic-a-0,而 A2 分配了 topic-a-1。

来自文档的建议:

我们的场景在文档的这一部分进行了描述:https ://docs.spring.io/spring-kafka/reference/html/#replying-template 它提供了一些建议:

  1. 给每个实例一个专门的回复主题
  2. 使用回复分区标头并为每个实例使用专用分区

我们的设置基于整个服务的单个主题。因此,所有传入事件和回复事件都发送到此并从此主题中使用。因此,在我们的情况下,选项 #1 是不可取的。

选项 #2 的缺点是您不能使用组管理功能,这是一个遗憾,因为我们的服务运行在 Kubernetes 上,因此我们希望使用组管理功能以获得最大的灵活性。

第三种选择?

所以我想知道是否有第三种选择:为什么不使用组管理并在发送消息时动态确定回复容器的分配主题分区并设置回复分区标头。看起来ReplyingKafkaTemplate#getAssignedReplyTopicPartitions方法正好提供了这些信息。这样,分区不固定,我们仍然可以使用组管理功能。我可以预见的唯一缺点是,在发送请求后但在收到回复之前重新平衡分区时,请求可能会失败。

我已经测试了一些东西,看看它是否有效,并且看起来确实有效。我发布这个问题的主要原因是检查我的想法是否有意义,是否有任何注意事项需要考虑。我想知道为什么开箱即用的 spring-kafka 不支持这一点。

如果我的解决方案有意义,我愿意提出增强问题并提供有关 spring-kafka 项目的 PR。

标签: spring-kafka

解决方案


正如您所描述的,问题是不能保证在重新平衡后我们会得到相同的分区。

“第三个选项”是group.id为每个实例使用不同的并设置sharedReplyTopic=true. 在这种情况下,所有实例都会收到回复,并且会被未发送请求的实例丢弃。

然而,最好的解决方案是为每个实例使用一个唯一的回复主题。


推荐阅读