From ea715b9c5dffa5f93ec5078274a3e5d1df36549e Mon Sep 17 00:00:00 2001 From: Peter Paul Bakker Date: Mon, 7 Mar 2022 10:55:44 +0100 Subject: [PATCH 1/2] Performance tweak for Prometheus scraping endpoint. Reduce the number of times capacity growth is needed inside the StringWriter. A typical default SpringBoot Prometheus page has more than 11k characters. Best performance results when no capacity growth is needed at all, so base it on previous metrics page size plus some room for possible extra metric info. --- .../prometheus/PrometheusScrapeEndpoint.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java index eb179c543842..56005e3c1cb7 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java @@ -42,8 +42,14 @@ @WebEndpoint(id = "prometheus") public class PrometheusScrapeEndpoint { + // the default Prometheus metrics contains more than 11k characters + private static final int METRICS_SCRAPE_CHARS_INIT = 12 * 1024; + private static final int METRICS_SCRAPE_CHARS_EXTRA = 1024; + private final CollectorRegistry collectorRegistry; + private volatile int previousMetricsScrapeSize = METRICS_SCRAPE_CHARS_INIT; + public PrometheusScrapeEndpoint(CollectorRegistry collectorRegistry) { this.collectorRegistry = collectorRegistry; } @@ -51,12 +57,16 @@ public PrometheusScrapeEndpoint(CollectorRegistry collectorRegistry) { @ReadOperation(producesFrom = TextOutputFormat.class) public WebEndpointResponse scrape(TextOutputFormat format, @Nullable Set includedNames) { try { - Writer writer = new StringWriter(); + Writer writer = new StringWriter(previousMetricsScrapeSize + METRICS_SCRAPE_CHARS_EXTRA); Enumeration samples = (includedNames != null) ? this.collectorRegistry.filteredMetricFamilySamples(includedNames) : this.collectorRegistry.metricFamilySamples(); format.write(writer, samples); - return new WebEndpointResponse<>(writer.toString(), format); + + String scrapePage = writer.toString(); + previousMetricsScrapeSize = scrapePage.length(); + + return new WebEndpointResponse<>(scrapePage, format); } catch (IOException ex) { // This actually never happens since StringWriter doesn't throw an IOException From 6a43f2fa608cc6eb7cc9e10e0aa5f69c42ca571f Mon Sep 17 00:00:00 2001 From: Peter Paul Bakker Date: Tue, 8 Mar 2022 17:23:33 +0100 Subject: [PATCH 2/2] Performance tweak for Prometheus scraping endpoint: do not use the initial 12k but the StringWriter default size. --- .../export/prometheus/PrometheusScrapeEndpoint.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java index 56005e3c1cb7..46974bab0cf6 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java @@ -42,13 +42,11 @@ @WebEndpoint(id = "prometheus") public class PrometheusScrapeEndpoint { - // the default Prometheus metrics contains more than 11k characters - private static final int METRICS_SCRAPE_CHARS_INIT = 12 * 1024; private static final int METRICS_SCRAPE_CHARS_EXTRA = 1024; private final CollectorRegistry collectorRegistry; - private volatile int previousMetricsScrapeSize = METRICS_SCRAPE_CHARS_INIT; + private volatile int nextMetricsScrapeSize = 16; public PrometheusScrapeEndpoint(CollectorRegistry collectorRegistry) { this.collectorRegistry = collectorRegistry; @@ -57,14 +55,14 @@ public PrometheusScrapeEndpoint(CollectorRegistry collectorRegistry) { @ReadOperation(producesFrom = TextOutputFormat.class) public WebEndpointResponse scrape(TextOutputFormat format, @Nullable Set includedNames) { try { - Writer writer = new StringWriter(previousMetricsScrapeSize + METRICS_SCRAPE_CHARS_EXTRA); + Writer writer = new StringWriter(nextMetricsScrapeSize); Enumeration samples = (includedNames != null) ? this.collectorRegistry.filteredMetricFamilySamples(includedNames) : this.collectorRegistry.metricFamilySamples(); format.write(writer, samples); String scrapePage = writer.toString(); - previousMetricsScrapeSize = scrapePage.length(); + nextMetricsScrapeSize = scrapePage.length() + METRICS_SCRAPE_CHARS_EXTRA; return new WebEndpointResponse<>(scrapePage, format); }