Skip to content

Commit 7a7da0f

Browse files
Merge pull request #10476 from rabbitmq/SimonUnge-check_consumer_count
Rework consumer sample deletion when a channel is closed
2 parents 6115f8f + dad9379 commit 7a7da0f

File tree

2 files changed

+34
-17
lines changed

2 files changed

+34
-17
lines changed

deps/rabbit/src/rabbit_channel.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,8 @@ terminate(_Reason,
825825
end, CM),
826826
rabbit_core_metrics:channel_closed(self()),
827827
rabbit_event:notify(channel_closed, [{pid, self()},
828-
{user_who_performed_action, Username}]),
828+
{user_who_performed_action, Username},
829+
{consumer_count, maps:size(CM)}]),
829830
case rabbit_confirms:size(State#ch.unconfirmed) of
830831
0 -> ok;
831832
NumConfirms ->
@@ -2860,4 +2861,3 @@ maybe_decrease_global_publishers(#ch{publishing_mode = true}) ->
28602861

28612862
is_global_qos_permitted() ->
28622863
rabbit_deprecated_features:is_permitted(global_qos).
2863-

deps/rabbitmq_management_agent/src/rabbit_mgmt_metrics_gc.erl

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
2020
code_change/3]).
2121

22+
-define(LARGE_CONSUMER_COUNT, 1000).
23+
2224
name(EventType) ->
2325
list_to_atom((atom_to_list(EventType) ++ "_metrics_gc")).
2426

@@ -42,7 +44,8 @@ handle_cast({event, #event{type = connection_closed, props = Props}},
4244
handle_cast({event, #event{type = channel_closed, props = Props}},
4345
State = #state{basic_i = BIntervals}) ->
4446
Pid = pget(pid, Props),
45-
remove_channel(Pid, BIntervals),
47+
ConsumerCount = pget(consumer_count, Props),
48+
remove_channel(Pid, ConsumerCount, BIntervals),
4649
{noreply, State};
4750
handle_cast({event, #event{type = consumer_deleted, props = Props}}, State) ->
4851
remove_consumer(Props),
@@ -82,13 +85,13 @@ remove_connection(Id, BIntervals) ->
8285
delete_samples(connection_stats_coarse_conn_stats, Id, BIntervals),
8386
ok.
8487

85-
remove_channel(Id, BIntervals) ->
88+
remove_channel(Id, ConsumerCount, BIntervals) ->
8689
ets:delete(channel_created_stats, Id),
8790
ets:delete(channel_stats, Id),
8891
delete_samples(channel_process_stats, Id, BIntervals),
8992
delete_samples(channel_stats_fine_stats, Id, BIntervals),
9093
delete_samples(channel_stats_deliver_stats, Id, BIntervals),
91-
index_delete(consumer_stats, channel, Id),
94+
index_delete(consumer_stats, {channel, ConsumerCount}, Id),
9295
index_delete(channel_exchange_stats_fine_stats, channel, Id),
9396
index_delete(channel_queue_stats_deliver_stats, channel, Id),
9497
ok.
@@ -137,18 +140,32 @@ delete_samples(Table, Id, Intervals) ->
137140
[ets:delete(Table, {Id, I}) || I <- Intervals],
138141
ok.
139142

140-
index_delete(consumer_stats = Table, channel = Type, Id) ->
141-
IndexTable = rabbit_mgmt_metrics_collector:index_table(Table, Type),
142-
MatchPattern = {'_', Id, '_'},
143-
%% Delete consumer_stats_queue_index
144-
ets:match_delete(consumer_stats_queue_index,
145-
{'_', MatchPattern}),
146-
%% Delete consumer_stats
147-
ets:match_delete(consumer_stats,
148-
{MatchPattern,'_'}),
149-
%% Delete consumer_stats_channel_index
150-
ets:delete(IndexTable, Id),
151-
ok;
143+
index_delete(consumer_stats = Table, {channel = Type, ConsumerCount}, Id) ->
144+
%% This uses two different deletion strategies depending on how many
145+
%% consumers a channel had. Most of the time there are many channels
146+
%% with a few (or even just one) consumers. For this common case, `ets:delete/2` is optimal
147+
%% since it avoids table scans.
148+
%%
149+
%% In the rather extreme scenario where only a handful of channels have a very large
150+
%% (e.g. tens of thousands) of consumers, `ets:match_delete/2` becomes a more efficient option.
151+
%%
152+
%% See rabbitmq-server/rabbitmq#10451, rabbitmq-server/rabbitmq#9356.
153+
case ConsumerCount > ?LARGE_CONSUMER_COUNT of
154+
true ->
155+
IndexTable = rabbit_mgmt_metrics_collector:index_table(Table, Type),
156+
MatchPattern = {'_', Id, '_'},
157+
%% Delete consumer_stats_queue_index
158+
ets:match_delete(consumer_stats_queue_index,
159+
{'_', MatchPattern}),
160+
%% Delete consumer_stats
161+
ets:match_delete(consumer_stats,
162+
{MatchPattern,'_'}),
163+
%% Delete consumer_stats_channel_index
164+
ets:delete(IndexTable, Id),
165+
ok;
166+
false ->
167+
index_delete(Table, Type, Id)
168+
end;
152169
index_delete(Table, Type, Id) ->
153170
IndexTable = rabbit_mgmt_metrics_collector:index_table(Table, Type),
154171
Keys = ets:lookup(IndexTable, Id),

0 commit comments

Comments
 (0)