JetStream 概念

JetStream 实现的功能

JetStream 是 NATS 内置的分布式持久化子系统。它在基础的 “Core NATS” 之上,提供了新的功能和更高的 QoS 。

时间解耦

在现代系统中,应用程序可以使用像 NATS 这样的发布-订阅消息系统来暴露服务或生产并消费数据流。

发布-订阅消息传递模型的基本特性之一是时间耦合:订阅者需要处于上线状态才能在消息发布时接收它。从高层次来看,如果需要实现可观测性、应用程序需要在未来消费消息、需要以自己的节奏进行消费,甚至需要所有历史消息,那么 JetStream 的流式传输功能可为发布者和消费者之间提供时间上的解耦。

Queueing and replay

JetStream 提供了将消息放入队列以备未来消费以及消息重放的能力。流可以配置为使用 WorkingQueue 保留策略,以便队列消息供消费者以后再消费,这意味着消息在被消费后会从流中删除;或者可以配置消费者使用 Limits 保留策略,以按需从流的开头或特定时间点进行单个或分布式消息重放。

Mirroring and Sourcing

JetStream 提供了将消息从一个流镜像到另一个流,以及设定一个流从别的流摄取消息的能力。这使得构建复杂的流和消费者拓扑成为可能。

例如,您可以有一个初始流,仅捕获有限时间内的消息,并用于重放消息,同时也可以将这些消息馈送到任何数量的其他流中,这些流就是初始流的 镜像流/设置了 Sources 的流。这使得消费者能够从 镜像流/设置了 Sources 的流 中消费消息,而不会影响原始流,并且可以按照自己的节奏进行消费。

更高的 QoS

除了发布者与订阅者之间的时间解耦(即 “Stream”),JetStream 还提供了其他功能和 QoS 。

可靠的消息传递

“Core NATS” 的基本 QoS 为 '最多一次' 消息传递。这意味着虽然依赖于可靠的网络传输协议(如 TCP)在服务器与客户端之间(以及集群中的服务器之间)进行通信,以恢复因“偶然”网络故障(如数据包丢失)导致的连接中断,但这并不是一种“可靠”的 QoS :在某些故障场景下,可能会导致客户端应用出现“消息丢失”,特别是:

  • 连接中断: 如果客户端应用遭遇足够严重的网络中断,导致其与服务器的 TCP 连接断开或重置,那么它可能会无法接收在该中断期间缓冲(或发布)的部分消息。
  • 慢速消费者: NATS 服务器基础设施设计用于“自我保护”,以防止“不良客户端”。具体来说,如果订阅消息的 NATS 客户端应用无法跟上主题上的发布速度(即如果应用程序是“慢速消费者”),尽管 nats-server 会尽力缓冲消息以交付给订阅的客户端应用,但其资源永远不会无限,因此为了保护 nats-server 不会耗尽内存缓冲区(包括连接到客户端应用的缓冲区),存在一个限制。当达到客户端缓冲区的限制时,nats-server 将通过“重置”与该客户端的连接并清除缓冲区来应对。

虽然 nats-server 在丢弃客户端连接以保护自身时会记录 有慢速消费者的信息 到日志,但从客户端应用的角度来看,这似乎只是应用程序经历了一次临时的服务器断开连接,部分消息可能永远无法被接收。

而 JetStream 会利用各种 ACK 机制(针对发布者和订阅者)提供了“可靠”的 QoS ,从而在 Core NATS 基本的 “最多一次” QoS 之上,提供了两种 QoS :

  • "至少一次" QoS:利用带 JetStream ACK 机制的 publish 调用和带 ACK 机制的消费者,确保所有消息都被接收,不会因为 故障、客户端应用不始终在线、消费缓慢 而导致“丢失”。它被称为“至少一次”,因为仍然存在一些故障场景的极端情况,可能导致某些消息实际上被消费应用程序多次接收(如果处理接收到消息的业务逻辑是幂等的,则这不是问题)。
  • "恰好一次" QoS:在上述基础上,增加了 nats-server 在发布者端执行消息去重的能力, 通过使用“双重 ACK”,避免了消费者下的应用程序在从某些故障场景中恢复时多次收到某些消息。

这两种 QoS 意味着客户端应用在与 nats-server 断开连接后会自动恢复,而不会丢失任何消息(如果你使用持久化消费者,客户端应用甚至可以在停止并稍后重新启动)。对于“慢速消费者”,使用流意味着消息的“缓冲”发生在流中(这可能比服务器缓冲区大得多),而不是在服务器缓冲区中。

流量控制

避免“慢速消费者”的最明显方法是实现某种形式的流量控制。虽然 TCP 本身在网络通信中提供了固有的流量控制,但它并不直接适用于发布-订阅消息系统,因为与纯粹点对点(即“1 对 1”)的 TCP 不同,发布-订阅允许“1 对 N”(以及“N 对 M”)通信。

如果您要为基本的“Core NATS”发布-订阅实现流量控制,您必须实现一种“端到端”的流量控制(即在发布者与其当前所有订阅者之间),这意味着您最终会将发布者流量控制到所有当前订阅者的 “最低公分母”。也就是说,发布者会被减速,以确保其发布速度不超过所有订阅者中处理速度 最慢 的那个。

由于这种“最低公分母”特性,即在 1对N 或 N对M 通信中的端到端流量控制,以及由于发布-订阅消息系统最重要的用例之一是分发实时数据,“Core NATS”并未实现任何类型的端到端流量控制。

虽然您当然可以通过利用请求-回复 交互来实现自己的端到端流量控制,但使用 JetStream 并利用其提供的 解耦 流量控制功能则更加简单(也更好)。

JetStream 上的流量控制是 解耦 的,因为它不是“端到端”的,而是独立地存在于 通过 JetStream 发布的客户端应用与流(即启用 JetStream 的 nats-server(s))之间,以及流与使用 JetStream 消费者的客户端应用之间。

Storage

在 JetStream 中,消息如何存储、消息如何被消费 是分开定义的。存储方法是在 中定义的,而消息的消费细节是由多个 消费者 设定的。