跳至主内容

RabbitMQ 3.11 功能预览:Super Streams

·阅读 7 分钟

RabbitMQ 3.11 将带来一个在其历史上名称最酷的功能之一:Super Streams。Super Streams 是一种通过将大型流分区为较小流来扩展的方法。它们与Single Active Consumer集成,以在分区内保留消息顺序。

这篇博文概述了 Super Streams 及其带来的用例。继续阅读以了解更多信息,我们重视您的反馈,以使此功能尽善尽美。

概述

Super stream 是一种逻辑流,由单独的、常规的 streams 组成。它是一种在 RabbitMQ Streams 中实现发布和消费扩展的方法:一个大的逻辑流被划分为多个分区流,将存储和流量分散到多个集群节点上。

Super stream 仍然是一个逻辑实体:应用程序通过客户端库的智能实现,将其视为一个“大”流。Super stream 的拓扑基于 AMQP 0.9.1 模型,即交换器、队列以及它们之间的绑定。

下图展示了一个由 3 个分区组成的 invoices super stream。它由一个 invoices 交换器和绑定到它的 3 个流定义。

A super stream is a structure that sits above streams, allowing to logically group a set of streams. AMQP 0.9.1 resources define its physical topology.
Super stream 是一种位于 streams 之上的结构,它允许逻辑上分组一组 streams。AMQP 0.9.1 资源定义了其物理拓扑。

消息不经过交换器,而是直接进入分区流。但是 客户端库 使用拓扑信息来确定消息的路由目标和消费来源。

让我们来谈谈大家最关心的问题:它与 Kafka 相比如何?我们可以将 super stream 与 Kafka 主题进行比较,将 stream 与 Kafka 主题的分区进行比较。然而,RabbitMQ stream 是一个一等公民,拥有独立的名称,而 Kafka 分区是 Kafka 主题的子项。这种解释遗漏了大量的细节,没有真正的一对一映射,但对于本文的论点来说已经足够准确了。

Super streams 还利用 单活动消费者 来保证在消费者处理期间分区内消息的顺序。

请注意,super streams 并不会弃用单独的 streams 或使其变得无用。它们也不是 streams 的 2.0 版本,因为我们最初就设计 streams 的方式存在一些问题。Super streams 建立在 streams 之上,带来了自己的一套功能和能力。您仍然可以在它们适用时继续使用单独的 streams,也可以探索 super streams 来满足更苛刻的用例。

发布到 Super Stream

应用程序发布到 super stream 的消息必须进入其中一个分区。应用程序可以通过客户端库的帮助来选择分区,而代理不负责路由。这非常灵活,并避免了服务器端的瓶颈。

应用程序必须提供至少一个信息:从消息中提取的路由键。以下代码片段展示了应用程序如何使用 stream Java 客户端库提供此代码。

Producer producer = environment.producerBuilder()
.superStream("invoices") // set the super stream name
.routing(message -> message.getProperties().getMessageIdAsString()) // extract routing key
.producerBuilder()
.build();

producer.send(...);

发布与使用 常规 stream 保持一致,只是生产者配置略有不同。发布到 stream 或 super stream 对应用程序代码的影响不大。

消息去哪里了?在这种情况下,库通过使用 MurmurHash3 对路由键进行哈希来选择 stream 分区。此哈希函数提供了良好的均匀性、性能和可移植性,使其成为一个不错的默认选择。在本例中,路由键是发票 ID,因此发票应该均匀分布在各个分区中。如果路由键是客户 ID,我们将保证给定客户的所有发票都在同一个分区中。这是一个可以利用的用例:在给定时间段内按客户进行报告,并附带相应的 基于时间戳的偏移量指定

说到处理,让我们来看看如何从 super stream 中消费。

从 Super Stream 消费

Super stream 的分区是常规 streams,因此应用程序可以像往常一样从它们进行消费。但这需要了解 super stream 的拓扑,而我们将其宣传为一个逻辑实体,即应用程序将其视为一个单独的 stream。幸运的是,客户端库可以在代理的帮助下实现这一点,从而对应用程序来说一切都是透明的。

客户端库可以实现一个 众所周知的设计模式,并提供一个复合消费者,该消费者同时从 super stream 的所有分区进行消费。

A client library provides a composite consumer that consumes from all partitions at the same time. Applications then see the super stream as an individual stream. This is not enough though.
客户端库提供了一个复合消费者,该消费者同时从所有分区进行消费。应用程序将 super stream 视为一个单独的 stream。但这还不够。

以这种方式实现的复合消费者存在局限性:如果您启动同一应用程序的多个实例以实现冗余和可扩展性,它们将消费相同的消息,导致处理重复。所有这些都需要协调,幸运的是,我们可以将 单活动消费者 的语义应用于我们的 super stream 复合消费者。

现在启用了单活动消费者,我们的复合消费者的实例将与代理协调,以确保在任何给定时间只有一个消费者在某个分区上活动。

Combining super stream consumers and single active consumer. There is only one active consumer on a partition at a time for a given group.
结合 Super Stream 消费者和单活动消费者。对于给定的组,在任何给定时间每个分区上只有一个活动消费者。

好消息是,所有这些都是实现细节。应用程序实例可以启动和关闭,消费者将根据单活动消费者语义进行激活或停用。

这在代码中如何体现?以下是 stream Java 客户端的一个示例。

Consumer consumer = environment.consumerBuilder()
.superStream("invoices") // set the super stream name
.name("application-1") // set the consumer name (mandatory)
.singleActiveConsumer() // enable single active consumer
.messageHandler((context, message) -> {
// message processing
})
.build();

这与 常规 stream 的消费者 类似,只有配置会改变,更重要的是消息处理代码保持不变。

总结

我们在本文中介绍了Super Streams,这是即将发布的 RabbitMQ 3.11 版本中的一项新功能。Super Streams 是分区流,它们为 RabbitMQ Stream 带来了可扩展性。结合 单活动消费者,它们保证在分区内按照发布顺序处理消息。

本文有一个 配套示例项目,提供了分步演示来阐释文中介绍的功能。请务必参考一下!

我们很高兴与 RabbitMQ 社区分享这项新功能,并迫不及待地希望在 RabbitMQ 3.11 今年晚些时候 GA 之前收到一些 反馈

© . This site is unofficial and not affiliated with VMware.