-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Add support of PrometheusRawMetricsProvider for the Pulsar-Proxy #14681
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
eolivelli
left a comment
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.
Really great work !
IIUC this change is totally backward compatible
lhotari
left a comment
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.
LGTM, good work @cbornet
michaeljmarshall
left a comment
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.
Overall, looks good.
I think we need to address metrics providers that are added late to ensure they are added to the metricsServlet.
pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyServiceStarter.java
Outdated
Show resolved
Hide resolved
| public void addPrometheusRawMetricsProvider(PrometheusRawMetricsProvider metricsProvider) { | ||
| metricsProviders.add(metricsProvider); | ||
| } |
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.
Since this method could be called from other threads in protocol handlers, I think we should consider using a concurrent data structure to back the metricsProviders list. Technically, it appears that the current implementation in the broker does not use a concurrent data structure, so I could be wrong about this class's thread safety requirements.
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.
@codelipenghui as you contributed the code for the broker, can you say if we should use concurrent structures for PulsarService's pendingMetricsProviders ?
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.
Initially, it was only considered when loading plugins when starting the broker, which will not be modified after the broker started. To avoid any potential thread-safety issues(maybe some users want to modify after the broker started), using concurrent structures looks good to me.
dlg99
left a comment
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.
+1 to @michaeljmarshall 's question, otherwise LGTM to me
codelipenghui
left a comment
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.
LGTM, just left a minor comment.
| private static final int HTTP_STATUS_OK_200 = 200; | ||
| private static final int HTTP_STATUS_INTERNAL_SERVER_ERROR_500 = 500; |
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.
Any reason for introducing new http status code?
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.
@codelipenghui
because we are not importing org.eclipse.jetty.http.HttpStatus anymore
500 is used below
pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyService.java
Show resolved
Hide resolved
| if (metricsServlet == null) { | ||
| if (pendingMetricsProviders == null) { | ||
| pendingMetricsProviders = new LinkedList<>(); | ||
| synchronized (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.
what about moving 'synchronized' to the signature of the method ?
| if (pendingMetricsProviders != null) { | ||
| pendingMetricsProviders.forEach(provider -> metricsServlet.addRawMetricsProvider(provider)); | ||
| this.pendingMetricsProviders = null; | ||
| synchronized (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.
what about creating a method like this:
private synchronised void initMetricsServlet() {
this.metricsServlet = new PrometheusMetricsServlet(-1L, proxyConfig.getClusterName());
if (pendingMetricsProviders != null) {
pendingMetricsProviders.forEach(provider -> metricsServlet.addRawMetricsProvider(provider));
this.pendingMetricsProviders = null;
}
}
| } | ||
|
|
||
| metricsServlet = null; | ||
| synchronized (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.
what about using a synchronised method here instead of using "synchronized (this)" ?
probably it is a matter of taste, but I think that "synchronized (this)" is quite hard to read
| if (metricsServlet == null) { | ||
| if (pendingMetricsProviders == null) { | ||
| pendingMetricsProviders = new LinkedList<>(); | ||
| synchronized (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.
what about moving 'synchronized' to the signature of the method ?
| pendingMetricsProviders.forEach(provider -> metricsServlet.addRawMetricsProvider(provider)); | ||
| this.pendingMetricsProviders = null; | ||
|
|
||
| synchronized (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.
what about moving this code to a dedicated method ?
private synchronised void initMetricsServlet() {
..
}
| } | ||
| } | ||
|
|
||
| private synchronized void resetMetricsServlet() { |
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.
getMetricsServlet should be synchronized as well (spotbugs should not pass)
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.
done
| this.pendingMetricsProviders = null; | ||
| } | ||
|
|
||
| createMetricsServlet(); |
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.
below we have a non synchronised access to metricsServlet.
I suggest to use a synchronised getter and use it while calling addWebServerHandlers
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.
There should be only one thread here.
eolivelli
left a comment
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.
Lgtm
@michaeljmarshall please take another look
michaeljmarshall
left a comment
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.
LGTM. Thanks for addressing my comments @cbornet!
) (cherry picked from commit ea95b28)
Motivation
PR #9021 added support for
PrometheusRawMetricsProviderin the broker so that plugins can add their metrics to the Prometheus/metricsendpoint.This change does the same for the Pulsar Proxy. Proxy plugins (additional servlets, extensions, ...) can then add their Prometheus providers with
ProxyService::addPrometheusRawMetricsProvider.This helps having common metrics code for servlets and handlers/extensions when they can be deployed both in the broker and the proxy.
Modifications
PrometheusRawMetricsProvidermoved frompulsar-brokertopulsar-broker-commonunder the same package name so the change is non-breaking.PrometheusMetricsServletnon-specific to the broker and have anotherPulsarPrometheusMetricsServletthat extends it for the broker.PrometheusMetricsGeneratormethods used by both the broker and the proxy to aPrometheusMetricsGeneratorUtilsclass.ProxyService::addPrometheusRawMetricsProvidermethod for use by plugins.PrometheusMetricsServletinstead of the classicalMetricsServletand add registeredPrometheusRawMetricsProviderto it onWebServerstartup.PrometheusMetricsServletis aware of the PrometheusCollectorRegistryso it's backward compatible for existing plugins that are registering standard Prometheus metrics./metricsendpoint.Verifying this change
This change is already covered by existing tests, such as
org.apache.pulsar.broker.stats.PrometheusMetricsTest.This change added tests and can be verified by running
org.apache.pulsar.proxy.server.ProxyPrometheusMetricsTestDoes this pull request potentially affect one of the following parts:
If
yeswas chosen, please highlight the changesDocumentation
Check the box below or label this PR directly (if you have committer privilege).
Need to update docs?
doc-required(If you need help on updating docs, create a doc issue)
no-need-docThis should be first documented for the broker.
doc(If this PR contains doc changes)