部署指南
概述
诸如 RabbitMQ 之类的数据服务通常具有许多可调参数。某些配置或实践对于开发而言很有意义,但实际上并不适合生产环境。没有一种配置适合所有用例。因此,评估系统配置并制定“第二天运维”活动的计划(例如 升级)在投入生产环境之前非常重要。
目录
生产系统除了配置之外,还需要关注以下方面:系统可观察性、安全性、应用程序开发实践、资源使用情况、发布支持时间表等等。
监控和指标是生产级系统的基础。除了帮助检测问题外,它还为运维人员提供了可用于调整 RabbitMQ 节点和应用程序大小和配置的数据。
本指南在以下几个领域提供建议
- 存储 节点数据目录的注意事项
- 网络相关建议
- 与 虚拟主机、用户和权限 相关的建议
- 监控和资源使用
- 每个虚拟主机和每个用户的限制
- 安全性
- 集群和多节点部署
- 应用程序级别的实践和注意事项
等等。
存储注意事项
使用持久存储
仲裁队列 和 流 的数据安全功能期望节点数据存储是持久的。这两种数据结构也都假设 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、btfs 等。
避免对节点数据目录使用分布式文件系统
- RabbitMQ 的存储子系统假定
fsync(2)
和其他关键操作的标准本地文件系统语义。分布式文件系统通常 偏离这些标准保证 - 分布式文件系统通常设计用于共享访问目录的子集。在 RabbitMQ 节点之间共享数据目录是**绝对禁止的**,并且保证会导致数据损坏,因为节点不会协调它们的写入操作
虚拟主机、用户、权限
通常需要在集群中预置虚拟主机、用户、权限、拓扑、策略等等。在部署时执行此操作的推荐方法是 通过定义导入。可以在节点启动时或在集群部署后的任何时候使用 rabbitmqadmin
或 POST /api/definitions
HTTP API 端点 导入定义。
虚拟主机
在单租户环境中,例如,当您的 RabbitMQ 集群专用于为生产环境中的单个系统供电时,使用默认虚拟主机 (/
) 完全可以。
在多租户环境中,为每个租户/环境使用单独的虚拟主机,例如 project1_development
、project1_production
、project2_development
、project2_production
等等。
用户
对于生产环境,请删除默认用户 (guest
)。默认用户默认只能从本地主机连接,因为它具有众所周知的凭据。与其启用远程连接,不如考虑创建一个具有管理权限和生成的密码的单独用户。
建议每个应用程序使用单独的用户。例如,如果您有一个移动应用程序、一个 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 节点受到各种资源的限制,包括物理资源(例如,可用 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
) 为每秒 2 万条,消息有效负载 (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 节点时,数据局部性将是最佳的。这种拓扑在实践中很难实现。
对于经典队列,所有交付都从领导者副本执行。仲裁队列也可以从队列副本交付消息,因此,只要消费者连接到托管仲裁队列副本的节点,交付给这些消费者的消息将从本地节点执行。
增加节点数量以维持更多并发客户端
必须维持 大量并发客户端连接 的环境将受益于更多集群节点,只要连接分布在这些节点上即可。这可以通过使用负载均衡器或使客户端从提供的节点列表中随机选择要连接的节点来实现。
增加节点数量与为不同目的部署单独的集群
所有元数据(定义:虚拟主机、用户、队列、交换器、绑定等)都在集群中的所有节点之间复制,并且大多数元数据更改本质上是同步的。
传播此类更改的成本会随着集群节点数量的增加而增加,无论是在操作期间还是节点重启期间。发现自己需要节点数量为两位数的集群的用户应**考虑为系统的不同部分使用独立的集群**(如果可能)。
节点时间同步
RabbitMQ 集群通常在参与服务器的时钟未同步的情况下也能良好运行。但是,某些插件(例如管理插件)会使用本地时间戳进行指标处理,并且当节点当前时间漂移时可能会显示不正确的统计信息。因此,建议服务器使用 NTP 或类似工具来确保时钟保持同步。
应用程序注意事项
应用程序的设计方式以及使用 RabbitMQ 客户端库的方式是系统整体弹性的主要贡献者。低效使用资源或泄漏资源的应用程序最终将影响系统的其余部分。例如,持续打开连接但从不关闭连接的应用程序将耗尽集群节点的可用文件描述符,因此将不接受任何新连接。这种问题和类似问题可能会在更复杂的场景中表现出来,例如那些统称为惊群问题的问题。
本节介绍了一些最常见的问题。这些问题中的大多数通常不是协议特定的或新的。但是,它们可能很难检测到。对系统进行充分的 监控 至关重要,因为它是及早发现问题趋势(例如,通道泄漏、连接管理不善导致的文件描述符使用量增长)的唯一方法。
连接管理
消息协议通常假设长连接。某些应用程序在启动时连接到 RabbitMQ,并且仅在必须终止时才关闭连接。其他应用程序更动态地打开和关闭连接。对于后一组,重要的是在不再使用连接时关闭它们。
连接可能会因应用程序开发人员无法控制的原因而关闭。RabbitMQ 支持的消息协议使用称为 心跳 的功能(名称可能不同,但概念相同)来比 TCP 堆栈更快地检测此类连接。开发人员应注意使用过低的心跳超时(少于 5 秒),因为当网络拥塞或系统负载升高时,这可能会产生误报。
应尽可能避免非常短的连接。以下部分将更详细地介绍这一点。
建议尽可能让发布者和消费者使用单独的连接,以便消费者与可能应用于发布连接的潜在 流量控制 隔离,从而影响 手动消费者确认。
连接抖动
如上所述,消息协议通常假设长连接。某些应用程序可能会打开一个新连接来执行单个操作(例如,发布消息),然后关闭它。这是非常低效的,因为打开连接是一项昂贵的操作(与重用现有连接相比)。这种工作负载还会导致 连接抖动。经历高连接抖动的节点必须进行调优,以便比内核默认值更快地释放 TCP 连接,否则它们最终会耗尽文件句柄或内存,并将停止接受新连接。
如果少量长连接不是一种选择,则连接池可以帮助减少峰值资源使用量。
从连接故障中恢复
某些客户端库,例如 Java、.NET 和 Ruby,支持在网络故障后自动恢复连接。如果使用的客户端提供此功能,建议使用它而不是开发自己的恢复机制。
其他客户端(Go、Pika)不支持自动连接恢复作为一项功能,但确实提供了演示如何从连接故障中恢复的示例。
过度使用通道
通道也会消耗客户端和服务器中的资源。应用程序应尽可能减少它们使用的通道数量,并关闭不再需要的通道。与连接一样,通道也应该是长连接。
注意关闭连接会自动关闭其上的所有通道。
轮询消费者
轮询消费者(使用 basic.get
进行消费)是应用程序开发者在大多数情况下应避免使用的功能,因为轮询本质上是低效的。