-
Couldn't load subscription status.
- Fork 3.4k
HBASE-20904 Prometheus /metrics http endpoint for monitoring #4691
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Co-authored-by: Luca Kovacs <[email protected]>
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
| Collection<MetricsRecord> metricRecords = MetricsExportHelper.export(); | ||
| for (MetricsRecord metricsRecord : metricRecords) { | ||
| for (AbstractMetric metrics : metricsRecord.metrics()) { | ||
| if (metrics.type() == MetricType.COUNTER || metrics.type() == MetricType.GAUGE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not want to rely on prometheus simpleclient to do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was part of the original pull request and because it doesn't add any dependencies I kept it like this. If you think simpleclient is a better solution, it can be replaced of course.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, just want to know the reason.
Then better add some references about the format spec, and also mention that the format is not hard to implement so do not want to add extra dependencies.
| import org.apache.yetus.audience.InterfaceAudience; | ||
|
|
||
| @InterfaceAudience.Private | ||
| public class PrometheusHadoop2Servlet extends HttpServlet { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why name it hadoop2, not hadoop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, I left it as it was, but I renamed to Hadoop in the last commit
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
Notes: - Fixed error that caused test fails - Renamed PrometheusHadoop2Servlet to PrometheusHadoopServlet (same in the test files) - Added comments, change in the documenatation
|
💔 -1 overall
This message was automatically generated. |
|
🎊 +1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
hbase-http/src/main/java/org/apache/hadoop/hbase/http/prometheus/PrometheusHadoopServlet.java
Outdated
Show resolved
Hide resolved
Notes: - Fixed RestrictedAPI annontation - Added '/metrics' endpoint to defaults
|
🎊 +1 overall
This message was automatically generated. |
|
🎊 +1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No big problem. Just some style nits.
| public static Collection<MetricsRecord> export() { | ||
| MetricsSystemImpl instance = (MetricsSystemImpl) DefaultMetricsSystem.instance(); | ||
| MetricsBuffer metricsBuffer = instance.sampleMetrics(); | ||
| List<MetricsRecord> metrics = new LinkedList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use ArrayList. LinkedList will lead to a error prone warning.
| public static final String METRIC_SERVLETS_CONF_KEY = "hbase.http.metrics.servlets"; | ||
| public static final String METRICS_SERVLETS_DEFAULT[] = { "jmx", "metrics", "prometheus" }; | ||
| private static final Map<String, ServletConfig> METRIC_SERVLETS = | ||
| new HashMap<String, ServletConfig>() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use ImmutableMap.Builder in guava. In hbase we have a shaded guava, under the org.apache.hbase.thirdparty.com.google package. The current code will lead to a error prone warning.
| import org.apache.yetus.audience.InterfaceAudience; | ||
|
|
||
| @InterfaceAudience.Private | ||
| public class MetricsExportHelper { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make this class final and add a private constructor.
| String metricName) { | ||
| return metrics.stream().filter(mr -> mr.name().equals(metricsName)).anyMatch(mr -> { | ||
| for (AbstractMetric metric : mr.metrics()) { | ||
| if (metric.name().equals(metricName)) return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New line with '{}', otherwise there will be a checkstyle warning.
| public static final String APP_DIR = "webapps"; | ||
|
|
||
| public static final String METRIC_SERVLETS_CONF_KEY = "hbase.http.metrics.servlets"; | ||
| public static final String METRICS_SERVLETS_DEFAULT[] = { "jmx", "metrics", "prometheus" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String METRICS_SERVLETS_DEFAULT[] -> String[] METRICS_SERVLETS_DEFAULT
| } | ||
|
|
||
| /* register metrics servlets */ | ||
| String enabledServlets[] = conf.getStrings(METRIC_SERVLETS_CONF_KEY, METRICS_SERVLETS_DEFAULT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String enabledServlets[] -> String[] enabledServlets
Fixed them :) |
|
💔 -1 overall
This message was automatically generated. |
|
🎊 +1 overall
This message was automatically generated. |
|
🎊 +1 overall
This message was automatically generated. |
|
Please take a look at the findbugs issue? |
|
🎊 +1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
|
💔 -1 overall
This message was automatically generated. |
Co-authored-by: Luca Kovacs <[email protected]> Co-authored-by: Madhusoodan P <[email protected]> Co-authored-by: Luca Kovacs <[email protected]> Signed-off-by: Duo Zhang <[email protected]> (cherry picked from commit f9ea7ee) Conflicts: src/main/asciidoc/_chapters/ops_mgt.adoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi there @lucakovacs , thanks for the contribution.
I must confess, I'm surprised that this project was resumed and committed. The last discussion on it was in 2020 when I expressed my reservations about implementing it. I think that we should not implement any code ourselves and instead use something like https://github.com/prometheus/jmx_exporter.
All that said, I have a couple concerns with the implementation as it is. Please take a look. If the community still wants this implementation instead of depending on a 3rd party agent, and if my questions can be addressed, we can probably include this one in the next 2.5.0 release candidate.
Thanks!
| clz.asSubclass(HttpServlet.class)); | ||
| } | ||
| } catch (Exception e) { | ||
| /* shouldn't be fatal, so warn the user about it */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised that having metrics be optional was accepted by review. Before this change, it was impossible to run an HBase processes that exposes no metrics at all. Now, that can happen. We do not have other healthcheck endpoints like a modern web service, metrics are the only lifeline for an operations team (besides inspecting the pid). I think that we should be more careful here:
- we should warn if the process is configured without any metrics endpoint
- we should warn if a configured metric endpoint fails to load
- we should abort the process launch if the process is configured with any metrics but none load
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me, I think the current implementation is enough. We will warn if a registered endpoint fails to load. And the default configuration is to load all metrics endpoints, if users configured it to none, they must have a reason, so I do not think here we need to warn it. And I also do not think we should abort the process if none metrics can be loaded, as it does not affect the normal read/write.
| import org.apache.yetus.audience.InterfaceAudience; | ||
|
|
||
| @InterfaceAudience.Private | ||
| public class PrometheusHadoopServlet extends HttpServlet { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this called a "Hadoop" servlet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it exports the metrics we registered to hadoop metrics system?
| import org.apache.yetus.audience.InterfaceAudience; | ||
|
|
||
| @InterfaceAudience.Private | ||
| public class PrometheusHadoopServlet extends HttpServlet { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh no, why was this implemented as a raw servlet :'(
We have Jersey. There is absolutely no reason to implement a servlet by hand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not see any advantages here to use jersey? The servlet is really easy to implement...
| new ServletConfig("jmx", "/jmx", "org.apache.hadoop.hbase.http.jmx.JMXJsonServlet")) | ||
| .put("metrics", | ||
| new ServletConfig("metrics", "/metrics", "org.apache.hadoop.metrics.MetricsServlet")) | ||
| .put("prometheus", new ServletConfig("prometheus", "/prometheus", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have changed the title of the jira to match the actual endpoint this feature uses. People will be confused that /metrics does not emit the prometheus formatted output.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is a problem. I just read it as 'Prometheus metrics http endpoint for monitoring'... Missed the '/'
…4691) Co-authored-by: Luca Kovacs <[email protected]> Co-authored-by: Madhusoodan P <[email protected]> Co-authored-by: Luca Kovacs <[email protected]> Signed-off-by: Duo Zhang <[email protected]> (cherry picked from commit f9ea7ee) Change-Id: I31ec9c68ffd05c0dc42acb8f4462d1e61c4741cf
Co-authored-by: Luca Kovacs [email protected]