-
Notifications
You must be signed in to change notification settings - Fork 934
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
Add port tag to server metrics #6116
base: main
Are you sure you want to change the base?
Conversation
Motivation: A server can be configured with multiple ports, and operators may want to collect connection and request metrics per port for better observability and debugging. Modifications: - Added a `port` tag to server metrics. - If a `DomainSocketAddress` is used, the path of the address is used as the tag value. Result: - Enabled per-port metrics collection for better monitoring and troubleshooting.
private final Map<Integer, LongAdder> pendingHttp1Requests; | ||
private final Map<Integer, LongAdder> pendingHttp2Requests; | ||
private final Map<Integer, LongAdder> activeHttp1WebSocketRequests; | ||
private final Map<Integer, LongAdder> activeHttp1Requests; | ||
private final Map<Integer, LongAdder> activeHttp2Requests; | ||
private final Map<String, LongAdder> domainSocketPendingHttp1Requests; | ||
private final Map<String, LongAdder> domainSocketPendingHttp2Requests; | ||
private final Map<String, LongAdder> domainSocketActiveHttp1WebSocketRequests; | ||
private final Map<String, LongAdder> domainSocketActiveHttp1Requests; | ||
private final Map<String, LongAdder> domainSocketActiveHttp2Requests; |
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.
Optional) The implementation that holds many Map
s in this class looks complex. How about introducing ServerMetricsGroup
to encapsulate the complexity?
My suggestion:
public interface ServerMetrics extends MeterBinder {
}
class ServerPortMetrics implements ServerMetrics {
...
}
class ServerMetricsGroup implements ServerMetrics {
private Map<Object, ServerPortMetrics> delegates;
...
}
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 don't fully understand your intention.
So the ServerMetricsGroup
has all the delegates?
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.
Right. I imagined the following implementation:
class ServerMetricsGroup implements ServerMetrics {
private Map<Object, ServerPortMetrics> delegates;
void increasePendingHttp1Requests(SocketAddress socketAddress) {
Object key = getPathOrPort(socketAddress);
delegates.get(key).increasePendingHttp1Requests();
}
public long pendingHttp1Requests() {
// Sum all pendingHttp1Requests in delegates and return
}
}
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.
That looks much simpler. 👍
Let me use that approach.
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.
On my second thought, I've realized that I didn't want to use the Object
as a key because
InetSocketAddress
is used mostly for applications- So the integer port needs to box and unbox.
Let me develop your idea and avoid those unboxing.
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.
Split to InetSocketServerMetrics
and DomainSocketServerMetrics
. PTAL. 🙇♂️
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.
Thanks! 👍
@yzfeng2020 Please let me know if the current implementation if fine. 😉 |
} finally { | ||
lock.unlock(); | ||
} | ||
|
||
config().serverMetrics().addActivePort(actualPort); |
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.
Note) It slightly bothers me that the active port is registered after binding to the port (since technically a connection could be attempted immediately and may not be able to find a LongAdder
).
In practice, I assume this won't happen much though.
Alternatively, another way that could've been possible seems to be using channel attributes.
PerPortMetrics perPortMetrics;
...
// use the metrics from the attribute to record metrics
CompletionStage<Void> doStart(@Nullable Void arg) {
Bootstrap b;
b.childAttr(AttributeKey.valueOf("SERVER_METRICS"), serverPortMetrics);
}
...
void operationComplete(ChannelFuture f) {
if (f.isSuccess()) {
// bind each port separately
serverPortMetrics.bind(meterRegistry, Tags.of(""));
...
}
I'm fine with the current implementation though
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.
That's a brilliant idea. 👍
Changed to use the attribute and reverted the ServerMetrics
to a concrete class since it's unlikely that a user would need to implement her own ServerMetrics
.
Motivation:
A server can be configured with multiple ports, and operators may want to collect connection and request metrics per port for better observability and debugging.
Modifications:
port
tag to server metrics.DomainSocketAddress
is used, the path of the address is used as the tag value.Result: