Skip to content

rabbit_db: Eliminate the delete_queue Khepri transaction#14902

Merged
dumbbell merged 2 commits intomainfrom
remove-delete-queue-transaction
Apr 8, 2026
Merged

rabbit_db: Eliminate the delete_queue Khepri transaction#14902
dumbbell merged 2 commits intomainfrom
remove-delete-queue-transaction

Conversation

@dumbbell
Copy link
Copy Markdown
Collaborator

@dumbbell dumbbell commented Nov 5, 2025

… by using keep_while conditions on bindings and auto-delete exchanges.

Why

The delete_queue transaction's anonymous function has to be extracted by Horus, like any Khepri transaction. This is an expensive operation, but Horus uses caching to avoid most work after the first extraction.

Unfortunately, even with this caching, this transaction is still very expensive when there are massive simultaneous deletions of queues. For instance when the queues' lifetime is linked to that of many clients, and all these clients get disconnected at once.

How

This patch removes the transaction entirely. Instead, it uses keep_while conditions on bindings and auto-delete exchanges to let Khepri handle the deletion of semantically related tree nodes. RabbitMQ just has to make a simle "delete this queue" command.

To maintain backward compatibility, we introduce the replaced_delete_queue_transaction feature flag. Its enable callback will take care of rewriting all bindings and auto-delete exchanges record in the store to add the new keep_while conditions.

The binding deletion transaction is also simplified because it benefits from the keep_while conditions. We may be able to replace this transaction is the future as well in the same manner.

@dumbbell dumbbell self-assigned this Nov 5, 2025
@mergify mergify Bot added the make label Nov 5, 2025
@dumbbell dumbbell force-pushed the remove-delete-queue-transaction branch from 082e24d to 3a75b6c Compare November 6, 2025 21:24
@the-mikedavis
Copy link
Copy Markdown
Collaborator

I was looking into eliminating the transaction for queue deletion a while back but I didn't get the changes over the finish line. I just pushed up the branch I was working on: https://github.com/rabbitmq/rabbitmq-server/tree/md/khepri-q-delete-command. It's quite old but maybe it has some interesting leads for this branch. I also looked into using stored procedures where we use transactions now - wouldn't help us with the BEAM file changes in OTP 28 but it avoided some performance impacts. The code-server work for transactions is expensive but also the size of transaction commands can be quite large (the compiled module binary + env) and we could do a lot less work with commands + keep-while conditions. But, if I am remembering correctly, we would need some sort of migration for existing Khepri DBs to transition from transactions to keep-while and regular commands so that they could add the keep-while conditions.

@dumbbell
Copy link
Copy Markdown
Collaborator Author

dumbbell commented Nov 7, 2025

But, if I am remembering correctly, we would need some sort of migration for existing Khepri DBs to transition from transactions to keep-while and regular commands so that they could add the keep-while conditions.

Yes, exactly. This patch is incomplete on purpose (the needed feature flag is a simple hard-coded true for now): I just want to validate the solution first, because updating all bindings and auto-delete exchanges is non-trivial.

Thank you very much for sharing your work! I will take a look at it :-)

@dumbbell dumbbell force-pushed the remove-delete-queue-transaction branch 7 times, most recently from c49b2d4 to a3fa372 Compare March 24, 2026 13:56
@dumbbell dumbbell changed the title (to be written) rabbit_db: Eliminate the delete_queue Khepri transaction Mar 24, 2026
@dumbbell
Copy link
Copy Markdown
Collaborator Author

This pull request is ready for review as it now takes care of the upgrade of cluster as well with the replaced_delete_queue_transaction feature flag.

@the-mikedavis: I looked at your branch and incorporated your changes in rabbit_db_binding:delete/2. I used a different approach to support mixed-version clusters, based on a feature flag. Could you please take a look at the result?

@dumbbell dumbbell requested review from mkuratczyk and the-mikedavis and removed request for the-mikedavis March 24, 2026 14:04
@dumbbell dumbbell marked this pull request as ready for review March 24, 2026 14:09
@dumbbell dumbbell marked this pull request as draft March 24, 2026 14:09
@dumbbell dumbbell force-pushed the remove-delete-queue-transaction branch 2 times, most recently from d53fb6c to e4e4f78 Compare March 25, 2026 14:56
dumbbell added a commit that referenced this pull request Mar 26, 2026
[Why]
This wrapper was calling `khepri_adv:delete_many()`, not
`khepri_adv:delete()` as the name was suggesting. They are not the same
function and have not the same behaviour.

This led to a performance issue with the branch that replaces the
"delete queue" transaction by a simple delete (#14902) that was related
to this confusion.

[How]
The wrapper is rename to reflect the Khepri API being called.

While here, add a `rabbit_khepri:adv_delete()` wrapper that calls the
similarily named Khepri API.
dumbbell added a commit that referenced this pull request Mar 26, 2026
[Why]
This wrapper was calling `khepri_adv:delete_many()`, not
`khepri_adv:delete()` as the name was suggesting. They are not the same
function and have not the same behaviour.

This led to a performance issue with the branch that replaces the
"delete queue" transaction by a simple delete (#14902) that was related
to this confusion.

[How]
The wrapper is renamed to reflect the Khepri API being called.

While here, add a `rabbit_khepri:adv_delete()` wrapper that calls the
similarily named Khepri API.
Copy link
Copy Markdown
Collaborator

@the-mikedavis the-mikedavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like what I was thinking of 👍, use keep-while conditions to tie together the bindings and the queue and then examine the deleted nodes in with the delete function from the adv API. I don't think I looked very far into how to make the migration work. The feature flag approach here makes sense to me.

Comment thread deps/rabbit/src/rabbit_core_ff.erl Outdated
Comment thread deps/rabbit/src/rabbit_db_queue.erl Outdated
dumbbell added a commit that referenced this pull request Apr 1, 2026
[Why]
This wrapper was calling `khepri_adv:delete_many()`, not
`khepri_adv:delete()` as the name was suggesting. They are not the same
function and have not the same behaviour.

This led to a performance issue with the branch that replaces the
"delete queue" transaction by a simple delete (#14902) that was related
to this confusion.

[How]
The wrapper is renamed to reflect the Khepri API being called.

While here, add a `rabbit_khepri:adv_delete()` wrapper that calls the
similarily named Khepri API.
mergify Bot pushed a commit that referenced this pull request Apr 1, 2026
[Why]
This wrapper was calling `khepri_adv:delete_many()`, not
`khepri_adv:delete()` as the name was suggesting. They are not the same
function and have not the same behaviour.

This led to a performance issue with the branch that replaces the
"delete queue" transaction by a simple delete (#14902) that was related
to this confusion.

[How]
The wrapper is renamed to reflect the Khepri API being called.

While here, add a `rabbit_khepri:adv_delete()` wrapper that calls the
similarily named Khepri API.

(cherry picked from commit 0d3edce)
mergify Bot pushed a commit that referenced this pull request Apr 1, 2026
[Why]
This wrapper was calling `khepri_adv:delete_many()`, not
`khepri_adv:delete()` as the name was suggesting. They are not the same
function and have not the same behaviour.

This led to a performance issue with the branch that replaces the
"delete queue" transaction by a simple delete (#14902) that was related
to this confusion.

[How]
The wrapper is renamed to reflect the Khepri API being called.

While here, add a `rabbit_khepri:adv_delete()` wrapper that calls the
similarily named Khepri API.

(cherry picked from commit 0d3edce)
(cherry picked from commit 77cdf87)
@dumbbell dumbbell force-pushed the remove-delete-queue-transaction branch 2 times, most recently from da0bf28 to f0059fa Compare April 1, 2026 14:51
@dumbbell dumbbell requested a review from the-mikedavis April 1, 2026 19:52
@dumbbell
Copy link
Copy Markdown
Collaborator Author

dumbbell commented Apr 7, 2026

@the-mikedavis: If you don’t have any more comments, are you ok if I mark this branch as ready for review and merge it?

Copy link
Copy Markdown
Collaborator

@the-mikedavis the-mikedavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me, thanks for bringing this work over the finish line! I expect we would will see really nice improvements in scenarios where we delete very many queues. If I remember correctly there is a setup with MQTT where this happens fairly often?

@dumbbell
Copy link
Copy Markdown
Collaborator Author

dumbbell commented Apr 8, 2026

Thank you! This is the case when many MQTT clients are disconnected simultaneously for instance. This might be what you are referring to.

dumbbell added 2 commits April 8, 2026 08:41
... by using `keep_while` conditions on bindings and auto-delete
exchanges.

[Why]
The `delete_queue` transaction's anonymous function has to be extracted
by Horus, like any Khepri transaction. This is an expensive operation,
but Horus uses caching to avoid most work after the first extraction.

Unfortunately, even with this caching, this transaction is still very
expensive when there are massive simultaneous deletions of queues. For
instance when the queues' lifetime is linked to that of many clients,
and all these clients get disconnected at once.

[How]
This patch removes the transaction entirely. Instead, it uses
`keep_while` conditions on bindings and auto-delete exchanges to let
Khepri handle the deletion of semantically related tree nodes. RabbitMQ
just has to make a simle "delete this queue" command.

To maintain backward compatibility, we introduce the
`tie_binding_to_dest_with_keep_while_cond` feature flag. Its `enable`
callback will take care of rewriting all bindings and auto-delete
exchanges record in the store to add the new `keep_while` conditions.

The binding deletion transaction is also simplified because it benefits
from the `keep_while` conditions. We may be able to replace this
transaction is the future as well in the same manner.
@dumbbell dumbbell force-pushed the remove-delete-queue-transaction branch from f0059fa to de43879 Compare April 8, 2026 06:41
@dumbbell dumbbell marked this pull request as ready for review April 8, 2026 06:53
@dumbbell dumbbell merged commit 46431b4 into main Apr 8, 2026
185 checks passed
@dumbbell dumbbell deleted the remove-delete-queue-transaction branch April 8, 2026 06:53
@dumbbell dumbbell added this to the 4.4.0 milestone Apr 8, 2026
dumbbell added a commit that referenced this pull request Apr 8, 2026
rabbit_db: Eliminate the `delete_queue` Khepri transaction (backport #14902)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants