运行时调优
概述
RabbitMQ 在 Erlang 虚拟机和运行时环境下运行。为了运行 RabbitMQ,必须安装兼容版本的 Erlang。
Erlang 运行时包含许多 RabbitMQ 使用的组件。就本指南而言,最重要的组件是
- Erlang 虚拟机执行代码
epmd
将主机上的节点名称解析为节点间通信端口
本指南将重点介绍虚拟机。有关 epmd
的概述,请参阅网络指南。
涵盖的主题包括
- 如何为 RabbitMQ 节点配置 Erlang VM 设置
- 运行时调度器,它们是什么,它们与 CPU 核心的关系等等
- 运行时线程活动指标:调度器和 CPU 时间花费在哪里
- 影响 CPU 利用率的运行时功能
- 如何在负载适中或较轻的节点上降低 CPU 利用率
- 内存分配器设置
- 打开文件句柄限制
- 节点间通信缓冲区大小
- Erlang 进程限制
- Erlang 崩溃转储
- Atom 使用量
VM 设置
Erlang VM 具有广泛的可配置选项,涵盖进程调度器设置、内存分配、垃圾回收、I/O 等。调整这些标志可以显着改变节点的运行时行为。
配置标志
大多数设置可以使用环境变量进行配置。一些设置有专用变量,其他设置只能使用以下通用变量进行更改,这些通用变量控制 RabbitMQ 启动脚本传递给 Erlang 虚拟机的标志。
通用变量包括
RABBITMQ_SERVER_ERL_ARGS
允许覆盖所有 VM 标志,包括 RabbitMQ 脚本设置的默认值RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
允许将一组标志附加到 RabbitMQ 脚本设置的默认值RABBITMQ_CTL_ERL_ARGS
控制 CLI 工具 VM 标志
在大多数情况下,建议使用 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
。它可用于以安全的方式覆盖默认值。例如,如果从 RABBITMQ_SERVER_ERL_ARGS
中省略了重要的标志,则运行时性能特征或系统限制可能会在无意中受到影响。
与 RabbitMQ 使用的其他环境变量一样,RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
及其友元可以使用单独的环境变量文件进行设置。
CPU 利用率
CPU 利用率是一个特定于工作负载的主题。一般来说,当工作负载涉及的队列、连接和通道多于 CPU 核心时,所有核心都将在无需任何配置的情况下被使用。
运行时提供了几个功能来控制核心的使用方式。
运行时调度器
运行时中的调度器将工作分配给执行它的内核线程。它们执行代码、执行 I/O、执行计时器等等。调度器有许多设置,这些设置会影响节点的整体系统性能、CPU 利用率、延迟和其他运行时特性。
默认情况下,运行时将为其检测到的每个 CPU 核心启动一个调度器。从 Erlang 23 开始,这将 CPU 配额考虑在内,例如 Docker 和 Kubernetes 等容器化环境中。
调度器的数量可以使用 +S
标志显式设置。以下示例配置节点启动 4 个调度器,即使它检测到更多核心可用
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+S 4:4"
大多数时候,默认行为运行良好。在共享或 CPU 受限的环境(包括容器化环境)中,可能需要显式配置调度器计数。
CPU 资源争用
运行时假定它不与其他工具或租户共享 CPU 资源。当情况如此时,使用的调度机制可能会变得非常低效,并导致某些操作的延迟显着增加(高达几个数量级)。
这意味着在大多数情况下,强烈建议不要将 RabbitMQ 节点与其他工具放在一起或应用 CPU 时间分片,这将导致次优性能。
调度器忙等待
当运行时调度器没有要执行的工作时,可以将其置于睡眠状态。将它们重新联机有一定的成本,因此对于某些工作负载,不这样做可能是有益的。
这可以比作具有多个传送带的工厂。当一条传送带上的物品用完时,可以停止它。但是,一旦有更多工作要做,重新启动它将需要时间。或者,传送带可以推测性地保持运行一段时间。
默认情况下,RabbitMQ 节点配置运行时调度器在进入睡眠状态之前推测性地等待一小段时间。可能存在长时间不活动的工作负载可以选择使用 +sbwt
和相关的运行时标志关闭此推测性忙等待
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+sbwt none +sbwtdcpu none +sbwtdio none"
这也可以减少 CPU 资源有限或可突发的系统上的 CPU 使用率。
为了确定调度器在忙等待中花费了多少时间,请查阅线程活动指标。忙等待通常会在 top
和 pidstat
等工具的输出中被计为系统时间。
调度器到 CPU 核心绑定
调度器的数量并不总是与可用 CPU 核心的数量匹配,并且 CPU 核心的数量不一定与硬件线程的数量相关(例如,由于超线程)。因此,运行时必须决定如何将调度器绑定绑定到硬件线程、CPU 核心和 NUMA 节点。
有几种绑定策略可用。可以使用 RABBITMQ_SCHEDULER_BIND_TYPE
环境变量或 +stbt
运行时标志值指定所需的策略。
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+stbt nnts"
RABBITMQ_SCHEDULER_BIND_TYPE="nnts"
请注意,只有当运行时可以检测到给定环境中的 CPU 拓扑时,该策略才有效。
有效值包括
db
(默认使用,当前 Erlang 发布系列中tnnps
的别名)tnnps
nnts
nnps
ts
ps
s
ns
有关更详细的说明,请参阅VM 标志文档。
降低 CPU 使用率
CPU 使用率在定义上是一个非常依赖于工作负载的指标。某些工作负载自然会使用更多 CPU 资源。其他工作负载使用磁盘密集型功能,例如仲裁队列,如果磁盘 I/O 吞吐量不足,则 CPU 资源将在节点忙于等待 I/O 操作完成时被浪费。
一些通用建议可以应用于“负载适中”的系统,在这些系统中,大部分或大多数连接和队列可能会不时空闲。换句话说,在本节中,我们将任何没有在其峰值容量附近徘徊的系统都视为“负载适中”。
这样的系统通常可以通过一些简单的步骤来减少其 CPU 占用空间。这些建议可以显着减少某些工作负载的 CPU 占用空间:例如,考虑这个社区案例。
收集运行时线程统计信息
收集运行时线程活动统计信息数据,以了解调度器和 CPU 时间是如何花费的。这是做出明智决策的关键步骤。
关闭推测性调度器忙等待
使用 +sbwt
和相关的运行时标志关闭推测性调度器忙等待
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+sbwt none +sbwtdcpu none +sbwtdio none"
推测性忙等待通常在负载适中的系统上没有效率。
降低统计信息发送频率(增加统计信息发送间隔)
将统计信息发送间隔从默认的 5 秒增加到 15 秒或 30 秒。这将减少所有连接、通道和队列执行的定期活动,即使它们在客户端操作方面原本是空闲的。对于大多数监控工具,这种监控频率就足够了,甚至可能是最佳的。
线程统计信息
RabbitMQ CLI 工具提供了许多指标,这些指标使推理运行时线程活动变得更容易。
rabbitmq-diagnostics runtime_thread_stats
是生成各种线程如何花费时间的细分信息的命令。
该命令的输出将生成一个表格,其中包含按线程活动划分的百分比
emulator
:通用代码执行port
:外部 I/O 活动(套接字 I/O、文件 I/O、子进程)gc
:执行垃圾回收check_io
:检查 I/O 事件other
,aux
:忙等待,管理计时器,所有其他任务sleep
:睡眠(空闲状态)
外部 I/O 状态下的活动百分比很高可能表明节点和/或客户端已达到网络链路容量上限。这可以通过基础设施指标来确认。
睡眠状态下的活动百分比很高可能表明节点负载较轻,或者可用硬件和工作负载的运行时调度器配置欠佳。
内存分配器设置
运行时管理(分配和释放)内存。运行时内存管理是一个复杂的主题,具有许多可调整的参数。本节仅涵盖基础知识。
内存从称为载体(carrier)的较大预分配区域中的块中分配。控制载体大小、块大小、内存分配策略等的设置通常称为分配器设置。
根据使用的分配器设置和工作负载,RabbitMQ 可能会遇到不同程度的内存碎片。为您的工作负载找到最佳匹配是一个试验、测量(指标收集)和错误的过程。请注意,一定程度的碎片是不可避免的。
以下是默认使用的分配器参数
RABBITMQ_DEFAULT_ALLOC_ARGS="+MBas ageffcbf +MHas ageffcbf +MBlmbcs 512 +MHlmbcs 512 +MMmcs 30"
不要覆盖 RABBITMQ_DEFAULT_ALLOC_ARGS
,而是将应覆盖的标志添加到 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
。它们将优先于默认标志。因此,使用以下 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
值启动的节点
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+MHlmbcs 8192"
将在以下有效分配器设置中使用
"+MBas ageffcbf +MHas ageffcbf +MBlmbcs 512 +MHlmbcs 8192 +MMmcs 30"
对于某些工作负载,较大的预分配区域会降低分配率和内存碎片。要配置节点使用 1 GB 的预分配区域,请使用 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
将 +MMscs 1024
添加到 VM 启动参数
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+MMscs 1024"
该值以 MB 为单位。以下示例将预分配一个更大的 4 GB 区域
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+MMscs 4096"
要了解其他可用设置,请参阅有关分配器的运行时文档。
打开文件句柄限制
大多数操作系统限制可以同时打开的文件句柄数。当 OS 进程(例如 RabbitMQ 的 Erlang VM)达到限制时,它将无法打开任何新文件或接受更多 TCP 连接。
此限制在网络指南中详细介绍。请注意,它不能使用 Erlang VM 标志进行配置。
节点间通信缓冲区大小
一对节点之间的节点间流量使用 TCP 连接,该连接具有称为节点间通信缓冲区的缓冲区。其大小默认为 128 MB。对于大多数工作负载来说,这是一个合理的默认值。在某些环境中,节点间流量可能非常大,并达到缓冲区的容量。默认值不适用的其他工作负载涉及传输非常大的消息(例如,数百兆字节),这些消息不适合缓冲区。
在这种情况下,可以使用 RABBITMQ_DISTRIBUTION_BUFFER_SIZE
环境变量或 +zdbbl
VM 标志增加该值。该值以千字节为单位
RABBITMQ_DISTRIBUTION_BUFFER_SIZE=192000
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+zdbbl 192000"
当缓冲区徘徊在满容量附近时,节点将记录警告,其中提到繁忙的分配端口 (busy_dist_port
)
2019-04-06 22:48:19.031 [warning] <0.242.0> rabbit_sysmon_handler busy_dist_port <0.1401.0>
增加缓冲区大小可能有助于提高吞吐量和/或减少延迟。
Erlang 进程限制
运行时对节点上可以存在的 Erlang 进程(“轻量级线程”)的数量有限制。默认值约为 100 万。在大多数环境中,这足以提供广泛的安全边际。
具有特别大量并发连接或大量队列(例如,数十万)的环境可能需要调整此限制。这可以使用 RABBITMQ_MAX_NUMBER_OF_PROCESSES
环境变量完成,这是一种设置 +P
Erlang VM 标志的便捷方法
RABBITMQ_MAX_NUMBER_OF_PROCESSES=2000000
要直接设置标志,请使用 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
环境变量
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+P 2000000"
Atom 使用量
与Erlang 进程限制类似,运行时对节点上可以存在的 atom 数量有限制。RabbitMQ 节点使用默认值 500 万。此限制应足以满足大多数用例。但是,在具有大量仲裁队列的环境中,可能需要增加限制。建议不要使用此类工作负载。
为了增加限制,请使用 +t
运行时参数
# sets the limit to 9M
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+t 9000000"
或 RABBITMQ_MAX_NUMBER_OF_ATOMS
环境变量
# sets the limit to 9M
RABBITMQ_MAX_NUMBER_OF_ATOMS=9000000
该值必须是 10 的幂。
Erlang 崩溃转储
当运行时异常终止或收到 SIGUSER1
信号时,它将生成一个名为崩溃转储的本地文件。
该文件包含终止时的某些运行时信息。此文件对于调试某些类型的问题很有用。在具有大内存占用空间的节点上,它也可能变得非常大。
要禁用崩溃转储文件,请将 ERL_CRASH_DUMP_BYTES
环境变量设置为 0。