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