Skip to content

Commit 07a1593

Browse files
Merge pull request #15018 from rabbitmq/mergify/bp/v4.2.x/pr-14885
Prometheus: stream HTTP responses (a double digit % reduction of both CPU and memory footprint) (backport #14885)
2 parents 0b56950 + d6dd60e commit 07a1593

File tree

4 files changed

+21
-55
lines changed

4 files changed

+21
-55
lines changed

deps/rabbitmq_prometheus/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ endef
99
PROJECT := rabbitmq_prometheus
1010
PROJECT_DESCRIPTION = Prometheus metrics for RabbitMQ
1111
PROJECT_MOD := rabbit_prometheus_app
12-
DEPS = accept cowboy rabbit rabbitmq_management_agent prometheus rabbitmq_web_dispatch
12+
DEPS = cowboy rabbit rabbitmq_management_agent prometheus rabbitmq_web_dispatch
1313
BUILD_DEPS = amqp_client rabbit_common rabbitmq_management
1414
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers rabbitmq_stream
1515

deps/rabbitmq_prometheus/src/rabbit_prometheus_handler.erl

Lines changed: 18 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
-define(SCRAPE_DURATION, telemetry_scrape_duration_seconds).
1616
-define(SCRAPE_SIZE, telemetry_scrape_size_bytes).
17-
-define(SCRAPE_ENCODED_SIZE, telemetry_scrape_encoded_size_bytes).
1817

1918
-define(AUTH_REALM, "Basic realm=\"RabbitMQ Prometheus\"").
2019

@@ -58,14 +57,9 @@ setup_metrics(Registry) ->
5857
{help, "Scrape size, not encoded"},
5958
{labels, ["registry", "content_type"]},
6059
{registry, Registry}],
61-
ScrapeEncodedSize = [{name, ?SCRAPE_ENCODED_SIZE},
62-
{help, "Scrape size, encoded"},
63-
{labels, ["registry", "content_type", "encoding"]},
64-
{registry, Registry}],
6560

6661
prometheus_summary:declare(ScrapeDuration),
67-
prometheus_summary:declare(ScrapeSize),
68-
prometheus_summary:declare(ScrapeEncodedSize).
62+
prometheus_summary:declare(ScrapeSize).
6963

7064
%% ===================================================================
7165
%% Private functions
@@ -89,47 +83,34 @@ gen_response(_, Request) ->
8983
Request.
9084

9185
gen_metrics_response(Registry, Request) ->
92-
{Code, RespHeaders, Body} = reply(Registry, Request),
93-
94-
Headers = to_cowboy_headers(RespHeaders),
95-
cowboy_req:reply(Code, maps:from_list(Headers), Body, Request).
96-
97-
to_cowboy_headers(RespHeaders) ->
98-
lists:map(fun to_cowboy_headers_/1, RespHeaders).
99-
100-
to_cowboy_headers_({Name, Value}) ->
101-
{to_cowboy_name(Name), Value}.
102-
103-
to_cowboy_name(Name) ->
104-
binary:replace(atom_to_binary(Name, utf8), <<"_">>, <<"-">>).
105-
106-
reply(Registry, Request) ->
10786
case validate_registry(Registry, registry()) of
10887
{true, RealRegistry} ->
10988
format_metrics(Request, RealRegistry);
11089
{registry_conflict, _ReqR, _ConfR} ->
111-
{409, [], <<>>}
90+
cowboy_req:reply(409, #{}, <<>>, Request)
11291
end.
11392

11493
format_metrics(Request, Registry) ->
115-
AcceptEncoding = cowboy_req:header(<<"accept-encoding">>, Request, undefined),
94+
%% Formatting registries produces large binaries. Fullsweep eagerly to
95+
%% evict the large binaries faster and make GC cheaper.
96+
process_flag(fullsweep_after, 0),
11697
ContentType = prometheus_text_format:content_type(),
117-
Scrape = render_format(ContentType, Registry),
118-
Encoding = accept_encoding_header:negotiate(AcceptEncoding, [<<"identity">>,
119-
<<"gzip">>]),
120-
encode_format(ContentType, binary_to_list(Encoding), Scrape, Registry).
121-
122-
render_format(ContentType, Registry) ->
123-
Scrape = prometheus_summary:observe_duration(
124-
Registry,
125-
?SCRAPE_DURATION,
126-
[Registry, ContentType],
127-
fun () -> prometheus_text_format:format(Registry) end),
98+
Req = cowboy_req:stream_reply(200, #{<<"content-type">> => ContentType}, Request),
99+
Fmt = fun(Size, Data) ->
100+
cowboy_req:stream_body(Data, nofin, Req),
101+
Size + byte_size(Data)
102+
end,
103+
Size = prometheus_summary:observe_duration(
104+
Registry,
105+
?SCRAPE_DURATION,
106+
[Registry, ContentType],
107+
fun () -> prometheus_text_format:format_into(Registry, Fmt, 0) end),
108+
cowboy_req:stream_body(<<>>, fin, Req),
128109
prometheus_summary:observe(Registry,
129110
?SCRAPE_SIZE,
130111
[Registry, ContentType],
131-
iolist_size(Scrape)),
132-
Scrape.
112+
Size),
113+
Req.
133114

134115
validate_registry(undefined, auto) ->
135116
{true, default};
@@ -146,20 +127,6 @@ telemetry_registry() ->
146127
registry() ->
147128
application:get_env(rabbitmq_prometheus, registry, auto).
148129

149-
encode_format(ContentType, Encoding, Scrape, Registry) ->
150-
Encoded = encode_format_(Encoding, Scrape),
151-
prometheus_summary:observe(telemetry_registry(),
152-
?SCRAPE_ENCODED_SIZE,
153-
[Registry, ContentType, Encoding],
154-
iolist_size(Encoded)),
155-
{200, [{content_type, binary_to_list(ContentType)},
156-
{content_encoding, Encoding}], Encoded}.
157-
158-
encode_format_("gzip", Scrape) ->
159-
zlib:gzip(Scrape);
160-
encode_format_("identity", Scrape) ->
161-
Scrape.
162-
163130
%% It's not easy to pass this information in a pure way (it'll require changing prometheus.erl)
164131
put_filtering_options_into_process_dictionary(Request) ->
165132
#{vhost := VHosts, family := Families} = cowboy_req:match_qs([{vhost, [], undefined}, {family, [], undefined}], Request),

deps/rabbitmq_prometheus/test/rabbit_prometheus_http_SUITE.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ content_type_test(Config) ->
373373

374374
encoding_test(Config) ->
375375
{Headers, Body} = http_get(Config, [{"accept-encoding", "deflate"}], 200),
376-
?assertMatch("identity", proplists:get_value("content-encoding", Headers)),
376+
?assertMatch(undefined, proplists:get_value("content-encoding", Headers)),
377377
?assertEqual(match, re:run(Body, "^# TYPE", [{capture, none}, multiline])).
378378

379379
gzip_encoding_test(Config) ->

rabbitmq-components.mk

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ endif
3939
# We do that in this file, which is included by all projects, to ensure
4040
# all projects use the same versions. It avoids conflicts.
4141

42-
dep_accept = hex 0.3.5
4342
dep_cowboy = hex 2.14.1
4443
dep_cowlib = hex 2.16.0
4544
dep_credentials_obfuscation = hex 3.5.0
@@ -50,7 +49,7 @@ dep_khepri = hex 0.17.2
5049
dep_khepri_mnesia_migration = hex 0.8.0
5150
dep_meck = hex 1.0.0
5251
dep_osiris = git https://github.com/rabbitmq/osiris v1.10.2
53-
dep_prometheus = hex 5.1.1
52+
dep_prometheus = hex 6.1.1
5453
dep_ra = hex 2.17.1
5554
dep_ranch = hex 2.2.0
5655
dep_recon = hex 2.5.6

0 commit comments

Comments
 (0)