This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push: new 15b0b0fffa ENHANCEMENT + DOCUMENTATION Performance / reliability setting for RabbitMQ quorum queues (#2121) 15b0b0fffa is described below commit 15b0b0fffac0bcbb460687cee23d108aaba179df Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Fri Mar 15 14:29:33 2024 +0100 ENHANCEMENT + DOCUMENTATION Performance / reliability setting for RabbitMQ quorum queues (#2121) * [ENHANCEMENT] Rabbit Quorum queue: set delivery limits Setting a delivery limit can prevent RabbitMQ outage if message processing fails. Read https://www.rabbitmq.com/docs/quorum-queues#poison-message-handling * [ENHANCEMENT] Rabbit Quorum queue: document performance setting Was advised on gitter --------- Co-authored-by: Rene Cordier <rcord...@linagora.com> --- .../james/backends/rabbitmq/QueueArguments.java | 5 ++++ .../backends/rabbitmq/RabbitMQConfiguration.java | 29 ++++++++++++++++++++-- .../modules/ROOT/pages/configure/rabbitmq.adoc | 19 ++++++++++++++ src/site/xdoc/server/config-rabbitmq.xml | 18 ++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/QueueArguments.java b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/QueueArguments.java index 62a7c86e70..5d782d059a 100644 --- a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/QueueArguments.java +++ b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/QueueArguments.java @@ -65,6 +65,11 @@ public class QueueArguments { return this; } + public Builder deliveryLimit(long deliveryLimit) { + arguments.put("x-delivery-limit", deliveryLimit); + return this; + } + public ImmutableMap<String, Object> build() { return arguments.build(); } diff --git a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConfiguration.java b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConfiguration.java index c7963e27d0..092804891e 100644 --- a/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConfiguration.java +++ b/backends-common/rabbitmq/src/main/java/org/apache/james/backends/rabbitmq/RabbitMQConfiguration.java @@ -307,6 +307,7 @@ public class RabbitMQConfiguration { private static final String SSL_KEY_STORE_PATH = "ssl.keystore"; private static final String SSL_KEY_STORE_PASSWORD = "ssl.keystore.password"; private static final String QUEUE_TTL = "notification.queue.ttl"; + private static final String QUEUE_DELIVERY_LIMIT = "quorum.queues.delivery.limit"; private static final String EVENT_BUS_NOTIFICATION_DURABILITY_ENABLED = "event.bus.notification.durability.enabled"; private static final String EVENT_BUS_PUBLISH_CONFIRM_ENABLED = "event.bus.publish.confirm.enabled"; private static final String TASK_QUEUE_CONSUMER_TIMEOUT = "task.queue.consumer.timeout"; @@ -403,6 +404,7 @@ public class RabbitMQConfiguration { private Optional<Boolean> useSsl; private Optional<Boolean> useSslManagement; private Optional<Boolean> useQuorumQueues; + private Optional<Integer> quorumQueueDeliveryLimit; private Optional<Integer> quorumQueueReplicationFactor; private Optional<SSLConfiguration> sslConfiguration; private Optional<Long> queueTTL; @@ -426,6 +428,7 @@ public class RabbitMQConfiguration { this.useSslManagement = Optional.empty(); this.sslConfiguration = Optional.empty(); this.useQuorumQueues = Optional.empty(); + this.quorumQueueDeliveryLimit = Optional.empty(); this.quorumQueueReplicationFactor = Optional.empty(); this.hosts = ImmutableList.builder(); this.queueTTL = Optional.empty(); @@ -445,6 +448,17 @@ public class RabbitMQConfiguration { return this; } + public Builder quorumQueueDeliveryLimit(int limit) { + Preconditions.checkArgument(limit > 0, "'quorumQueueDeliveryLimit' should be strictly positive"); + this.quorumQueueDeliveryLimit = Optional.of(limit); + return this; + } + + public Builder quorumQueueDeliveryLimit(Optional<Integer> limit) { + limit.ifPresent(this::quorumQueueDeliveryLimit); + return this; + } + public Builder connectionTimeoutInMs(int connectionTimeout) { this.connectionTimeoutInMs = Optional.of(connectionTimeout); return this; @@ -551,6 +565,7 @@ public class RabbitMQConfiguration { useSslManagement.orElse(false), sslConfiguration.orElse(defaultBehavior()), useQuorumQueues.orElse(false), + quorumQueueDeliveryLimit, quorumQueueReplicationFactor.orElse(DEFAULT_QUORUM_QUEUE_REPLICATION_FACTOR), hostsDefaultingToUri(), queueTTL, @@ -605,6 +620,7 @@ public class RabbitMQConfiguration { .orElse(ImmutableList.of()); Optional<Long> queueTTL = Optional.ofNullable(configuration.getLong(QUEUE_TTL, null)); + Optional<Integer> quorumQueueDeliveryLimit = Optional.ofNullable(configuration.getInteger(QUEUE_DELIVERY_LIMIT, null)); Optional<String> vhost = Optional.ofNullable(configuration.getString(VHOST, null)); @@ -622,6 +638,7 @@ public class RabbitMQConfiguration { .sslConfiguration(sslConfiguration(configuration)) .useQuorumQueues(useQuorumQueues) .quorumQueueReplicationFactor(quorumQueueReplicationFactor) + .quorumQueueDeliveryLimit(quorumQueueDeliveryLimit) .hosts(hosts) .queueTTL(queueTTL) .eventBusNotificationDurabilityEnabled(configuration.getBoolean(EVENT_BUS_NOTIFICATION_DURABILITY_ENABLED, null)) @@ -692,6 +709,7 @@ public class RabbitMQConfiguration { private final Boolean useSslManagement; private final SSLConfiguration sslConfiguration; private final boolean useQuorumQueues; + private final Optional<Integer> quorumQueueDeliveryLimit; private final int quorumQueueReplicationFactor; private final List<Host> hosts; private final ManagementCredentials managementCredentials; @@ -704,7 +722,7 @@ public class RabbitMQConfiguration { private RabbitMQConfiguration(URI uri, URI managementUri, ManagementCredentials managementCredentials, int maxRetries, int minDelayInMs, int connectionTimeoutInMs, int channelRpcTimeoutInMs, int handshakeTimeoutInMs, int shutdownTimeoutInMs, int networkRecoveryIntervalInMs, Boolean useSsl, Boolean useSslManagement, SSLConfiguration sslConfiguration, - boolean useQuorumQueues, int quorumQueueReplicationFactor, List<Host> hosts, Optional<Long> queueTTL, + boolean useQuorumQueues, Optional<Integer> quorumQueueDeliveryLimit, int quorumQueueReplicationFactor, List<Host> hosts, Optional<Long> queueTTL, boolean eventBusPublishConfirmEnabled, boolean eventBusNotificationDurabilityEnabled, Optional<String> vhost, Duration taskQueueConsumerTimeout) { this.uri = uri; @@ -721,6 +739,7 @@ public class RabbitMQConfiguration { this.useSslManagement = useSslManagement; this.sslConfiguration = sslConfiguration; this.useQuorumQueues = useQuorumQueues; + this.quorumQueueDeliveryLimit = quorumQueueDeliveryLimit; this.quorumQueueReplicationFactor = quorumQueueReplicationFactor; this.hosts = hosts; this.queueTTL = queueTTL; @@ -786,6 +805,7 @@ public class RabbitMQConfiguration { QueueArguments.Builder builder = QueueArguments.builder(); if (allowQuorum && useQuorumQueues) { builder.quorumQueue().replicationFactor(quorumQueueReplicationFactor); + quorumQueueDeliveryLimit.ifPresent(builder::deliveryLimit); } return builder; } @@ -823,6 +843,10 @@ public class RabbitMQConfiguration { return taskQueueConsumerTimeout; } + public Optional<Integer> getQuorumQueueDeliveryLimit() { + return quorumQueueDeliveryLimit; + } + @Override public final boolean equals(Object o) { if (o instanceof RabbitMQConfiguration) { @@ -841,6 +865,7 @@ public class RabbitMQConfiguration { && Objects.equals(this.useSsl, that.useSsl) && Objects.equals(this.useQuorumQueues, that.useQuorumQueues) && Objects.equals(this.quorumQueueReplicationFactor, that.quorumQueueReplicationFactor) + && Objects.equals(this.quorumQueueDeliveryLimit, that.quorumQueueDeliveryLimit) && Objects.equals(this.useSslManagement, that.useSslManagement) && Objects.equals(this.sslConfiguration, that.sslConfiguration) && Objects.equals(this.hosts, that.hosts) @@ -855,7 +880,7 @@ public class RabbitMQConfiguration { @Override public final int hashCode() { - return Objects.hash(uri, managementUri, maxRetries, minDelayInMs, connectionTimeoutInMs, quorumQueueReplicationFactor, useQuorumQueues, hosts, + return Objects.hash(uri, managementUri, maxRetries, minDelayInMs, connectionTimeoutInMs, quorumQueueReplicationFactor, quorumQueueDeliveryLimit, useQuorumQueues, hosts, channelRpcTimeoutInMs, handshakeTimeoutInMs, shutdownTimeoutInMs, networkRecoveryIntervalInMs, managementCredentials, useSsl, useSslManagement, sslConfiguration, queueTTL, eventBusPublishConfirmEnabled, eventBusNotificationDurabilityEnabled, vhost, taskQueueConsumerTimeout); } diff --git a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/rabbitmq.adoc b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/rabbitmq.adoc index 0910b2d61e..c4089e29c8 100644 --- a/server/apps/distributed-app/docs/modules/ROOT/pages/configure/rabbitmq.adoc +++ b/server/apps/distributed-app/docs/modules/ROOT/pages/configure/rabbitmq.adoc @@ -87,6 +87,10 @@ False (default value) results in the usage of classic queues. | quorum.queues.replication.factor | Strictly positive integer. The replication factor to use when creating quorum queues. +| quorum.queues.delivery.limit +| Strictly positive integer. Value for x-delivery-limit queue parameter, default to none. Setting a delivery limit can +prevent RabbitMQ outage if message processing fails. Read https://www.rabbitmq.com/docs/quorum-queues#poison-message-handling + | hosts | Optional, default to the host specified as part of the URI. Allow creating cluster aware connections. @@ -107,6 +111,21 @@ You still need to specify the vhost in the uri parameter. |=== +== Tuning RabbitMQ for quorum queue use + +While quorum queues are great at preserving your data and enabling High Availability, they demand more resources and +a greater care than regular RabbitMQ queues. + +See link:https://www.rabbitmq.com/docs/quorum-queues#performance-tuning[this section of RabbitMQ documentation regarding RabbitMQ quroum queue performance tunning]. + + - Provide decent amount of RAM memory to RabbitMQ. 4GB is a good start. + - Setting a delivery limit is advised as looping messages can cause extreme memory consumptions onto quorum queues. + - Set up Raft for small messages: + +.... +raft.segment_max_entries = 32768 +.... + == RabbitMQ MailQueue Configuration James mail queue is a component acting like a queue where it can enqueue and dequeue mails. diff --git a/src/site/xdoc/server/config-rabbitmq.xml b/src/site/xdoc/server/config-rabbitmq.xml index 6bbf9a6ea9..cc651d1ef7 100644 --- a/src/site/xdoc/server/config-rabbitmq.xml +++ b/src/site/xdoc/server/config-rabbitmq.xml @@ -120,6 +120,10 @@ <dt><strong>quorum.queues.replication.factor</strong></dt> <dd> Strictly positive integer. The replication factor to use when creating quorum queues.</dd> + <dt><strong>quorum.queues.delivery.limit</strong></dt> + <dd> Strictly positive integer. Value for x-delivery-limit queue parameter, default to none. Setting a delivery limit can + prevent RabbitMQ outage if message processing fails. Read https://www.rabbitmq.com/docs/quorum-queues#poison-message-handling</dd> + <dt><strong>hosts</strong></dt> <dd>Optional, default to the host specified as part of the URI. Allow creating cluster aware connections. @@ -146,7 +150,21 @@ </dd> </dl> </section> + <section name="Tuning RabbitMQ for quorum queue use"> + <p>While quorum queues are great at preserving your data and enabling High Availability, they demand more resources and + a greater care than regular RabbitMQ queues.</p> + + <p>See <a href="https://www.rabbitmq.com/docs/quorum-queues#performance-tuning"> + this section of RabbitMQ documentation regarding RabbitMQ quroum queue performance tunning</a>.</p> + <ul> + <li>Provide decent amount of RAM memory to RabbitMQ. 4GB is a good start.</li> + <li>Setting a delivery limit is advised as looping messages can cause extreme memory consumptions onto quorum queues.</li> + <li>Set up Raft for small messages:</li> + </ul> + + <pre><code>raft.segment_max_entries = 32768</code></pre> + </section> <section name="RabbitMQ MailQueue Configuration"> <p> RabbitMQ MailQueue Configuration --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org