From 3541e9237e6561c9ebf900bd90a167a309ac1d97 Mon Sep 17 00:00:00 2001 From: "igor.petrenko" Date: Thu, 2 Apr 2026 11:07:03 +0300 Subject: [PATCH 1/3] CE-141 http client: random connection pool --- .../remote/RemoteInvocationHandler.java | 2 + .../java/oap/http/client/OapHttpClient.java | 50 ++++++++++++++++--- pom.xml | 2 +- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/oap-application/oap-application/src/main/java/oap/application/remote/RemoteInvocationHandler.java b/oap-application/oap-application/src/main/java/oap/application/remote/RemoteInvocationHandler.java index 9abd163a2..3df6e4bec 100644 --- a/oap-application/oap-application/src/main/java/oap/application/remote/RemoteInvocationHandler.java +++ b/oap-application/oap-application/src/main/java/oap/application/remote/RemoteInvocationHandler.java @@ -36,6 +36,7 @@ import oap.util.Stream; import oap.util.function.Try; import org.eclipse.jetty.client.BytesRequestContent; +import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.InputStreamResponseListener; import org.eclipse.jetty.client.Request; import org.eclipse.jetty.client.Response; @@ -61,6 +62,7 @@ import java.util.concurrent.TimeoutException; import static java.net.HttpURLConnection.HTTP_OK; +import static oap.http.client.OapHttpClient.OapHttpClientBuilder.ConnectionPoolFactoryType.RANDOM; @Slf4j public final class RemoteInvocationHandler implements InvocationHandler { diff --git a/oap-http/oap-http/src/main/java/oap/http/client/OapHttpClient.java b/oap-http/oap-http/src/main/java/oap/http/client/OapHttpClient.java index 41e8b995d..6dcad2ee9 100644 --- a/oap-http/oap-http/src/main/java/oap/http/client/OapHttpClient.java +++ b/oap-http/oap-http/src/main/java/oap/http/client/OapHttpClient.java @@ -8,7 +8,10 @@ import oap.util.Lists; import org.eclipse.jetty.client.AbstractConnectionPool; import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport; +import org.eclipse.jetty.client.ConnectionPool; import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.RandomConnectionPool; +import org.eclipse.jetty.client.RoundRobinConnectionPool; import org.eclipse.jetty.client.WWWAuthenticationProtocolHandler; import org.eclipse.jetty.http.HttpCookieStore; import org.eclipse.jetty.io.ClientConnector; @@ -24,8 +27,13 @@ import java.util.List; import java.util.concurrent.atomic.LongAdder; +import static oap.http.client.OapHttpClient.OapHttpClientBuilder.ConnectionPoolFactoryType.RANDOM; + public class OapHttpClient { - public static final HttpClient DEFAULT_HTTP_CLIENT = customHttpClient().build(); + public static final HttpClient DEFAULT_HTTP_CLIENT = customHttpClient() + .withConnectionPoolFactoryType( RANDOM ) + .metrics( "default" ) + .build(); public static OapHttpClientBuilder customHttpClient() { return new OapHttpClientBuilder(); @@ -47,6 +55,8 @@ public static class OapHttpClientBuilder { public boolean dnsjava = false; private String metrics; private HttpCookieStore cookieStore; + private ConnectionPool.Factory connectionPoolFactory; + private ConnectionPoolFactoryType connectionPoolFactoryType; public OapHttpClientBuilder transport( AbstractConnectorHttpClientTransport httpClientTransport ) { this.httpClientTransport = httpClientTransport; @@ -90,6 +100,18 @@ public OapHttpClientBuilder cookieStore( HttpCookieStore cookieStore ) { return this; } + public OapHttpClientBuilder withConnectionPoolFactory( ConnectionPool.Factory connectionPoolFactory ) { + this.connectionPoolFactory = connectionPoolFactory; + + return this; + } + + public OapHttpClientBuilder withConnectionPoolFactoryType( ConnectionPoolFactoryType connectionPoolFactoryType ) { + this.connectionPoolFactoryType = connectionPoolFactoryType; + + return this; + } + @SneakyThrows public HttpClient build() { HttpClient httpClient = httpClientTransport != null ? new HttpClient( httpClientTransport ) : new HttpClient(); @@ -124,15 +146,15 @@ public HttpClient build() { if( metrics != null ) { ( ( AbstractConnectorHttpClientTransport ) httpClient.getHttpClientTransport() ).getClientConnector().addEventListener( new ClientConnectorConnectListener( metrics ) ); - Gauge.builder( "dsp_tunneling_connections", httpClient, cs -> cs.getDestinations().stream().mapToInt( d -> ( ( AbstractConnectionPool ) d.getConnectionPool() ).getMaxConnectionCount() ).sum() ) + Gauge.builder( "http_client_connections", httpClient, cs -> cs.getDestinations().stream().mapToInt( d -> ( ( AbstractConnectionPool ) d.getConnectionPool() ).getMaxConnectionCount() ).sum() ) .baseUnit( BaseUnits.CONNECTIONS ) .tags( "event", "max", "client", metrics ) .register( Metrics.globalRegistry ); - Gauge.builder( "dsp_tunneling_connections", httpClient, cs -> cs.getDestinations().stream().mapToInt( d -> ( ( AbstractConnectionPool ) d.getConnectionPool() ).getConnectionCount() ).sum() ) + Gauge.builder( "http_client_connections", httpClient, cs -> cs.getDestinations().stream().mapToInt( d -> ( ( AbstractConnectionPool ) d.getConnectionPool() ).getConnectionCount() ).sum() ) .baseUnit( BaseUnits.CONNECTIONS ) .tags( "event", "total", "client", metrics ) .register( Metrics.globalRegistry ); - Gauge.builder( "dsp_tunneling_connections", httpClient, cs -> cs.getDestinations().stream().mapToInt( d -> ( ( AbstractConnectionPool ) d.getConnectionPool() ).getActiveConnectionCount() ).sum() ) + Gauge.builder( "http_client_connections", httpClient, cs -> cs.getDestinations().stream().mapToInt( d -> ( ( AbstractConnectionPool ) d.getConnectionPool() ).getActiveConnectionCount() ).sum() ) .baseUnit( BaseUnits.CONNECTIONS ) .tags( "event", "active", "client", metrics ) .register( Metrics.globalRegistry ); @@ -142,19 +164,35 @@ public HttpClient build() { httpClient.getProtocolHandlers().remove( WWWAuthenticationProtocolHandler.NAME ); + if( connectionPoolFactory != null ) { + httpClient.getHttpClientTransport().setConnectionPoolFactory( connectionPoolFactory ); + } + + if( connectionPoolFactoryType != null ) { + httpClient.getHttpClientTransport().setConnectionPoolFactory( destination -> switch( this.connectionPoolFactoryType ) { + case RANDOM -> new RandomConnectionPool( destination, httpClient.getMaxConnectionsPerDestination(), 1 ); + case ROUND_ROBIN -> new RoundRobinConnectionPool( destination, httpClient.getMaxConnectionsPerDestination(), 1 ); + } ); + } + return httpClient; } + public enum ConnectionPoolFactoryType { + RANDOM, + ROUND_ROBIN + } + public static class ClientConnectorConnectListener implements ClientConnector.ConnectListener { public final LongAdder connectSuccessCounter = new LongAdder(); public final LongAdder connectFailedCounter = new LongAdder(); public ClientConnectorConnectListener( String name ) { - Gauge.builder( "dsp_tunneling_connections", this, cs -> cs.connectSuccessCounter.doubleValue() ) + Gauge.builder( "http_client_connections", this, cs -> cs.connectSuccessCounter.doubleValue() ) .baseUnit( BaseUnits.CONNECTIONS ) .tags( "event", "success", "client", name ) .register( Metrics.globalRegistry ); - Gauge.builder( "dsp_tunneling_connections", this, cs -> cs.connectFailedCounter.doubleValue() ) + Gauge.builder( "http_client_connections", this, cs -> cs.connectFailedCounter.doubleValue() ) .baseUnit( BaseUnits.CONNECTIONS ) .tags( "event", "failed", "client", name ) .register( Metrics.globalRegistry ); diff --git a/pom.xml b/pom.xml index daa029348..3ac94d7c6 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ - 25.4.10 + 25.4.11 25.0.1 25.0.0 From b88e42c4d50da6ff76feac693bf63ec389384d7a Mon Sep 17 00:00:00 2001 From: "igor.petrenko" Date: Thu, 2 Apr 2026 11:27:05 +0300 Subject: [PATCH 2/3] CE-141 http client: random connection pool --- .../java/oap/application/remote/RemoteInvocationHandler.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/oap-application/oap-application/src/main/java/oap/application/remote/RemoteInvocationHandler.java b/oap-application/oap-application/src/main/java/oap/application/remote/RemoteInvocationHandler.java index 3df6e4bec..9abd163a2 100644 --- a/oap-application/oap-application/src/main/java/oap/application/remote/RemoteInvocationHandler.java +++ b/oap-application/oap-application/src/main/java/oap/application/remote/RemoteInvocationHandler.java @@ -36,7 +36,6 @@ import oap.util.Stream; import oap.util.function.Try; import org.eclipse.jetty.client.BytesRequestContent; -import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.InputStreamResponseListener; import org.eclipse.jetty.client.Request; import org.eclipse.jetty.client.Response; @@ -62,7 +61,6 @@ import java.util.concurrent.TimeoutException; import static java.net.HttpURLConnection.HTTP_OK; -import static oap.http.client.OapHttpClient.OapHttpClientBuilder.ConnectionPoolFactoryType.RANDOM; @Slf4j public final class RemoteInvocationHandler implements InvocationHandler { From b687e17c5795f65c7b800dbdbd72c9681acdda17 Mon Sep 17 00:00:00 2001 From: "igor.petrenko" Date: Thu, 2 Apr 2026 11:33:20 +0300 Subject: [PATCH 3/3] CE-141 http client: random connection pool --- .../java/oap/http/prometheus/PrometheusExporterTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oap-http/oap-http-prometheus/src/test/java/oap/http/prometheus/PrometheusExporterTest.java b/oap-http/oap-http-prometheus/src/test/java/oap/http/prometheus/PrometheusExporterTest.java index da4038b85..ea2dad60f 100644 --- a/oap-http/oap-http-prometheus/src/test/java/oap/http/prometheus/PrometheusExporterTest.java +++ b/oap-http/oap-http-prometheus/src/test/java/oap/http/prometheus/PrometheusExporterTest.java @@ -49,8 +49,8 @@ private static void clear() { @Test public void server() throws Exception { int port = Ports.getFreePort( getClass() ); - try( var server = new NioHttpServer( new NioHttpServer.DefaultPort( port ) ) ) { - var exporter = new PrometheusExporter( server ); + try( NioHttpServer server = new NioHttpServer( new NioHttpServer.DefaultPort( port ) ) ) { + new PrometheusExporter( server ); Counter metric1 = Metrics.counter( "test1" ); Timer metric2 = Metrics.timer( "test2" ); @@ -69,7 +69,7 @@ public void server() throws Exception { """ ) .contains( "test2_seconds_count 1" ) .contains( "test2_seconds_max 2.0" ) - .contains( "system_metrics 5" ); + .contains( "system_metrics 10.0" ); } }