Expose client request metrics
If a client handles many requests, using multiple event loops instead of one allows better CPU utilization and faster request processing. To decide the number of event loops allocated to an endpoint, the client's current traffic information must be considered.
For that, I propose to expose ClientMetrics for use in selecting the number of event loops.
public class ClientMetrics {
/**
* Returns the number of all pending requests.
*/
public long pendingRequests() {
return pendingHttp1Requests() + pendingHttp2Requests();
}
/**
* Returns the number of pending http1 requests.
*/
public long pendingHttp1Requests() {
return ...;
}
/**
* Returns the number of pending http2 requests.
*/
public long pendingHttp2Requests() {
return ...;
}
/**
* Returns the number of all active requests.
*/
public Map<Endpoint, Integer> activeRequestsPerEndpoint() {
return ...;
}
...
}
@ikhoon Hi, If it's okay with you, may I give it a try?
@ikhoon nim,
IMHO, I have an implementation idea for this.
I think DefaultRequestLog already has all information for this feature.
Maybe, DefaultRequelstLog can be single source of truth for http state machine.
So, we can use it for implementation.
- Make
ClientMetricssingleton. - Inject it to
DefaultClientRequestContext. - Make callbacks for updating
ClientMetricsand Inject itDefaultRequestLogwhenDefatulRequestLogis created. I think it would be better put it intoRequestLogBuilderinterfaces. - Then, calls updating
ClientMetricscallbacks instartRequest(),endRequest(),responseFirstBytesTransferred(), and so on.
I think it would be good solution, because ClientMetrics is synchronized with actual http state. (Http State Machine)
By using callbacks, DefaultRequestLog has minimized dependencies about Metrics or micrometer.
What do you think? If this is reasonable to you, I can make skeleton codes!
Hi, @ikhoon nim. Sorry to bother you. When you have time, could you take a look?
Make ClientMetrics singleton.
We may create ClientMetrics per ClientFactory. Users could access the metrics through ClientFactory.
var clientFactory =
ClientFactory
.builder()
// Expose as a parameter of maxNumEventLoopsFunction
.maxNumEventLoopsFunction((endpoint, clientMetrics) -> {
// determine the number of event loop based on clientMetrics
})
.build()
// And access the metrics via a getter of ClientFatory.
clientFactory.clientMetrics();
Make callbacks for updating ClientMetrics and Inject it DefaultRequestLog when DefatulRequestLog is created. I think it would be better put it intoRequestLogBuilder interfaces.
I prefer recoding the metrics inside HttpSessionHandler since we can know the actual session protocol there.
https://github.com/line/armeria/blob/32e7c3eb8b5bb5a1a2223f37d449f8f9d805ebce/core/src/main/java/com/linecorp/armeria/client/HttpSessionHandler.java#L236-L237
It is also a good idea to implement it in DefaultRequestLog but fixing HttpSessionHandler might be a easier way.
Sounds good! I made a PR based on your comments. When you have time, please take a look 🙇♂️