armeria icon indicating copy to clipboard operation
armeria copied to clipboard

Expose client request metrics

Open ikhoon opened this issue 4 months ago • 5 comments

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 avatar Aug 27 '25 04:08 ikhoon

@ikhoon Hi, If it's okay with you, may I give it a try?

chickenchickenlove avatar Oct 25 '25 01:10 chickenchickenlove

@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.

  1. Make ClientMetrics singleton.
  2. Inject it to DefaultClientRequestContext.
  3. Make callbacks for updating ClientMetrics and Inject it DefaultRequestLog when DefatulRequestLog is created. I think it would be better put it intoRequestLogBuilder interfaces.
  4. Then, calls updating ClientMetrics callbacks in startRequest(), 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!

chickenchickenlove avatar Oct 26 '25 02:10 chickenchickenlove

Hi, @ikhoon nim. Sorry to bother you. When you have time, could you take a look?

chickenchickenlove avatar Oct 29 '25 13:10 chickenchickenlove

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.

ikhoon avatar Nov 13 '25 08:11 ikhoon

Sounds good! I made a PR based on your comments. When you have time, please take a look 🙇‍♂️

chickenchickenlove avatar Nov 16 '25 13:11 chickenchickenlove