Skip to content

Ensure stable routing for x-modulus-hash exchange (backport #15849)#15859

Merged
ansd merged 3 commits intov4.3.xfrom
mergify/bp/v4.3.x/pr-15849
Mar 27, 2026
Merged

Ensure stable routing for x-modulus-hash exchange (backport #15849)#15859
ansd merged 3 commits intov4.3.xfrom
mergify/bp/v4.3.x/pr-15849

Conversation

@mergify
Copy link
Copy Markdown

@mergify mergify Bot commented Mar 27, 2026

What?

This PR makes routing stable for the x-modulus-hash exchange: If the same destination queues stay bound to the exchange (i.e. do not bind or unbind queues after the "initial setup"), messages with the same domain entity (routing key) will always end up in the same destination queue, even across node restarts.

Move the x-modulus-hash exchange type from rabbitmq_sharding to rabbit since this exchange type is useful even without the sharding plugin.

How?

With Mnesia this was guaranteed due to order_set tables. Khepri introduced a regression since it uses a bag ETS projection table.

This PR simply sorts the destinations before picking the Nth destination.

Why?

Uses cases where message order matters are common. This PR allows to for example bind N quorum queues to an x-modulus-hash exchange instance (the binding keys do not matter) and use the Single Active Consumer (SAC) feature on each quorum queue. This will provide

  • message ordering thanks to stable routing and SAC
  • concurrent consumption: N app instances can process messages in parallel
  • fault tolerance since the broker will deliver messages to another consumer when the active consumer crashes

Using the consistent hash exchange is an alternative, but unnecessarily complex for this use case.

Yet another alternative for this use case is using the murmur3 exchange type (#8319).

Docs:

rabbitmq/rabbitmq-website#2494


This is an automatic backport of pull request #15849 done by [Mergify](https://mergify.com).

ansd added 3 commits March 27, 2026 16:54
 ## What?

This commit makes routing stable for the `x-modulus-hash` exchange:
If the same destination queues stay bound to the exchange (i.e. do not
bind or unbind queues after the "initial setup"), messages with the same
domain entity (routing key) will always end up in the same destination queue,
even across node restarts.

 ## How?

With Mnesia this was guaranteed due to order_set tables. Khepri
introduced a regression since it uses a bag ETS projection table.

This commit simply sorts the destinations before picking the Nth
destination.

 ## Why?

Uses cases where message order matters are common. This commit allows to
for example bind N quorum queues to an `x-modulus-hash` exchange
instance (the binding key doesn't matter) and use the Single Active
Consumer (SAC) feature on each quorum queue. This will provide
* message ordering thanks to stable routing and SAC
* concurrent consumption: N app instances can process messages in parallel
* fault tolerance since the broker will deliver messages to another consumer
  when the active consumer crashes

Using the consistent hash exchange is an alternative, but unnecessarily complex
for this use case.

Yet another alternative for this use case is using the murmur3 exchange
type (#8319).

(cherry picked from commit e7dfae5)
Move the x-modulus-hash exchange type from rabbitmq_sharding to rabbit
since this exchange type is useful even without the sharding plugin.

(cherry picked from commit 1229705)
This commit adds a test case to explicitly verify that the
`x-modulus-hash` exchange supports weighted routing.

Because the exchange uses `lists:sort/1` instead of `lists:usort/1`
when fetching the bound destinations, a user can bind the exact same
queue multiple times to the exchange (using different dummy binding
keys) to increase its weight. If a queue is bound N times, it will
appear N times in the destination list, giving it a proportionally
higher chance of receiving messages.

(cherry picked from commit d7b3d19)
@mergify mergify Bot assigned ansd Mar 27, 2026
@mergify mergify Bot added the make label Mar 27, 2026
@ansd ansd merged commit 564e1b2 into v4.3.x Mar 27, 2026
184 checks passed
@ansd ansd deleted the mergify/bp/v4.3.x/pr-15849 branch March 27, 2026 17:32
@michaelklishin michaelklishin added this to the 4.3.0 milestone Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants