Skip to content

Commit 949292e

Browse files
authored
HADOOP-19571. Improve PrometheusMetricsSink#normalizeName performance (#7692) Contributed by Ivan Andika.
* HADOOP-19571. Improve PrometheusMetricsSink#normalizeName performance Reviewed-by: Akira Ajisaka <aajisaka@apache.org> Signed-off-by: Shilun Fan <slfan1989@apache.org>
1 parent 66adc68 commit 949292e

File tree

1 file changed

+51
-1
lines changed

1 file changed

+51
-1
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/sink/PrometheusMetricsSink.java

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@
1919

2020
import java.util.ArrayList;
2121
import java.util.List;
22+
import java.util.concurrent.ExecutionException;
2223
import java.util.regex.Matcher;
24+
25+
import org.apache.hadoop.thirdparty.com.google.common.cache.CacheBuilder;
26+
import org.apache.hadoop.thirdparty.com.google.common.cache.CacheLoader;
27+
import org.apache.hadoop.thirdparty.com.google.common.cache.LoadingCache;
28+
import org.apache.hadoop.thirdparty.com.google.common.util.concurrent.UncheckedExecutionException;
2329
import org.apache.commons.configuration2.SubsetConfiguration;
2430
import org.apache.hadoop.metrics2.AbstractMetric;
2531
import org.apache.hadoop.metrics2.MetricType;
@@ -35,13 +41,16 @@
3541
import java.util.regex.Pattern;
3642

3743
import org.apache.commons.lang3.StringUtils;
44+
import org.slf4j.Logger;
45+
import org.slf4j.LoggerFactory;
3846

3947
/**
4048
* Metrics sink for prometheus exporter.
4149
* <p>
4250
* Stores the metric data in-memory and return with it on request.
4351
*/
4452
public class PrometheusMetricsSink implements MetricsSink {
53+
private static final Logger LOG = LoggerFactory.getLogger(PrometheusMetricsSink.class);
4554

4655
/**
4756
* Cached output lines for each metrics.
@@ -62,6 +71,17 @@ public class PrometheusMetricsSink implements MetricsSink {
6271
Pattern
6372
.compile("^op=(?<op>\\w+)(.user=(?<user>.*)|)\\.(TotalCount|count)$");
6473

74+
/**
75+
* A fixed cache for Hadoop metric to Prometheus metric name conversion.
76+
*/
77+
private static final int NORMALIZED_NAME_CACHE_MAX_SIZE = 100_000;
78+
private static final CacheLoader<String, String> NORMALIZED_NAME_CACHE_LOADER =
79+
CacheLoader.from(PrometheusMetricsSink::normalizeImpl);
80+
private static final LoadingCache<String, String> NORMALIZED_NAME_CACHE =
81+
CacheBuilder.newBuilder()
82+
.maximumSize(NORMALIZED_NAME_CACHE_MAX_SIZE)
83+
.build(NORMALIZED_NAME_CACHE_LOADER);
84+
6585
public PrometheusMetricsSink() {
6686
}
6787

@@ -83,7 +103,21 @@ public void putMetrics(MetricsRecord metricsRecord) {
83103

84104
/**
85105
* Convert CamelCase based names to lower-case names where the separator
86-
* is the underscore, to follow prometheus naming conventions.
106+
* is the underscore, to follow prometheus naming conventions. This method
107+
* utilizes a cache to improve performance.
108+
*
109+
* <p>
110+
* Reference:
111+
* <ul>
112+
* <li>
113+
* <a href="https://prometheus.io/docs/practices/naming/">
114+
* Metrics and Label Naming</a>
115+
* </li>
116+
* <li>
117+
* <a href="https://prometheus.io/docs/instrumenting/exposition_formats/">
118+
* Exposition formats</a>
119+
* </li>
120+
* </ul>
87121
*
88122
* @param metricName metricName.
89123
* @param recordName recordName.
@@ -93,6 +127,22 @@ public String prometheusName(String recordName,
93127
String metricName) {
94128
String baseName = StringUtils.capitalize(recordName)
95129
+ StringUtils.capitalize(metricName);
130+
try {
131+
return NORMALIZED_NAME_CACHE.get(baseName);
132+
} catch (ExecutionException | UncheckedExecutionException e) {
133+
// This should not happen since normalization function do not throw any exception
134+
// Nevertheless, we can fall back to uncached implementation if it somehow happens.
135+
LOG.warn("Exception encountered when loading metric with base name {} from cache, " +
136+
"fall back to uncached normalization implementation", baseName, e);
137+
return normalizeImpl(baseName);
138+
}
139+
}
140+
141+
/**
142+
* Underlying Prometheus normalization implementation.
143+
* See {@link PrometheusMetricsSink#prometheusName(String, String)} for more information.
144+
*/
145+
private static String normalizeImpl(String baseName) {
96146
String[] parts = SPLIT_PATTERN.split(baseName);
97147
String joined = String.join("_", parts).toLowerCase();
98148
return DELIMITERS.matcher(joined).replaceAll("_");

0 commit comments

Comments
 (0)