在微服务的发布/订阅模型中,每个服务类型如何只接收/消费一次消息

Posted

技术标签:

【中文标题】在微服务的发布/订阅模型中,每个服务类型如何只接收/消费一次消息【英文标题】:In a publish/subscribe model in microservices, how to receive/consume a message only once per service type 【发布时间】:2018-01-14 06:01:37 【问题描述】:

我们正在设计一个微服务架构模型,其中服务 A 发布消息,服务 B 发布,而 C 希望接收/使用该消息。但是,为了实现高可用性,服务 B 和 C 的多个实例同时运行。现在的问题是我们如何设计使得只有 B 的一个服务实例和 C 的一个服务实例接收消息,而不是所有其他服务实例。

据我对 RabbitMQ 的了解,要实现这种行为并不容易。我想知道 Kafka 或任何其他消息传递框架是否具有对这种场景的内置支持,我认为这在微服务架构中应该很常见。

【问题讨论】:

【参考方案1】:

您还可以使用命令行工具在 kafka 中测试此用例。

你创建一个生产者

bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test

然后,您可以使用

创建两个不同的消费者组(cgB,cgC)
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning --consumer-property group.id=cgB

bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning --consumer-property group.id=cgC

一旦您向主题发送消息,两个组(B,C)都会收到该消息,但会保存他们独立处理的消息。

在这里更好地解释:Kafka quickstart

【讨论】:

【参考方案2】:

这是您需要执行的更改才能使用 Rabbit MQ 实现相同目标

创建 2 个单独的队列,每个 B 和 C 服务一个 更改逻辑以从队列中读取消息,这样只有一个 实例将从队列中读取消息,使用阻塞 rabbitmq的连接东西。

这样,当 B 和 C 的多个实例同时运行时,两者都会收到消息并且仍然具有可扩展性。

【讨论】:

如何将消息同时发布到两个或多个队列?您使用密钥向交换器发送消息,该密钥用于确定哪个队列与该密钥绑定。你如何定义你的绑定键? 使用广播交换,因此每一个来交换的消息都会被广播到所有队列中,而不管key。 如果其中一个队列不可用/关闭而另一个队列已启动,会发生什么情况?一个队列不会收到另一个会错过的消息吗?如果您有更多的服务,因此有更多的队列,那么确保它们同时启动并运行不是一个管理负担,特别是因为它们可能位于集群中的不同节点上,并且单个节点故障只需要部分队列暂时停止服务? ,系统故障是不可避免的,解决方案是让并行节点启动并运行以进行备份。 @VijayParmar,您能否分享一些演示示例或代码来执行此操作。【参考方案3】:

Kafka 有一个名为 Consumer Groups 的功能,它完全符合您的描述。

每个相同的 B 实例都可以将其 group.id 声明为相同的字符串(例如“serviceB”),并且 Kafka 将确保为每个实例分配一组互斥的主题分区,用于其订阅的所有主题。

由于 C 的所有实例都将具有不同的 group.id(例如“serviceC”),因此它们也将获得与 B 的实例相同的消息,但它们将位于独立的消费者组中,因此消息仅发送到C的N个实例,最大实例数为主题分区的总数。

您可以动态且独立地增加或减少 B 和 C 的实例数量。如果任何实例死亡,其余实例将自动重新平衡其分配的主题分区并接管死亡实例的消息处理。

数据永远不必存储不止一次,因此所有这些服务实例仍然只有一个提交日志或“真实来源”。

【讨论】:

我是 Kafka 新手,请多多包涵。文档说每个分区仅分配给组中的一个消费者,并且消费者组中的消费者实例不能多于分区。这不是服务 B 和 C 的可扩展性限制吗?这是否意味着如果我需要添加更多服务实例,我也必须创建一个新分区? 这意味着如果您想避免重新划分主题,则需要提前计划。一个主题从 12 或 16 个分区开始的情况并不少见,因此有增长的空间。如果你只有 4 个消费者开始,他们每个人只会得到 3-4 个分区。如果您用完了分区,您可以添加更多。你永远不能把它们带走。【参考方案4】:

Kafka 已内置支持此场景。

您可以创建两个Consumer Groups,一个用于B,另一个用于CConsumer Groups 都订阅了来自 A 的消息。

A 发布的任何消息都将发送到两个组。但是,每个组中只有一个成员可以收到该消息。

【讨论】:

以上是关于在微服务的发布/订阅模型中,每个服务类型如何只接收/消费一次消息的主要内容,如果未能解决你的问题,请参考以下文章

如何实时接收微信订阅号的更新提醒?

微信小程序发送一次性订阅消息

通过 BLE 通知接收数据包

公众平台服务号订阅号企业号的相关说明

在微服务架构中组织授权的最佳实践?

Azure 服务总线主题订阅者接收订单