Add mqtt.max_connections per-node connection limit (backport #16367) (backport #16391)#16412
Merged
Conversation
Add the `mqtt.max_connections` configuration key, which sets a
node-wide limit on the number of concurrent MQTT connections.
The limit is checked in `rabbit_mqtt_processor:process_connect/5`
as the first step in the CONNECT packet handler, before
authentication. When exceeded, the broker returns a CONNACK with
reason code `quota_exceeded` (MQTT 5) or return code
`not_authorized` (MQTT 3.x/4).
The active connection count is obtained via
`ets:info(persistent_term:get(?PG_SCOPE), size)`. The MQTT plugin
creates a node-local PG scope in `rabbit_mqtt_sup`; each connection
joins it via `pg:join/3` in `register_client_id/4`, using
`{VHost, ClientId}` as the group key. Since the MQTT spec requires
unique client IDs per vhost, which RabbitMQ enforces, each group
has exactly one member. The PG scope ETS table therefore has one
row per active connection node-wide, covering all listeners and
transports (plain TCP, TLS, and Web MQTT). `ets:info/2` reads this
count in O(1) - important given that MQTT nodes can host a very
large number of connections.
The check runs before `register_client_id/4`, so the current
connection is not yet counted; the limit comparison is `>= Limit`.
When `mqtt.max_connections` is absent, `application:get_env/3`
returns `infinity` and no check is performed.
A `node_connection_limit` test is added to the `limit` group in
`auth_SUITE`.
(cherry picked from commit 9c1683a)
(cherry picked from commit ef7427a)
…nel_closed` This change reduces the polling and message generation frequency to what the sibling tests use. (cherry picked from commit 52b9a29)
`rabbit_mqtt_keepalive:handle/2` returns `{error, _}` when
`inet:getstat/2` fails on an already-closed socket (typically
`einval`). Route these through `network_error/2` so the pending
`{tcp_closed, Socket}` message handles teardown cleanly, instead
of crashing the reader which in turn makes
the test fail.
(cherry picked from commit ee8fedd)
(cherry picked from commit 54b6566)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #16347 (partial - adds
mqtt.max_connections).What this PR does
Adds
mqtt.max_connections, a per-node connection limit for the MQTT plugin. When the limit is reached, the broker sends a CONNACK with return codenot_authorized(MQTT 3.x/4) or reason codequota_exceeded(MQTT 5) and closes the connection.How it works
The limit is checked in
rabbit_mqtt_processor:process_connect/5as the first step in the CONNECT packet handler, before authentication. It does not operate at the Ranch transport layer, so the TCP listen queue is unaffected and Ranch continues accepting connections normally.The active connection count uses
ets:info(persistent_term:get(?PG_SCOPE), size). The MQTT plugin creates a node-local PG scope inrabbit_mqtt_sup; each connection joins it viapg:join/3inregister_client_id/4, using{VHost, ClientId}as the group key. Since the MQTT spec requires unique client IDs per vhost, which RabbitMQ enforces, each group has exactly one member. The PG scope ETS table therefore has one row per active connection node-wide, covering all listeners and transports (plain TCP, TLS, and Web MQTT).ets:info/2reads this count in O(1) - important given that MQTT nodes can host a very large number of connections.The check runs before
register_client_id/4, so the current connection is not yet counted; the limit comparison is>= max_connections.Configuration
mqtt.max_connections = 1000The default is
infinity(no limit). The setting accepts a non-negative integer orinfinity.Testing
Adds
node_connection_limitto thelimitgroup inauth_SUITE. The test sets the limit to 0 via RPC so the first CONNECT attempt is rejected, covering both MQTT v4 and v5 via the existingexpected_connection_limit_error/1helper.This is an automatic backport of pull request #16367 done by [Mergify](https://mergify.com).
This is an automatic backport of pull request #16391 done by [Mergify](https://mergify.com).