跳至主内容
版本:4.3

运行时调优

概述

RabbitMQ 运行在 Erlang 虚拟机和运行时之上。为了运行 RabbitMQ,必须安装兼容版本的 Erlang

Erlang 运行时包含 RabbitMQ 所使用的多个组件。就本指南而言,最重要的组件是:

本指南将重点介绍虚拟机。有关 epmd 的概述,请参阅网络指南

涵盖的主题包括:

虚拟机设置

Erlang 虚拟机拥有广泛的可配置选项,涵盖了进程调度器设置、内存分配、垃圾回收、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 开始,在 Docker 和 Kubernetes 等容器化环境中,这会考虑 CPU 配额

调度器的数量可以使用 +S 标志显式设置。以下示例配置节点启动 4 个调度器,即使检测到有更多可用核心:

RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+S 4:4"

大多数情况下,默认行为运行良好。在共享或 CPU 受限的环境(包括容器化环境)中,可能需要显式配置调度器数量。

CPU 资源争用

运行时假设它不会与其他工具或租户共享 CPU 资源。如果发生共享,所使用的调度机制可能会变得非常低效,并导致某些操作的延迟显著增加(高达几个数量级)。

这意味着在大多数情况下,强烈建议不要将 RabbitMQ 节点与其他工具放在一起或应用 CPU 时间片分割,否则会导致性能欠佳。

调度器忙等待

当调度器没有工作可执行时,运行时可以将它们置于睡眠状态。使它们重新联机需要一定的代价,因此对于某些工作负载,不这样做可能更有利。

这可以比作一个拥有多条传送带的工厂。当一条传送带没有物品时,它可以停止。但是,一旦有更多工作需要处理,重启它需要时间。或者,可以让传送带预先保持运转一段时间。

默认情况下,RabbitMQ 节点配置运行时调度器以禁用推测性等待。这有利于在给定的连接、通道、会话、队列或流副本上可能存在非活动期的情况。

推测性忙等待通过 +sbwt 及相关运行时标志进行控制。

# This is the default used by modern RabbitMQ versions: it disables speculative
# busy waiting.
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+sbwt none +sbwtdcpu none +sbwtdio none"

禁用推测性等待可降低 CPU 资源有限或突发性 CPU 资源系统上的 CPU 使用率。

要确定调度器在忙等待上花费了多少时间,请参阅线程活动指标。忙等待通常在 toppidstat 等工具的输出中记为系统时间。

调度器与 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 吞吐量不足,当节点忙于等待 I/O 操作完成时,CPU 资源就会被浪费。

对于“中等负载”的系统(其中很大一部分或大部分连接和队列偶尔会空闲),可以应用一些一般性建议。换句话说,在本节中,我们将任何未在其峰值容量附近徘徊的系统视为“中等负载”。

此类系统通常可以通过几个简单的步骤减少其 CPU 足迹。这些建议可以显著降低某些工作负载的 CPU 足迹:例如,请参考此社区案例

收集运行时线程统计信息

收集运行时线程活动统计数据,以了解调度器和 CPU 时间是如何花费的。这是做出明智决策的关键步骤。

关闭推测性调度器忙等待

如果自定义了推测性调度器忙等待,请使用 +sbwt 及相关运行时标志将其禁用。

# This is the default used by modern RabbitMQ versions: it disables speculative
# busy waiting.
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 状态中显著的活动百分比可能表明节点和/或客户端已达到网络链路容量上限。这可以通过基础设施指标来确认。

睡眠状态中显著的活动百分比可能表明节点负载较轻,或者针对可用硬件和工作负载的运行时调度器配置不佳。

内存分配器设置

运行时管理(分配和释放)内存。运行时内存管理是一个复杂的主题,有许多可调参数。本节仅涵盖基础知识。

内存从称为载体 (carriers) 的较大预分配区域中以块的形式分配。控制载体大小、块大小、内存分配策略等的设置通常称为分配器设置。

根据所使用的分配器设置和工作负载,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 GiB (1024 MiB) 的预分配区域,请使用 RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS+MMscs 1024 添加到 VM 启动参数中。

RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+MMscs 1024"

该值以 MiB 为单位。以下示例将预分配一个更大的 4 GiB 区域:

RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+MMscs 4096"

另一个标志 +MMscrpm 控制节点启动时如何预留预分配的内存:

  • 使用 +MMscrpm true(默认),物理内存在节点启动时被预留。
  • 使用 +MMscrpm false,仅预留虚拟地址空间(在 Linux 上,使用 MAP_NORESERVE);物理内存按需分配。

载体大小限制

+MBlmbcs+MHlmbcs(代表“最大多块载体大小”)标志控制运行时分配的内存块(称为载体)可以增长多大。

处理较大消息的工作负载可能会受益于增加此限制。

# Increases binary carrier limit to 2048 KiB (2 MiB)
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+MBlmbcs 2048"

# Increases binary carrier limit to 8192 KiB (8 MiB) for workloads with even larger messages
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+MBlmbcs 8192"

要了解其他可用设置,请参阅有关分配器的运行时文档

打开文件句柄限制

大多数操作系统限制了可以同时打开的文件句柄数量。当 OS 进程(例如 RabbitMQ 的 Erlang VM)达到该限制时,它将无法打开任何新文件或接受更多 TCP 连接。

此限制在网络指南中有详细介绍。请注意,它不能通过 Erlang VM 标志进行配置。

节点间通信缓冲区大小

一对节点之间的节点间流量使用带有缓冲区(称为节点间通信缓冲区)的 TCP 连接。其默认大小为 128 MB。对于大多数工作负载,这是一个合理的默认值。在某些环境中,节点间流量可能非常大,并达到缓冲区的容量。另一个默认值不适用的工作负载涉及传输非常大(例如数百兆字节)且不适合缓冲区内的消息。

在这种情况下,可以使用 RABBITMQ_DISTRIBUTION_BUFFER_SIZE 环境变量或 +zdbbl VM 标志增加该值。该值以千字节 (KB) 为单位:

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"

原子使用量

Erlang 进程限制类似,运行时对节点上可以存在的原子数量有限制。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 信号时,它将生成一个本地文件,称为崩溃转储 (crash dump)

该文件包含终止时某些运行时信息。此文件对于调试某些类型的问题很有用。在内存占用较大的节点上,它也可能变得非常大。

要禁用崩溃转储文件,请将 ERL_CRASH_DUMP_BYTES 环境变量设置为 0。

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