Runtime Tuning
Overview
RabbitMQ runs on the Erlang virtual machine and runtime. A compatible version of Erlang must be installed in order to run RabbitMQ.
The Erlang runtime includes a number of components used by RabbitMQ. The most important ones as far as this guide is concerned are
- The Erlang virtual machine executes the code
epmd
resolves node names on a host to an inter-node communication port
This guide will focus on the virtual machine. For an overview of epmd
, please refer to the
Networking guide.
Topics covered include:
- How to configure Erlang VM settings for RabbitMQ nodes
- Runtime schedulers, what they are, how they relate to CPU cores, and so on
- Runtime thread activity metrics: where is scheduler and CPU time spent
- Runtime features that affect CPU utilisation
- How to reduce CPU utilisation on moderately or lightly loaded nodes
- Memory allocator settings
- Open file handle limit
- Inter-node communication buffer size
- Erlang process limit
- Erlang crash dumps
- Atom usage
VM Settings
The Erlang VM has a broad range of options that can be configured that cover process scheduler settings, memory allocation, garbage collection, I/O, and more. Tuning of those flags can significantly change runtime behavior of a node.
Configuring Flags
Most of the settings can be configured using environment variables. A few settings have dedicated variables, others can only be changed using the following generic variables that control what flags are passed by RabbitMQ startup scripts to the Erlang virtual machine.
The generic variables are
RABBITMQ_SERVER_ERL_ARGS
allows all VM flags to be overridden, including the defaults set by RabbitMQ scriptsRABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
allows a set of flags to be appended to the defaults set by RabbitMQ scriptsRABBITMQ_CTL_ERL_ARGS
controls CLI tool VM flags
In most cases RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
is the recommended option. It can be used to override defaults
in a safe manner. For example, if an important flag is omitted from RABBITMQ_SERVER_ERL_ARGS
, runtime performance
characteristics or system limits can be unintentionally affected.
As with other environment variables used by RabbitMQ, RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS
and friends can be set using a separate environment variable file.
CPU Utilisation
CPU utilisation is a workload-specific topic. Generally speaking, when a workload involves more queues, connections and channels than CPU cores, all cores will be used without any configuration necessary.
The runtime provides several features that control how the cores are used.
Runtime Schedulers
Schedulers in the runtime assign work to kernel threads that perform it. They execute code, perform I/O, execute timers and so on. Schedulers have a number of settings that can affect overall system performance, CPU utilisation, latency and other runtime characteristics of a node.
By default the runtime will start one scheduler for one CPU core it detects. Starting with Erlang 23, this takes CPU quotas into account in containerized environments such as Docker and Kubernetes.
The number of schedulers can be explicitly set using the +S
flag. The following example configures
the node to start 4 schedulers even if it detects more cores to be available to it:
RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="+S 4:4"
Most of the time the default behaviour works well. In shared or CPU constrained environments (including containerised ones), explicitly configuring scheduler count may be necessary.
CPU Resource Contention
The runtime assumes that it does not share CPU resources with other tools or tenants. When that's the case, the scheduling mechanism used can become very inefficient and result in significant (up to several orders of magnitude) latency increase for certain operations.
This means that in most cases colocating RabbitMQ nodes with other tools or applying CPU time slicing is highly discouraged and will result in suboptimal performance.