生产环境部署指南
概述
像 RabbitMQ 这样的数据服务通常有许多可调参数。有些配置或实践对于开发来说很有意义,但对于生产环境来说并不适用。没有一种配置适合所有用例。因此,在部署到生产环境之前,评估系统配置并制定“第二天运维”活动的计划(例如 升级)非常重要。
目录
生产系统需要考虑的不仅仅是配置:系统可观测性、安全性、应用程序开发实践、资源使用、发布支持时间表 等等。
监控和指标是生产级系统的基础。除了帮助检测问题外,它还为运维人员提供了可用于调整 RabbitMQ 节点和应用程序规模和配置的数据。
本指南在几个方面提供了建议
等等。
最低硬件要求
RabbitMQ 可用于各种工作负载。有些可能 I/O 密集型(流),有些可能需要更多 CPU 资源(大量并发连接和队列)。这些工作负载可能需要不同的 CPU、存储和网络资源组合。
本节描述了生产系统推荐的最低资源要求。
以下是每个节点的生产部署的最低系统要求
- 不与其他数据服务(例如数据存储)或磁盘、网络 I/O 密集型应用程序共置
- 4 个 CPU 核心
- 4 GiB RAM
- 有关存储,请参阅下面的存储
对于某些负载较轻的环境、质量保证和开发环境,较低规格的环境也是可以接受的。
RabbitMQ 不是为在单核 CPU 环境中运行,或与其他磁盘和网络 I/O 密集型工具共存而设计的。
存储注意事项
使用持久化存储
法定队列和流的数据安全功能期望节点数据存储是持久化的。这两种数据结构还假定 I/O 操作具有相当稳定的延迟,而网络附加存储在实践中并不总是能够提供这一点。
在使用瞬态存储的已重启节点上托管的法定队列和流副本将不得不与主副本同步整个数据集。这可能导致大量数据传输和网络链路过载,而这些本可以通过使用持久化存储来避免。
当节点重启时,集群的其余部分期望它们保留有关其集群对等节点的信息。如果不是这样,重启的节点可能可以作为新节点重新加入,但需要启用特殊的对等清理机制来移除它们之前的身份。
瞬态实体(如队列)和 RAM 节点支持将在 RabbitMQ 4.x 中移除。
过度配置磁盘空间
经验法则是:如有疑问,请过度配置 RabbitMQ 节点使用的磁盘。法定队列和流可能占用大量的磁盘空间。
法定队列和流可能占用大量的磁盘空间。根据工作负载和设置,它们可能快速回收已消费、已确认或已过期的消息所占用的磁盘空间,也可能不回收。
下面列出了磁盘空间与 RAM 的比例建议。经验法则是:如有疑问,请过度配置 RabbitMQ 节点使用的磁盘。
网络附加存储 (NAS)
网络附加存储 (NAS) 可用于 RabbitMQ 节点数据目录,前提是 NAS 卷
- 提供低 I/O 延迟
- 能够保证没有显著的延迟峰值(例如,由于与其他 I/O 密集型服务共享)
法定队列、流和其他 RabbitMQ 功能将受益于快速的本地 SSD 和 NVMe 存储。在可能的情况下,优先使用本地存储而不是 NAS。
存储隔离
RabbitMQ 节点不得共享其数据目录。理想情况下,为了最可预测的延迟和吞吐量,它们不应与其他服务共享其磁盘 I/O。
文件系统选择
RabbitMQ 节点可以使用大多数广泛使用的本地文件系统:ext4、btrfs 等。
避免为节点数据目录使用分布式文件系统
- RabbitMQ 的存储子系统假定 `fsync(2)` 和其他关键操作的标准本地文件系统语义。分布式文件系统通常偏离这些标准保证
- 分布式文件系统通常设计用于对目录子集进行共享访问。在 RabbitMQ 节点之间共享数据目录是绝对禁止的,并且肯定会导致数据损坏,因为节点不会协调它们的写入
虚拟主机、用户、权限
通常需要使用虚拟主机、用户、权限、拓扑、策略等来初始化集群。在部署时推荐的方法是通过定义导入。可以在节点启动时导入定义,或者在集群部署后使用 `rabbitmqadmin` 或 `POST /api/definitions` HTTP API 端点的任何时间点导入。
虚拟主机
例如,在单租户环境中,当您的 RabbitMQ 集群专用于生产中的单个系统时,使用默认虚拟主机(`/`)是完全可以的。
在多租户环境中,为每个租户/环境使用一个单独的 vhost,例如 `project1_development`、`project1_production`、`project2_development`、`project2_production` 等。
用户
对于生产环境,删除默认用户(`guest`)。默认用户默认只能从 localhost 连接,因为它具有众所周知的凭据。与其启用远程连接,不如考虑创建一个具有管理员权限和生成密码的单独用户。
建议每个应用程序使用一个单独的用户。例如,如果您有一个移动应用程序、一个 Web 应用程序和一个数据聚合系统,您将有 3 个单独的用户。这使得许多事情更容易
- 将客户端连接与应用程序关联
- 使用细粒度权限
- 凭据轮换(例如,定期或在发生泄露时)
如果同一应用程序有许多实例,则需要在更好的安全性(每个实例一组凭据)和方便的配置(在某些或所有实例之间共享一组凭据)之间进行权衡。
对于涉及许多执行相同或类似功能并具有固定 IP 地址的客户端的 IoT 应用程序,可以考虑使用 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 节点。
操作系统和文件系统使用系统内存来加速所有系统进程的操作。未能为这些目的留下足够的可用系统内存将由于操作系统交换而对系统性能产生不利影响,甚至可能导致 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`。
打开文件句柄限制
操作系统限制了并发打开文件句柄的最大数量,其中包括网络套接字。确保您的限制设置足够高,以允许预期的并发连接和队列数量。
确保生产环境至少允许 50K 打开的文件描述符供有效的 RabbitMQ 用户使用,包括在开发环境中。
作为指导,将 95% 百分位并发连接数乘以 2,再加上总队列数,即可计算推荐的打开文件句柄限制。高达 500K 的值并不会不充足,也不会消耗大量硬件资源,因此,它们推荐用于生产设置。
有关更多信息,请参阅网络指南。
日志收集
强烈建议收集和聚合所有 RabbitMQ 节点和应用程序(如果可能)的日志。日志对于调查异常系统行为至关重要。
可配置的限制
生产集群应采用至少一些可配置的限制,作为保护机制,防止行为不当的应用程序耗尽资源并影响集群稳定性。
RabbitMQ 在多个级别提供了全面的可配置限制:从集群范围到每个虚拟主机和每个用户,一直到单个连接、通道、队列和流。
在多租户环境或将 RabbitMQ 作为服务提供时,采用这些限制尤其重要。即使在单租户部署中,限制也有助于防止资源泄漏并提供应用程序问题的早期检测。
有关可用限制及其配置方法的详细信息,请咨询可配置限制指南。
安全注意事项
用户和权限
请参阅上面关于 vhosts、用户和凭据的部分。
节点间和 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,消息载荷为 6 KB(`MS`)时
20K * 6 KB * 110% * 8 bit/B = 20000 * 6000 * 1.1 * 8 = 1.056 (gigabit/second)
使用上述输入,集群节点必须具有至少 1.056 千兆比特每秒的吞吐量网络链路。
这个公式**是一个经验法则**,没有考虑协议或特定于工作负载的细微差别。
集群注意事项
集群大小
队列数量、队列复制因子、连接数、最大消息积压以及有时是消息吞吐量是决定集群应该多大的因素。
当简单性比其他任何因素都重要时,单节点集群可能就足够了:开发、集成测试和某些 QA 环境。
三节点集群是下一个级别。它们可以容忍单个节点发生故障(或不可用)并仍然维持仲裁。简单性被可用性、弹性以及在某些情况下的吞吐量所取代。
建议使用奇数个节点的集群(3、5、7 等),这样当一个节点变得不可用时,服务仍然可用,并且可以识别出明确的大多数节点。
对于大多数环境,将队列复制配置为超过一半但不到所有集群节点的数量就足够了。
奇数个节点和集群多数
在部署到生产环境之前,选择一个分区处理策略非常重要。如有疑问,请使用 `pause_minority` 策略和奇数个节点(3、5、7 等)。
奇数个节点使网络分区恢复更加可预测,常见的选项是少数节点自动拒绝服务命令。
数据局部性注意事项
对于多节点集群,数据局部性成为一个重要考虑因素。由于客户端可以连接到任何节点,RabbitMQ 节点可能需要执行集群间消息路由和内部操作。当生产者(发布者)连接到运行队列领导者的 RabbitMQ 节点时,数据局部性将是最佳的。这种拓扑在实践中很难实现。
对于经典队列,所有传递都来自主副本。法定队列也可以从队列副本进行传递,因此只要消费者连接到托管法定队列副本的节点,传递给这些消费者的消息将从本地节点进行。
增加节点数量以支持更多并发客户端
需要支持大量并发客户端连接的环境将受益于更多的集群节点,只要连接分布在它们之间。这可以通过使用负载均衡器或让客户端从提供的节点列表中随机选择一个节点进行连接来实现。
增加节点数量与为不同目的部署独立集群
所有元数据(定义:虚拟主机、用户、队列、交换器、绑定等)都会在集群中的所有节点之间复制,并且大多数元数据更改本质上是同步的。
在操作和节点重启期间,传播此类更改的成本会随着集群节点数量的增加而增加。发现需要两位数节点数的集群的用户应该**考虑在可能的情况下使用独立的集群来处理系统的不同部分**。
节点时间同步
RabbitMQ 集群在参与服务器的时钟不同步的情况下通常也能正常工作。但是,某些插件(如管理插件)会利用本地时间戳进行指标处理,当节点的当前时间漂移时,可能会显示不正确的统计信息。因此,建议服务器使用 NTP 或类似的工具来确保时钟保持同步。
应用程序注意事项
应用程序的设计方式和使用 RabbitMQ 客户端库的方式是影响整体系统弹性的主要因素。效率低下或泄漏资源的应用程序最终会影响系统的其余部分。例如,一个持续打开连接但从不关闭的应用程序将耗尽集群节点的句柄,导致无法接受新连接。这以及类似的问题可能表现为更复杂的场景,例如统称为“惊群效应”的问题。
本节涵盖了许多最常见的问题。大多数这些问题通常不是协议特定的,也不是新的。但是,它们可能难以检测。对系统的充分监控至关重要,因为它是及早发现问题趋势(例如,通道泄漏、由于连接管理不善导致的句柄使用量增长)的唯一方法。
连接管理
消息协议通常假定长连接。一些应用程序在启动时连接到 RabbitMQ,并且只有在它们必须终止时才关闭连接。后一种情况更动态地打开和关闭连接。对于后者,在不再使用连接时关闭它们很重要。
连接可能因应用程序开发者无法控制的原因而关闭。RabbitMQ 支持的消息协议使用一种称为心跳(名称可能不同,但概念不变)的功能,比 TCP 堆栈更快地检测到此类连接。开发人员在使用心跳超时时应小心,不要设置过低(低于 5 秒),因为这可能会在网络拥塞或系统负载增加时产生误报。
应尽可能避免使用寿命非常短的连接。下一节将对此进行更详细的介绍。
建议尽可能让发布者和消费者使用独立的连接,这样消费者就可以与可能应用于发布连接的流控制隔离开,从而影响手动消费者确认。
连接耗损
如上所述,消息协议通常假定长连接。一些应用程序可能会打开一个新连接来执行单个操作(例如,发布一条消息),然后关闭它。这效率非常低下,因为打开连接是一个昂贵的操作(与重用现有连接相比)。此类工作负载还会导致连接耗损。必须对经历高连接耗损的节点进行调优,使其比内核默认值更快地释放 TCP 连接,否则它们最终将耗尽文件句柄或内存,并将停止接受新连接。
如果少量长连接不可行,连接池可以帮助减少峰值资源使用。
从连接失败中恢复
一些客户端库,例如Java、.NET 和Ruby,支持网络故障后的自动连接恢复。如果使用的客户端提供此功能,建议使用它而不是开发自己的恢复机制。
其他客户端(Go、Pika)不支持自动连接恢复作为一项功能,但提供了演示如何从连接失败中恢复的示例。
过度使用通道
通道也会在客户端和服务器中消耗资源。应用程序应尽可能减少使用的通道数量,并关闭不再需要的通道。通道(与连接一样)是长期的。
请注意,关闭连接会自动关闭其上的所有通道。
轮询消费者
应用程序开发人员在大多数情况下应避免轮询消费者(使用 `basic.get` 进行消费),因为轮询效率低下。