Merge pull request #9080 from rabbitmq/mqtt-qos0-queue-metrics
Add Prometheus metric for messages dropped by MQTT QoS 0 Queue
This commit is contained in:
commit
a6c5820e47
|
|
@ -1,2 +1,41 @@
|
||||||
-define(NUM_PROTOCOL_COUNTERS, 8).
|
-define(NUM_PROTOCOL_COUNTERS, 8).
|
||||||
-define(NUM_PROTOCOL_QUEUE_TYPE, 8).
|
-define(NUM_PROTOCOL_QUEUE_TYPE_COUNTERS, 8).
|
||||||
|
|
||||||
|
%% Dead Letter counters:
|
||||||
|
%%
|
||||||
|
%% The following two counters are mutually exclusive because
|
||||||
|
%% quorum queue dead-letter-strategy at-least-once is incompatible with overflow drop-head.
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_MAXLEN, 1).
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_CONFIRMED, 1).
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_EXPIRED, 2).
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_REJECTED, 3).
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT, 4).
|
||||||
|
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER,
|
||||||
|
{messages_dead_lettered_maxlen_total, ?MESSAGES_DEAD_LETTERED_MAXLEN, counter,
|
||||||
|
"Total number of messages dead-lettered due to overflow drop-head or reject-publish-dlx"
|
||||||
|
}).
|
||||||
|
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_CONFIRMED_COUNTER,
|
||||||
|
{
|
||||||
|
messages_dead_lettered_confirmed_total, ?MESSAGES_DEAD_LETTERED_CONFIRMED, counter,
|
||||||
|
"Total number of messages dead-lettered and confirmed by target queues"
|
||||||
|
}).
|
||||||
|
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_EXPIRED_COUNTER,
|
||||||
|
{
|
||||||
|
messages_dead_lettered_expired_total, ?MESSAGES_DEAD_LETTERED_EXPIRED, counter,
|
||||||
|
"Total number of messages dead-lettered due to message TTL exceeded"
|
||||||
|
}).
|
||||||
|
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_REJECTED_COUNTER,
|
||||||
|
{
|
||||||
|
messages_dead_lettered_rejected_total, ?MESSAGES_DEAD_LETTERED_REJECTED, counter,
|
||||||
|
"Total number of messages dead-lettered due to basic.reject or basic.nack"
|
||||||
|
}).
|
||||||
|
|
||||||
|
-define(MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT_COUNTER,
|
||||||
|
{
|
||||||
|
messages_dead_lettered_delivery_limit_total, ?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT, counter,
|
||||||
|
"Total number of messages dead-lettered due to delivery-limit exceeded"
|
||||||
|
}).
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
-module(rabbit_global_counters).
|
-module(rabbit_global_counters).
|
||||||
|
|
||||||
|
-include("rabbit_global_counters.hrl").
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
boot_step/0,
|
boot_step/0,
|
||||||
init/1,
|
init/1,
|
||||||
|
|
@ -128,57 +130,48 @@
|
||||||
}
|
}
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_EXPIRED, 1).
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_REJECTED, 2).
|
|
||||||
%% The following two counters are mutually exclusive because
|
|
||||||
%% quorum queue dead-letter-strategy at-least-once is incompatible with overflow drop-head.
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_MAXLEN, 3).
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_CONFIRMED, 3).
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT, 4).
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_COUNTERS,
|
|
||||||
[
|
|
||||||
{
|
|
||||||
messages_dead_lettered_expired_total, ?MESSAGES_DEAD_LETTERED_EXPIRED, counter,
|
|
||||||
"Total number of messages dead-lettered due to message TTL exceeded"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
messages_dead_lettered_rejected_total, ?MESSAGES_DEAD_LETTERED_REJECTED, counter,
|
|
||||||
"Total number of messages dead-lettered due to basic.reject or basic.nack"
|
|
||||||
}
|
|
||||||
]).
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER,
|
|
||||||
{
|
|
||||||
messages_dead_lettered_maxlen_total, ?MESSAGES_DEAD_LETTERED_MAXLEN, counter,
|
|
||||||
"Total number of messages dead-lettered due to overflow drop-head or reject-publish-dlx"
|
|
||||||
}).
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_CONFIRMED_COUNTER,
|
|
||||||
{
|
|
||||||
messages_dead_lettered_confirmed_total, ?MESSAGES_DEAD_LETTERED_CONFIRMED, counter,
|
|
||||||
"Total number of messages dead-lettered and confirmed by target queues"
|
|
||||||
}).
|
|
||||||
-define(MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT_COUNTER,
|
|
||||||
{
|
|
||||||
messages_dead_lettered_delivery_limit_total, ?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT, counter,
|
|
||||||
"Total number of messages dead-lettered due to delivery-limit exceeded"
|
|
||||||
}).
|
|
||||||
|
|
||||||
boot_step() ->
|
boot_step() ->
|
||||||
|
%% Protocol counters
|
||||||
init([{protocol, amqp091}]),
|
init([{protocol, amqp091}]),
|
||||||
|
|
||||||
|
%% Protocol & Queue Type counters
|
||||||
init([{protocol, amqp091}, {queue_type, rabbit_classic_queue}]),
|
init([{protocol, amqp091}, {queue_type, rabbit_classic_queue}]),
|
||||||
init([{protocol, amqp091}, {queue_type, rabbit_quorum_queue}]),
|
init([{protocol, amqp091}, {queue_type, rabbit_quorum_queue}]),
|
||||||
init([{protocol, amqp091}, {queue_type, rabbit_stream_queue}]),
|
init([{protocol, amqp091}, {queue_type, rabbit_stream_queue}]),
|
||||||
|
|
||||||
|
%% Dead Letter counters
|
||||||
|
%%
|
||||||
|
%% Streams never dead letter.
|
||||||
|
%%
|
||||||
|
%% Source classic queue dead letters.
|
||||||
init([{queue_type, rabbit_classic_queue}, {dead_letter_strategy, disabled}],
|
init([{queue_type, rabbit_classic_queue}, {dead_letter_strategy, disabled}],
|
||||||
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER]),
|
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_EXPIRED_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_REJECTED_COUNTER]),
|
||||||
init([{queue_type, rabbit_classic_queue}, {dead_letter_strategy, at_most_once}],
|
init([{queue_type, rabbit_classic_queue}, {dead_letter_strategy, at_most_once}],
|
||||||
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER]),
|
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_EXPIRED_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_REJECTED_COUNTER]),
|
||||||
|
%%
|
||||||
|
%% Source quorum queue dead letters.
|
||||||
|
%% Only quorum queues can dead letter due to delivery-limit exceeded.
|
||||||
|
%% Only quorum queues support dead letter strategy at-least-once.
|
||||||
init([{queue_type, rabbit_quorum_queue}, {dead_letter_strategy, disabled}],
|
init([{queue_type, rabbit_quorum_queue}, {dead_letter_strategy, disabled}],
|
||||||
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER,
|
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER,
|
||||||
?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT_COUNTER]),
|
?MESSAGES_DEAD_LETTERED_EXPIRED_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_REJECTED_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT_COUNTER
|
||||||
|
]),
|
||||||
init([{queue_type, rabbit_quorum_queue}, {dead_letter_strategy, at_most_once}],
|
init([{queue_type, rabbit_quorum_queue}, {dead_letter_strategy, at_most_once}],
|
||||||
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER,
|
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER,
|
||||||
?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT_COUNTER]),
|
?MESSAGES_DEAD_LETTERED_EXPIRED_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_REJECTED_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT_COUNTER
|
||||||
|
]),
|
||||||
init([{queue_type, rabbit_quorum_queue}, {dead_letter_strategy, at_least_once}],
|
init([{queue_type, rabbit_quorum_queue}, {dead_letter_strategy, at_least_once}],
|
||||||
[?MESSAGES_DEAD_LETTERED_CONFIRMED_COUNTER,
|
[?MESSAGES_DEAD_LETTERED_CONFIRMED_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_EXPIRED_COUNTER,
|
||||||
|
?MESSAGES_DEAD_LETTERED_REJECTED_COUNTER,
|
||||||
?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT_COUNTER
|
?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT_COUNTER
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
|
@ -193,9 +186,9 @@ init(Labels = [{protocol, Protocol}], Extra) ->
|
||||||
_ = seshat:new_group(?MODULE),
|
_ = seshat:new_group(?MODULE),
|
||||||
Counters = seshat:new(?MODULE, Labels, ?PROTOCOL_COUNTERS ++ Extra),
|
Counters = seshat:new(?MODULE, Labels, ?PROTOCOL_COUNTERS ++ Extra),
|
||||||
persistent_term:put({?MODULE, Protocol}, Counters);
|
persistent_term:put({?MODULE, Protocol}, Counters);
|
||||||
init(Labels = [{queue_type, QueueType}, {dead_letter_strategy, DLS}], Extra) ->
|
init(Labels = [{queue_type, QueueType}, {dead_letter_strategy, DLS}], DeadLetterCounters) ->
|
||||||
_ = seshat:new_group(?MODULE),
|
_ = seshat:new_group(?MODULE),
|
||||||
Counters = seshat:new(?MODULE, Labels, ?MESSAGES_DEAD_LETTERED_COUNTERS ++ Extra),
|
Counters = seshat:new(?MODULE, Labels, DeadLetterCounters),
|
||||||
persistent_term:put({?MODULE, QueueType, DLS}, Counters).
|
persistent_term:put({?MODULE, QueueType, DLS}, Counters).
|
||||||
|
|
||||||
overview() ->
|
overview() ->
|
||||||
|
|
@ -263,9 +256,9 @@ consumer_deleted(Protocol) ->
|
||||||
|
|
||||||
messages_dead_lettered(Reason, QueueType, DeadLetterStrategy, Num) ->
|
messages_dead_lettered(Reason, QueueType, DeadLetterStrategy, Num) ->
|
||||||
Index = case Reason of
|
Index = case Reason of
|
||||||
|
maxlen -> ?MESSAGES_DEAD_LETTERED_MAXLEN;
|
||||||
expired -> ?MESSAGES_DEAD_LETTERED_EXPIRED;
|
expired -> ?MESSAGES_DEAD_LETTERED_EXPIRED;
|
||||||
rejected -> ?MESSAGES_DEAD_LETTERED_REJECTED;
|
rejected -> ?MESSAGES_DEAD_LETTERED_REJECTED;
|
||||||
maxlen -> ?MESSAGES_DEAD_LETTERED_MAXLEN;
|
|
||||||
delivery_limit -> ?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT
|
delivery_limit -> ?MESSAGES_DEAD_LETTERED_DELIVERY_LIMIT
|
||||||
end,
|
end,
|
||||||
counters:add(fetch(QueueType, DeadLetterStrategy), Index, Num).
|
counters:add(fetch(QueueType, DeadLetterStrategy), Index, Num).
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
-include("rabbit_mqtt.hrl").
|
-include("rabbit_mqtt.hrl").
|
||||||
-include("rabbit_mqtt_packet.hrl").
|
-include("rabbit_mqtt_packet.hrl").
|
||||||
|
-include_lib("rabbit/include/rabbit_global_counters.hrl").
|
||||||
-include_lib("stdlib/include/assert.hrl").
|
-include_lib("stdlib/include/assert.hrl").
|
||||||
|
|
||||||
-export([start/2, stop/1]).
|
-export([start/2, stop/1]).
|
||||||
|
|
@ -93,16 +94,18 @@ local_connection_pids() ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
init_global_counters() ->
|
init_global_counters() ->
|
||||||
init_global_counters(?MQTT_PROTO_V3),
|
lists:foreach(fun init_global_counters/1, [?MQTT_PROTO_V3,
|
||||||
init_global_counters(?MQTT_PROTO_V4),
|
?MQTT_PROTO_V4,
|
||||||
init_global_counters(?MQTT_PROTO_V5).
|
?MQTT_PROTO_V5]).
|
||||||
|
|
||||||
init_global_counters(ProtoVer) ->
|
init_global_counters(ProtoVer) ->
|
||||||
Proto = {protocol, ProtoVer},
|
Proto = {protocol, ProtoVer},
|
||||||
rabbit_global_counters:init([Proto]),
|
rabbit_global_counters:init([Proto]),
|
||||||
rabbit_global_counters:init([Proto, {queue_type, ?QUEUE_TYPE_QOS_0}]),
|
|
||||||
rabbit_global_counters:init([Proto, {queue_type, rabbit_classic_queue}]),
|
rabbit_global_counters:init([Proto, {queue_type, rabbit_classic_queue}]),
|
||||||
rabbit_global_counters:init([Proto, {queue_type, rabbit_quorum_queue}]).
|
rabbit_global_counters:init([Proto, {queue_type, rabbit_quorum_queue}]),
|
||||||
|
rabbit_global_counters:init([Proto, {queue_type, ?QUEUE_TYPE_QOS_0}]),
|
||||||
|
rabbit_global_counters:init([{queue_type, ?QUEUE_TYPE_QOS_0}, {dead_letter_strategy, disabled}],
|
||||||
|
[?MESSAGES_DEAD_LETTERED_MAXLEN_COUNTER]).
|
||||||
|
|
||||||
persist_static_configuration() ->
|
persist_static_configuration() ->
|
||||||
rabbit_mqtt_util:init_sparkplug(),
|
rabbit_mqtt_util:init_sparkplug(),
|
||||||
|
|
|
||||||
|
|
@ -1982,6 +1982,8 @@ handle_queue_event({queue_event, ?QUEUE_TYPE_QOS_0, Msg},
|
||||||
false ->
|
false ->
|
||||||
deliver_one_to_client(Msg, false, State0);
|
deliver_one_to_client(Msg, false, State0);
|
||||||
true ->
|
true ->
|
||||||
|
rabbit_global_counters:messages_dead_lettered(
|
||||||
|
maxlen, ?QUEUE_TYPE_QOS_0, disabled, 1),
|
||||||
State0#state{qos0_messages_dropped = N + 1}
|
State0#state{qos0_messages_dropped = N + 1}
|
||||||
end,
|
end,
|
||||||
{ok, State};
|
{ok, State};
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,22 @@ event_authentication_failure(Config) ->
|
||||||
%% Test that queue type rabbit_mqtt_qos0_queue drops QoS 0 messages when its
|
%% Test that queue type rabbit_mqtt_qos0_queue drops QoS 0 messages when its
|
||||||
%% max length is reached.
|
%% max length is reached.
|
||||||
rabbit_mqtt_qos0_queue_overflow(Config) ->
|
rabbit_mqtt_qos0_queue_overflow(Config) ->
|
||||||
ok = rabbit_ct_broker_helpers:enable_feature_flag(Config, rabbit_mqtt_qos0_queue),
|
ProtoVer = case ?config(mqtt_version, Config) of
|
||||||
|
v4 -> mqtt311;
|
||||||
|
v5 -> mqtt50
|
||||||
|
end,
|
||||||
|
QType = rabbit_mqtt_qos0_queue,
|
||||||
|
|
||||||
|
#{
|
||||||
|
[{protocol, ProtoVer}, {queue_type, QType}] :=
|
||||||
|
#{messages_delivered_total := 0,
|
||||||
|
messages_delivered_consume_auto_ack_total := 0},
|
||||||
|
|
||||||
|
[{queue_type, QType}, {dead_letter_strategy, disabled}] :=
|
||||||
|
#{messages_dead_lettered_maxlen_total := NumDeadLettered}
|
||||||
|
} = rabbit_ct_broker_helpers:rpc(Config, rabbit_global_counters, overview, []),
|
||||||
|
|
||||||
|
ok = rabbit_ct_broker_helpers:enable_feature_flag(Config, QType),
|
||||||
|
|
||||||
Topic = atom_to_binary(?FUNCTION_NAME),
|
Topic = atom_to_binary(?FUNCTION_NAME),
|
||||||
Msg = binary:copy(<<"x">>, 4000),
|
Msg = binary:copy(<<"x">>, 4000),
|
||||||
|
|
@ -289,7 +304,8 @@ rabbit_mqtt_qos0_queue_overflow(Config) ->
|
||||||
{status, _, _, [_, _, _, _, Misc]} = sys:get_status(ServerConnectionPid),
|
{status, _, _, [_, _, _, _, Misc]} = sys:get_status(ServerConnectionPid),
|
||||||
[State] = [S || {data, [{"State", S}]} <- Misc],
|
[State] = [S || {data, [{"State", S}]} <- Misc],
|
||||||
#{proc_state := #{qos0_messages_dropped := NumDropped}} = State,
|
#{proc_state := #{qos0_messages_dropped := NumDropped}} = State,
|
||||||
ct:pal("NumReceived=~b~nNumDropped=~b", [NumReceived, NumDropped]),
|
|
||||||
|
ct:pal("NumReceived=~b NumDropped=~b", [NumReceived, NumDropped]),
|
||||||
|
|
||||||
%% We expect that
|
%% We expect that
|
||||||
%% 1. all sent messages were either received or dropped
|
%% 1. all sent messages were either received or dropped
|
||||||
|
|
@ -302,6 +318,19 @@ rabbit_mqtt_qos0_queue_overflow(Config) ->
|
||||||
%% of mailbox_soft_limit=200 should not be dropped
|
%% of mailbox_soft_limit=200 should not be dropped
|
||||||
?assert(NumReceived >= 200),
|
?assert(NumReceived >= 200),
|
||||||
|
|
||||||
|
%% Assert that Prometheus metrics counted correctly.
|
||||||
|
ExpectedNumDeadLettered = NumDeadLettered + NumDropped,
|
||||||
|
?assertMatch(
|
||||||
|
#{
|
||||||
|
[{protocol, ProtoVer}, {queue_type, QType}] :=
|
||||||
|
#{messages_delivered_total := NumReceived,
|
||||||
|
messages_delivered_consume_auto_ack_total := NumReceived},
|
||||||
|
|
||||||
|
[{queue_type, QType}, {dead_letter_strategy, disabled}] :=
|
||||||
|
#{messages_dead_lettered_maxlen_total := ExpectedNumDeadLettered}
|
||||||
|
},
|
||||||
|
rabbit_ct_broker_helpers:rpc(Config, rabbit_global_counters, overview, [])),
|
||||||
|
|
||||||
ok = emqtt:disconnect(Sub),
|
ok = emqtt:disconnect(Sub),
|
||||||
ok = emqtt:disconnect(Pub).
|
ok = emqtt:disconnect(Pub).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -866,7 +866,7 @@ at_most_once_dead_letter_detect_cycle(Config) ->
|
||||||
ok = emqtt:disconnect(Pub),
|
ok = emqtt:disconnect(Pub),
|
||||||
%% Given our subscribing client is disconnected, the message should be dead lettered after 1 ms.
|
%% Given our subscribing client is disconnected, the message should be dead lettered after 1 ms.
|
||||||
%% However, due to the dead letter cycle, we expect the message to be dropped.
|
%% However, due to the dead letter cycle, we expect the message to be dropped.
|
||||||
timer:sleep(5),
|
timer:sleep(20),
|
||||||
Sub2 = connect(SubClientId, Config, [{clean_start, false}]),
|
Sub2 = connect(SubClientId, Config, [{clean_start, false}]),
|
||||||
assert_nothing_received(),
|
assert_nothing_received(),
|
||||||
%% Double check that the message was indeed (exactly once) dead lettered.
|
%% Double check that the message was indeed (exactly once) dead lettered.
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,9 @@ To generate these:
|
||||||
Metrics `rabbitmq_global_messages_dead_lettered_*` have labels `queue_type` and `dead_letter_strategy`.
|
Metrics `rabbitmq_global_messages_dead_lettered_*` have labels `queue_type` and `dead_letter_strategy`.
|
||||||
|
|
||||||
Label `queue_type` denotes the type of queue messages were discarded from. It can have value
|
Label `queue_type` denotes the type of queue messages were discarded from. It can have value
|
||||||
* `rabbit_classic_queue`, or
|
* `rabbit_classic_queue`,
|
||||||
* `rabbit_quorum_queue`
|
* `rabbit_quorum_queue`, or
|
||||||
|
* `rabbit_mqtt_qos0_queue`
|
||||||
|
|
||||||
(Queue type `rabbit_stream_queue` does not dead letter messages.)
|
(Queue type `rabbit_stream_queue` does not dead letter messages.)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue