<commit_before># Lazy Queues

## <a id="overview" class="anchor" href="#overview">Overview</a>

Since **RabbitMQ 3.6.0**, the broker has the concept of **Lazy Queues** -
queues that move their contents to disk as early as practically possible,
and only load them in RAM when requested by consumers,
therefore the lazy denomination.

One of the main goals of lazy queues is to be able to support very
long queues (many millions of messages).  Queues can become very long
for various reasons:

<ul class="plain">
  <li>consumers are offline / have crashed / are down for maintenance</li>
  <li>there is a sudden message ingress spike, producers are outpacing consumers</li>
  <li>consumers are slower than normal</li>
</ul>

By default, queues keep an in-memory cache of messages that is filled up as messages are published into RabbitMQ.
The idea of this cache is to be able to deliver messages to consumers as fast as possible.
Note that persistent messages can be written to disk as they enter the broker **and** kept in RAM at the same time.

Whenever the broker [considers it needs to free up memory](memory.html), messages from this cache will be [paged out to disk](persistence-conf.html).
Paging a batch of messages to disk takes time and blocks the queue process,
making it unable to receive new messages while it's paging.
Even though recent versions of RabbitMQ improved the paging algorithm,
the situation is still not ideal for use cases where you have
many millions on messages in the queue that might need to be paged out.

Lazy queues attempt to move messages to disk as early as practically possible.
This means significantly fewer messages are kept in RAM in the majority of cases under normal operation.
This comes at a cost of increased disk I/O.

## <a id="configuration" class="anchor" href="#configuration">Making a Queue Lazy</a>

Queues can be made to run in `default` mode or `lazy` mode by:

<ul class="plain">
  <li>setting the mode via <code>queue.declare</code> arguments</li>
  <li>applying a queue <a href="parameters.html#policies">policy</a></li>
</ul>

When both a [policy](parameters.html) and queue arguments specify a queue mode, the queue argument has priority over the policy value.

If a queue mode is set via an optional argument at the time of declaration,
it can only be changed by deleting the queue, and re-declaring it later with a different argument.

### Using Arguments at the Time of Declaration

The queue mode can be set by supplying the `x-queue-mode` queue declaration argument with a string specifying the desired mode.
Valid modes are:

<ul class="plain">
  <li><code>"default"</code></li>
  <li><code>"lazy"</code></li>
</ul>

If no mode is specified during declare, then `"default"` is assumed.
The `default` mode is the behaviour already present in pre 3.6.0 versions of the broker,
so there are no breaking changes in this regard.

This example in Java declares a queue with the queue mode set to `"lazy"`:

<pre class="lang-java">
  Map&lt;String, Object> args = new HashMap&lt;String, Object>();
  args.put("x-queue-mode", "lazy");
  channel.queueDeclare("myqueue", false, false, false, args);
</pre>

### Using a policy

To specify a queue mode using a policy, add the key `queue-mode` to a policy definition, e.g.:

<table>
  <tr>
    <th>rabbitmqctl</th>
    <td>
      <pre>rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"lazy"}' --apply-to queues</pre>
    </td>
  </tr>
  <tr>
    <th>rabbitmqctl (Windows)</th>
    <td>
      <pre>rabbitmqctl set_policy Lazy "^lazy-queue$" "{""queue-mode"":""lazy""}" --apply-to queues</pre>
    </td>
  </tr>
</table>

This ensures the queue called `lazy-queue` will work in the `lazy` mode.

Policies can also be defined via [management UI](management.html).

### Changing Queue Mode at Runtime

If queue mode was configured via a policy,
it is possible to change it at runtime without the need of deleting and re-declaring the queue.
To make a queue named "lazy-queue" use the default (non-lazy) mode, update its matching policy
to specify a different `queue-mode`:

<table>
  <tr>
    <th>rabbitmqctl</th>
    <td>
      <pre>rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"default"}' --apply-to queues</pre>
    </td>
  </tr>
  <tr>
    <th>rabbitmqctl (Windows)</th>
    <td>
      <pre>rabbitmqctl set_policy Lazy "^lazy-queue$" "{""queue-mode"":""default""}" --apply-to queues</pre>
    </td>
  </tr>
</table>

## <a id="performance" class="anchor" href="#performance">Performance Considerations for Lazy Queues</a>

### Disk Utilization

A lazy queue will move its messages to disk as soon as practically possible, even if the message was published
as transient by the publisher. This generally will result in higher disk I/O utilisation.

A regular queue will [keep messages in memory for longer](memory.html).
This will result in delayed disk I/O which is less even (has more spikes)
since more data will need to be written to disk at once.

### RAM Utilization

While it's impossible to provide accurate numbers every use
case, this is a simplistic test that showcases the difference in RAM
utilization between a regular &amp; a lazy queue:

| Number of messages | Message body size | Message type | Producers | Consumers |
| -                  | -                 | -            | -         | -         |
| 1,000,000          | 1,000 bytes       | persistent   | 1         | 0         |<commit_msg>Recommend policies for setting classic queue mode<commit_after># Lazy Queues

## <a id="overview" class="anchor" href="#overview">Overview</a>

Since **RabbitMQ 3.6.0**, the broker has the concept of **Lazy Queues** -
queues that move their contents to disk as early as practically possible,
and only load them in RAM when requested by consumers,
therefore the lazy denomination.

One of the main goals of lazy queues is to be able to support very
long queues (many millions of messages).  Queues can become very long
for various reasons:

<ul class="plain">
  <li>consumers are offline / have crashed / are down for maintenance</li>
  <li>there is a sudden message ingress spike, producers are outpacing consumers</li>
  <li>consumers are slower than normal</li>
</ul>

By default, queues keep an in-memory cache of messages that is filled up as messages are published into RabbitMQ.
The idea of this cache is to be able to deliver messages to consumers as fast as possible.
Note that persistent messages can be written to disk as they enter the broker **and** kept in RAM at the same time.

Whenever the broker [considers it needs to free up memory](memory.html), messages from this cache will be [paged out to disk](persistence-conf.html).
Paging a batch of messages to disk takes time and blocks the queue process,
making it unable to receive new messages while it's paging.
Even though recent versions of RabbitMQ improved the paging algorithm,
the situation is still not ideal for use cases where you have
many millions on messages in the queue that might need to be paged out.

Lazy queues attempt to move messages to disk as early as practically possible.
This means significantly fewer messages are kept in RAM in the majority of cases under normal operation.
This comes at a cost of increased disk I/O.

## <a id="configuration" class="anchor" href="#configuration">Making a Queue Lazy</a>

Queues can be made to run in `default` mode or `lazy` mode by:

<ul class="plain">
  <li>applying a queue <a href="parameters.html#policies">policy</a> (recommended)</li>
  <li>setting the mode via <code>queue.declare</code> arguments</li>
</ul>

When both a [policy](parameters.html) and queue arguments specify a queue mode,
the queue argument has priority over the policy value if both are specified.

If a queue mode is set via an optional argument at the time of declaration,
it can only be changed by deleting the queue, and re-declaring it later with a different argument.

### Using a policy

To specify a queue mode using a policy, add the key `queue-mode` to a policy definition, e.g.:

<table>
  <tr>
    <th>rabbitmqctl</th>
    <td>
      <pre>rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"lazy"}' --apply-to queues</pre>
    </td>
  </tr>
  <tr>
    <th>rabbitmqctl (Windows)</th>
    <td>
      <pre>rabbitmqctl set_policy Lazy "^lazy-queue$" "{""queue-mode"":""lazy""}" --apply-to queues</pre>
    </td>
  </tr>
</table>

This ensures the queue called `lazy-queue` will work in the `lazy` mode.

Policies can also be defined via [management UI](management.html).

### Changing Queue Mode at Runtime

If queue mode was configured via a policy,
it is possible to change it at runtime without the need of deleting and re-declaring the queue.
To make a queue named "lazy-queue" use the default (non-lazy) mode, update its matching policy
to specify a different `queue-mode`:

<table>
  <tr>
    <th>rabbitmqctl</th>
    <td>
      <pre>rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"default"}' --apply-to queues</pre>
    </td>
  </tr>
  <tr>
    <th>rabbitmqctl (Windows)</th>
    <td>
      <pre>rabbitmqctl set_policy Lazy "^lazy-queue$" "{""queue-mode"":""default""}" --apply-to queues</pre>
    </td>
  </tr>
</table>

### Using Arguments at the Time of Declaration

The queue mode can be set by supplying the `x-queue-mode` queue declaration argument with a string specifying the desired mode.
Valid modes are:

<ul class="plain">
  <li><code>"default"</code></li>
  <li><code>"lazy"</code></li>
</ul>

If no mode is specified during declare, then `"default"` is assumed.
The `default` mode is the behaviour already present in pre 3.6.0 versions of the broker,
so there are no breaking changes in this regard.

This example in Java declares a queue with the queue mode set to `"lazy"`:

<pre class="lang-java">
  Map&lt;String, Object> args = new HashMap&lt;String, Object>();
  args.put("x-queue-mode", "lazy");
  channel.queueDeclare("myqueue", false, false, false, args);
</pre>

## <a id="performance" class="anchor" href="#performance">Performance Considerations for Lazy Queues</a>

### Disk Utilization

A lazy queue will move its messages to disk as soon as practically possible, even if the message was published
as transient by the publisher. This generally will result in higher disk I/O utilisation.

A regular queue will [keep messages in memory for longer](memory.html).
This will result in delayed disk I/O which is less even (has more spikes)
since more data will need to be written to disk at once.

### RAM Utilization

While it's impossible to provide accurate numbers every use
case, this is a simplistic test that showcases the difference in RAM
utilization between a regular &amp; a lazy queue:

| Number of messages | Message body size | Message type | Producers | Consumers |
| -                  | -                 | -            | -         | -         |
| 1,000,000          | 1,000 bytes       | persistent   | 1         | 0         |
{'fraction_non_alphanumeric': 0.09998172180588558, 'fraction_numerical': 0.003472856881740084, 'mean_word_length': 3.8420353982300885, 'pattern_counts': {'":': 8, '<': 147, '<?xml version=': 0, '>': 151, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2928733', 'n_tokens_mistral': 3215, 'n_tokens_neox': 3101, 'n_words': 1483}