运行环境方面的考虑

网络

负载均衡

你可以在客户端应用与集群服务器之间(甚至在集群内部的服务器之间,或超级集群中的不同集群之间)放置负载均衡器,但你并不需要这样做,因为 NATS 已有自己的机制,可以平衡连接 URL 中种子节点之间的连接(包括:客户端会随机选择返回的 DNS A 记录),并且能够自动重新建立掉线的连接。 如果你有一个包含 3 个种子节点的集群,不使用负载均衡器通常可以得到更高的网络吞吐量(云服务提供商的负载均衡器性能可能严重不足,更不用说使用负载均衡器还会增加成本,因为通常按通过它的数据量收费)。 此外,如果你想使用 TLS 进行身份验证,就不希望负载均衡器成为 TLS 的终止点。

{% hint style="warning" %} 如果你决定将 NATS 与负载均衡器一起使用,你需要了解下客户端连接、集群连接以及自动发现行为。

客户端连接和路由是持久的。因此,负载均衡器不会把来自同一个客户端连接的消息分发到不同的服务器上,或者更糟糕的是(这在自动配置环境中部署时很常见),你最终会得到冗余但彼此不相连(非集群化)的服务器,而客户端则会随机连接到这些服务器。此时需要关闭 advertise 功能 或通过 advertise 服务器配置选项 配置为指向负载均衡器地址。

负载均衡器还可能因为以下问题带来麻烦: 配置不当的空闲检测、数据包检查导致的协议问题、在大规模场景下的临时端口耗尽问题。

如果路由或网关连接经过负载均衡器,你很可能会遇到上述问题,这可能导致 JetStream 出现失去仲裁期的情况,并引发不必要的重新同步和额外的协议开销流量。 {% endhint %}

把客户端连接经过负载均衡器有一些合理的使用场景。 如果被负载均衡的 NATS 服务器被设置为集群(或超级集群),它们能够提供透明的消息路由,那么负载均衡器可以简化客户端配置:要么只需提供一个统一的入口端口,要么自动连接到地理位置上更接近的集群节点。

虚拟化、容器化

NATS 是“云原生”的,预期将在虚拟环境和/或容器中部署。

然而,当涉及到确保 NATS 能够提供尽可能高的性能时,需要注意以下几点。

可以把 Core NATS 服务器想象成软件版的网络交换机。启用 JetStream 后,它们同时也会变成一种新型的数据库服务器。

你需要记住的是,在公用云中选择 NATS 服务器主机实例的实例类型和存储选项时:一分钱一分货

例如,非网络优化型实例可能提供 10 Gb/s 的网络带宽……但仅限于一段时间(比如 30 分钟),之后可用带宽可能会急剧下降(比如降至 5 Gb/s)并持续一段时间。因此,如果你始终需要稳定的标称带宽,请选择网络优化型实例。

存储选项也是同样的道理:

  • 本地 SSD 实例类型可以提供最佳的延迟;
  • 使用网络附加块存储(例如 AWS 的 Elastic Block Storage,EBS)则可以提供最高的整体吞吐量。

再次强调,使用 EBS 时同样是 一分钱一分货:通用型存储可能会提供一定数量的 IOPS,但只能在一段时间内维持这些速率,之后 IOPS 可能会大幅下降。若你希望持续维持相同的最大 IOPS,应选择 IO 优化型存储类型(例如 AWS 提供的类型)。

资源限制

在为 nats-server 容器 设置资源限制时要小心。

  • nats-server 进程使用的资源与所有客户端应用产生的负载流量成正比。
  • 如果 NATS(以及 JetStream)的使用量很高,或者存在突发流量(nats-server 非常快,可以处理尖锐的流量峰值),那么你需要相应地设置容器的资源限制,否则容器编排系统会直接杀掉该服务器容器。
  • nats-server 会自动检测可用的 CPU 核心数,但它会尝试使用所有主机内存,而不是容器设置的内存限制,除非你指定 GOMEMLIMIT
  • GOMEMLIMIT 已在官方 NATS Helm Charts 中提供作为可选项。