跳至主内容
版本:4.3

生产环境部署指南

概述

RabbitMQ 等数据服务通常有许多可调参数。某些配置或做法在开发阶段非常合理,但并不真正适合生产环境。没有一种配置能适用于所有用例。因此,在进入生产环境之前,务必评估系统配置,并针对升级等“日常运维”活动制定计划。

目录

生产系统除了配置外,还需要关注其他方面:系统可观测性、安全性、应用程序开发实践、资源使用、发布支持时间线等。

监控和指标是生产级系统的基础。除了帮助检测问题外,它还为运营商提供可用于调整 RabbitMQ 节点和应用程序规模及配置的数据。

本指南在以下几个方面提供了建议:

等等。

最低硬件要求

RabbitMQ 可用于各种工作负载。有些负载可能对 I/O 要求非常高(流),有些则需要更多的 CPU 资源(大量的并发连接和队列)。这些工作负载可能需要不同的 CPU、存储和网络资源组合。

提示

本节描述了生产系统的推荐资源最小值。

以下是生产部署的最低系统要求(每个节点):

  • 不应与其他数据服务(例如数据库)或磁盘、网络 I/O 密集型应用程序共存
  • 4 个 CPU 核心
  • 4 GiB 内存
  • 存储相关说明请参见下文的存储部分

对于负载较低的环境、质量保证(QA)和开发环境,较低规格的环境是可以接受的。

危险

RabbitMQ 的设计初衷并非在单核 CPU 环境中运行,也不建议与其它磁盘和网络 I/O 密集型工具共存。

存储注意事项

使用持久化存储

重要

现代 RabbitMQ 功能(例如 Khepri仲裁队列)仅适用于持久化存储。

仲裁队列的数据安全功能要求节点数据存储必须是持久的。这两种数据结构还假设 I/O 操作的延迟相对稳定,而网络附加存储(NAS)在实践中往往无法始终提供这种稳定性。

使用临时存储的节点重启后,其上的仲裁队列和流副本必须在领导者副本上执行整个数据集的完全同步。这可能导致大规模数据传输和网络链路过载,而这些原本可以通过使用持久化存储来避免。

当节点重启时,集群中的其余部分期望它们保留有关集群对等体的信息。如果情况并非如此,重启后的节点可能以新节点身份重新加入,但必须启用特殊的对等清理机制来删除其之前的身份。

临时实体(如队列)和 RAM 节点支持将在 RabbitMQ 4.x 中移除。

超额配置磁盘空间

重要

经验法则是:如果有疑问,请对 RabbitMQ 节点使用的磁盘进行超额配置。仲裁队列和流可能会占用大量的磁盘空间。

仲裁队列和流可能会占用大量的磁盘空间。根据工作负载和设置的不同,它们可能会也可能不会迅速回收已消费、已确认或已过期消息占用的磁盘空间。

以下列出了磁盘空间与内存比例的建议。经验法则是:如果有疑问,请对 RabbitMQ 节点使用的磁盘进行超额配置。

网络附加存储 (NAS)

只要 NAS 卷满足以下条件,即可用于 RabbitMQ 节点数据目录:

  • 提供低 I/O 延迟
  • 能够保证不会出现明显的延迟峰值(例如由于与其他 I/O 密集型服务共享)

仲裁队列、流以及其他 RabbitMQ 功能将受益于快速的本地 SSD 和 NVMe 存储。尽可能优先选择本地存储而不是 NAS。

存储隔离

RabbitMQ 节点绝不能共享它们的数据目录。理想情况下,也不应与其他服务共享磁盘 I/O,以获得最可预测的延迟和吞吐量。

文件系统的选择

RabbitMQ 节点可以使用大多数常用的本地文件系统:ext4、btfs 等。

避免将分布式文件系统用于节点数据目录

  • RabbitMQ 的存储子系统假设 fsync(2) 和其他关键操作具有标准的本地文件系统语义。分布式文件系统通常偏离这些标准保证
  • 分布式文件系统通常设计用于对部分目录的共享访问。在 RabbitMQ 节点之间共享数据目录是绝对禁止的,这必然会导致数据损坏,因为节点不会协调它们的写入操作。

虚拟主机、用户、权限

通常需要在集群初始化时配置虚拟主机、用户、权限、拓扑、策略等。部署时的推荐做法是通过定义导入。定义可以在节点启动时导入,也可以在集群部署后的任何时间使用 rabbitmqadminPOST /api/definitions HTTP API 端点进行导入。

虚拟主机

在单租户环境中,例如当您的 RabbitMQ 集群专门用于支撑生产环境中的单个系统时,使用默认虚拟主机 (/) 完全没问题。

在多租户环境中,请为每个租户/环境使用单独的 vhost,例如 project1_developmentproject1_productionproject2_developmentproject2_production 等。

用户

对于生产环境,请删除默认用户 (guest)。默认用户因其凭据众所周知,默认情况下仅允许从 localhost 连接。与其启用远程连接,不如考虑创建一个具有管理权限和生成密码的单独用户。

建议每个应用程序使用一个单独的用户。例如,如果您有一个移动应用、一个 Web 应用和一个数据聚合系统,您应该拥有 3 个独立的用户。这会使以下几点变得更容易:

  • 将客户端连接与应用程序关联
  • 使用细粒度权限
  • 凭据轮换(例如定期轮换或在发生安全泄露时)

如果同一个应用程序有多个实例,则需要在更好的安全性(每个实例一套凭据)和配置的便利性(在部分或所有实例之间共享一套凭据)之间进行权衡。

对于涉及许多执行相同或相似功能且具有固定 IP 地址的客户端的物联网应用,考虑使用 x509 证书源 IP 地址范围进行身份验证是有意义的。

匿名登录

对于生产环境,禁用匿名登录几乎总是一个好主意。

您可以在 rabbitmq.conf 中按如下方式禁用 ANONYMOUS SASL 机制

auth_mechanisms.1 = PLAIN
auth_mechanisms.2 = AMQPLAIN
# note: the ANONYMOUS mechanism is not listed

# Value none has a special meaning that no user is configured for anonymous logins.
anonymous_login_user = none

监控和资源限制

RabbitMQ 节点受各种资源的限制,既包括物理资源(如可用内存量),也包括软件资源(如进程可打开的最大文件句柄数)。在进入生产环境之前评估资源限制配置,并在之后持续监控资源使用情况非常重要。

监控

监控系统的多个方面(从基础设施和内核指标到 RabbitMQ 再到应用级指标)至关重要。虽然监控需要前期的时间投入,但它在及早捕捉问题和发现潜在的棘手趋势方面非常有效。

内存

RabbitMQ 使用资源驱动的告警在消费者跟不上时对发布者进行限流。

默认情况下,当 RabbitMQ 检测到使用的内存超过可用内存(操作系统报告)的 60% 时,它将不再接受任何新消息:vm_memory_high_watermark.relative = 0.6。这是一个安全的默认值,即使主机是专用的 RabbitMQ 节点,修改此值时也应谨慎。

操作系统和文件系统使用系统内存来加速所有系统进程的操作。如果未能为此保留足够的空闲系统内存,将由于操作系统交换(swapping)而对系统性能产生不利影响,甚至可能导致 RabbitMQ 进程终止。

调整默认 vm_memory_high_watermark 时的几点建议:

  • 托管 RabbitMQ 的节点应始终至少有 256 MiB 的可用内存。使用仲裁队列的部署需要更多内存,请参阅仲裁队列如何使用资源了解更多信息。
  • 推荐的 vm_memory_high_watermark.relative 范围是 0.4 到 0.7
  • 高于 0.7 的值应谨慎使用,并确保已建立可靠的内存使用和基础设施级监控。必须为操作系统和文件系统保留至少 30% 的内存,否则由于页面交换,性能可能会严重下降。

这些是非常笼统的指导原则。与所有调优场景一样,需要通过监控、基准测试和测量来找到最适合环境和工作负载的设置。

在单独的指南中了解更多关于 RabbitMQ 和系统内存的信息。

磁盘空间

当前的 50MB disk_free_limit 默认值非常适合开发和教程。生产部署需要更大的安全边际。磁盘空间不足会导致节点故障,并可能因所有磁盘写入失败而导致数据丢失。

那为什么默认值是 50MB 呢?开发环境有时使用非常小的分区来托管 /var/lib,这意味着节点在启动后立即进入资源告警状态。极低的默认值确保了 RabbitMQ 可以开箱即用。对于生产部署,我们建议如下:

建议的最小可用磁盘空间低水位值与高内存水位值大致相同。例如,在配置为内存水位为 4GB 的节点上,disk_free_limit.absolute = 4G 是推荐的最小值。

警告

磁盘空间耗尽的节点应被视为非常严重的运维问题,通常会导致受影响节点的中断并可能导致数据丢失。

如果有疑问,请超额配置磁盘空间和/或使用较高的 disk_free_limit

打开文件句柄限制

操作系统限制了可同时打开的文件句柄的最大数量,其中包括网络套接字。确保设置的限制足够高,以满足预期的并发连接数和队列数。

确保生产环境(包括开发环境)为 RabbitMQ 有效用户提供至少 50K 的打开文件描述符限制。

作为准则,将并发连接数的 95 分位数值乘以 2,加上队列总数,即可计算出推荐的打开文件句柄限制。高达 500K 的值并不算过分,也不会消耗大量的硬件资源,因此推荐用于生产环境设置。

请参阅网络指南了解更多信息。

日志收集

强烈建议收集并聚合所有 RabbitMQ 节点和应用程序(尽可能)的日志。在调查异常系统行为时,日志可能至关重要。

可配置限制

生产集群应至少采用一些可配置的限制,作为护栏,防止行为不端的应用程序泄漏资源并影响集群稳定性。

RabbitMQ 在多个级别提供了一套全面的可配置限制:从集群级到每个虚拟主机每个用户,一直到单个连接、通道、队列和流。

在多租户环境或将 RabbitMQ 作为服务提供时,采用这些限制尤为重要。即使在单租户部署中,限制也有助于防止资源泄漏并提供对应用程序问题的早期检测。

有关可用限制及其配置方法的详细信息,请参阅可配置限制指南

安全注意事项

用户和权限

请参阅上面关于 vhost、用户和凭据的部分。

节点间及 CLI 工具认证

RabbitMQ 节点使用存储在文件中的共享密钥进行相互认证。在 Linux 和其他类 UNIX 系统上,必须将 cookie 文件的访问权限仅限制为将运行 RabbitMQ 和 CLI 工具的 OS 用户。

使用合理安全的方式(例如不是从容易猜测的值计算得出)生成该值非常重要。这通常在初始部署时使用自动化部署工具完成。这些工具可能使用默认或占位符值:请勿依赖它们。让运行时在一个节点上生成 cookie 文件并将其复制到所有其他节点也是一种糟糕的做法:因为生成算法是已知的,这使得生成的值更具可预测性。

CLI 工具使用相同的认证机制。建议将节点间及 CLI 通信端口的访问权限限制为运行 RabbitMQ 节点或 CLI 工具的主机。

建议使用 TLS 加密节点间通信。这意味着 CLI 工具也必须配置为使用 TLS。

防火墙配置

RabbitMQ 使用的端口大致可分为两类:

  • 客户端库使用的端口(AMQP 0-9-1、AMQP 1.0、MQTT、STOMP、HTTP API)
  • 所有其他端口(节点间通信、CLI 工具等)

通常应将后一类端口的访问权限限制为运行 RabbitMQ 节点或 CLI 工具的主机。前一类端口应可由运行应用程序的主机访问,在某些情况下(例如在负载均衡器后面)这意味着公共网络。

TLS

我们建议尽可能使用 TLS 连接,至少用于加密流量。也建议进行对等验证(身份验证)。开发和 QA 环境可以使用自签名 TLS 证书。当 RabbitMQ 和所有应用程序都在受信任的网络上运行或使用 VMware NSX 等技术进行隔离时,自签名证书在生产环境中也是合适的。

虽然 RabbitMQ 默认尝试提供合理的安全 TLS 配置,但强烈建议使用 testssl.sh 等工具评估 TLS 配置(版本、密码套件等)。请参阅 TLS 指南以了解更多信息。

请注意,TLS 可能会对整体系统吞吐量产生重大影响,包括 RabbitMQ 和使用它的应用程序的 CPU 使用率。

网络配置

生产环境可能需要调整网络配置,例如为了支撑大量的并发客户端。请参阅网络指南获取详细信息。

最低可用网络吞吐量估算

随着消息速率的提高和消息载荷的增大,集群节点可用的流量带宽成为一个重要因素。

可以使用以下(特意简化的)公式来计算集群节点必须具备的最低带宽(单位为比特/秒):

MR * MS * 110% * 8

其中:

  • MR:每秒 95 分位消息速率
  • MS:95 分位消息大小(单位:字节)
  • 110%:考虑了消息属性、协议元数据以及传输的其他数据
  • 8:每字节的位数

例如,消息速率 (MR) 为每秒 20K,消息载荷 (MS) 为 6 KB:

20K * 6 KB * 110% * 8 bit/B = 20000 * 6000 * 1.1 * 8 = 1.056 (gigabit/second)

根据上述输入,集群节点必须具备至少 1.056 吉比特每秒的吞吐量网络链路。

该公式仅为经验法则,并未考虑协议或工作负载特有的细微差别。

集群注意事项

集群规模

队列数量、队列复制因子、连接数量、最大消息积压量以及消息吞吐量等都是决定集群规模大小的因素。

当简洁性高于一切时,单节点集群就足够了:开发、集成测试和某些 QA 环境。

三节点集群是进阶选择。它们可以容忍单个节点故障(或不可用)并继续保持仲裁。为了可用性、弹性和某些情况下的吞吐量,我们牺牲了简洁性。

建议使用奇数个节点的集群(3、5、7 等),这样当一个节点不可用时,服务仍然可用,并且可以确定明确的节点多数派。

对于大多数环境,将队列复制配置为超过半数(但不是全部)集群节点就足够了。

奇数个节点与集群多数派

在进入生产环境之前,选择网络分区处理策略非常重要。如果有疑问,请对奇数个节点(3、5、7 等)使用 pause_minority 策略。

奇数个节点使网络分区恢复更具可预测性,其中一个常见选项是少数派自动拒绝服务命令。

数据局部性注意事项

在多节点集群中,数据局部性成为一个重要的考量因素。由于客户端可以连接到任何节点,RabbitMQ 节点可能需要执行跨集群的消息路由和内部操作。当生产者连接到运行队列领导者的 RabbitMQ 节点时,数据局部性最好。这种拓扑在实践中很难实现。

对于经典队列,所有投递均从领导者副本执行。仲裁队列也可以从队列副本投递消息,因此只要消费者连接到托管仲裁队列副本的节点,投递给这些消费者的消息将从本地节点执行。

增加节点数量以维持更多并发客户端

必须支撑大量并发客户端连接的环境将受益于更多的集群节点,只要连接分布在这些节点上即可。这可以通过使用负载均衡器,或者让客户端从提供的节点列表中随机选择一个节点进行连接来实现。

增加节点数量 vs. 为不同用途部署独立集群

所有元数据(定义:虚拟主机、用户、队列、交换机、绑定等)都会在集群中的所有节点之间进行复制,并且大多数元数据更改本质上是同步的。

随着集群节点数量的增加,传播此类更改的成本会上升,无论是在运维期间还是节点重启期间。如果您的集群节点数量达到两位数,请在可能的情况下考虑为系统的不同部分使用独立的集群

节点时间同步

RabbitMQ 集群通常在服务器时钟未同步的情况下也能良好运行。但某些插件(例如管理插件)会利用本地时间戳进行指标处理,当节点当前时间产生偏差时,可能会显示不正确的统计信息。因此,建议服务器使用 NTP 或类似服务来确保时钟保持同步。

应用程序注意事项

应用程序的设计方式及其使用 RabbitMQ 客户端库的方式是系统整体弹性的主要决定因素。低效使用资源或泄漏资源的应用程序最终会影响系统的其余部分。例如,一个不断打开连接却从不关闭它们的应用程序将耗尽集群节点的文件描述符,导致无法接受新的连接。此类问题在更复杂的场景下(例如统称为“惊群效应”的问题)会表现得更加明显。

本节涵盖了一些最常见的问题。大多数这些问题通常不是协议特有的,也不是新问题。然而,它们可能很难检测。对系统进行充分的监控至关重要,因为这是及早发现问题趋势(例如通道泄漏、因连接管理不善导致的文件描述符使用增加)的唯一途径。

连接管理

消息协议通常假设长连接。一些应用程序在启动时连接到 RabbitMQ,仅在必须终止时才关闭连接。其他应用程序则更动态地打开和关闭连接。对于后一组,在不再使用时关闭连接非常重要。

连接可能会因应用程序开发人员无法控制的原因而关闭。RabbitMQ 支持的消息协议使用一种称为心跳的功能(名称可能不同,但概念相同)来比 TCP 栈更快地检测此类连接。开发人员应小心不要将心跳超时设置得太低(小于 5 秒),因为这可能会在网络拥塞或系统负载升高时产生误报。

尽可能避免非常短的连接。下一节将更详细地介绍这一点。

建议尽可能让发布者和消费者使用单独的连接,以便消费者与可能应用于发布连接的流控相隔离,从而避免影响手动消费者确认

连接抖动

如上所述,消息协议通常假设长连接。一些应用程序可能会打开一个新连接来执行单个操作(例如发布一条消息),然后将其关闭。这是极其低效的,因为打开连接是一项昂贵的操作(相比重用现有连接)。这种工作负载也会导致连接抖动。经历高连接抖动的节点必须进行调优以比内核默认值更快地释放 TCP 连接,否则它们最终会耗尽文件句柄或内存,并停止接受新连接。

如果不能选择少量长连接,连接池可以帮助减少峰值资源使用量。

从连接故障中恢复

一些客户端库(例如 Java.NETRuby)支持网络故障后的自动连接恢复。如果使用的客户端提供此功能,建议使用它,而不是开发自己的恢复机制。

其他客户端(Go、Pika)不支持自动连接恢复作为一项特性,但提供了演示如何从连接故障中恢复的示例。

过度的通道使用

通道在客户端和服务器端都会消耗资源。应用程序应尽可能减少使用的通道数量,并关闭不再需要的通道。通道和连接一样,旨在长久存续。

注意,关闭连接会自动关闭其上的所有通道。

轮询消费者

轮询消费者(使用 basic.get 进行消费)是应用程序开发人员在大多数情况下应避免的功能,因为轮询本质上是低效的。

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