Skip to content

Commit c741619

Browse files
committed
feat: optimize http long link
1 parent 8f706bc commit c741619

8 files changed

Lines changed: 146 additions & 555 deletions

File tree

trpc-proto/trpc-proto-http/src/main/java/com/tencent/trpc/proto/http/client/Http2ConsumerInvoker.java

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,6 @@
4444

4545
/**
4646
* HTTP/2 protocol client invoker, supporting both h2 and http2c.
47-
*
48-
* <p>Each {@link #send(Request)} entry signals the underlying {@link Http2cRpcClient} that
49-
* it is being used (drives the idle-eviction heuristic) and reports success / failure to
50-
* drive the consecutive-failure counter that flips the client to unavailable on sustained
51-
* backend outages.</p>
5247
*/
5348
public class Http2ConsumerInvoker<T> extends AbstractConsumerInvoker<T> {
5449

@@ -72,31 +67,20 @@ public Http2ConsumerInvoker(Http2cRpcClient client, ConsumerConfig<T> config,
7267
@Override
7368
public Response send(Request request) throws Exception {
7469
Http2cRpcClient http2cRpcClient = (Http2cRpcClient) client;
75-
// Mark "used" before any work so even a failed request keeps the idle-eviction timer
76-
// accurate (a failing client is still actively used and must not be reaped as orphan).
77-
http2cRpcClient.markUsed();
7870

7971
int requestTimeout = config.getBackendConfig().getRequestTimeout();
8072
SimpleHttpRequest simpleHttpRequest;
8173
try {
8274
simpleHttpRequest = buildRequest(request, requestTimeout);
8375
} catch (Exception ex) {
84-
http2cRpcClient.markFailure();
8576
return RpcUtils.newResponse(request, null, ex);
8677
}
8778

8879
try {
8980
SimpleHttpResponse simpleHttpResponse = execute(request, requestTimeout,
9081
simpleHttpRequest, http2cRpcClient);
91-
Response response = handleResponse(request, simpleHttpResponse);
92-
if (response.getException() == null) {
93-
http2cRpcClient.markSuccess();
94-
} else {
95-
http2cRpcClient.markFailure();
96-
}
97-
return response;
82+
return handleResponse(request, simpleHttpResponse);
9883
} catch (Exception e) {
99-
http2cRpcClient.markFailure();
10084
return RpcUtils.newResponse(request, null, e);
10185
}
10286

@@ -164,42 +148,56 @@ private SimpleHttpResponse execute(Request request, int requestTimeout,
164148
SimpleHttpRequest simpleHttpRequest, Http2cRpcClient http2cRpcClient) throws Exception {
165149
CloseableHttpAsyncClient httpAsyncClient = http2cRpcClient.getHttpAsyncClient();
166150
Future<SimpleHttpResponse> httpResponseFuture = httpAsyncClient.execute(simpleHttpRequest,
167-
new FutureCallback<SimpleHttpResponse>() {
168-
@Override
169-
public void completed(SimpleHttpResponse result) {
170-
if (logger.isDebugEnabled()) {
171-
logger.debug(result.getBodyText());
172-
}
173-
}
174-
175-
@Override
176-
public void failed(Exception ex) {
177-
String msg = String
178-
.format("request has exception > %s ms, service=%s, "
179-
+ "method=%s, remoteAddr=%s, exception=%s",
180-
requestTimeout,
181-
request.getInvocation().getRpcServiceName(),
182-
request.getInvocation().getRpcMethodName(),
183-
request.getMeta().getRemoteAddress(),
184-
ex.getMessage());
185-
logger.error(msg);
186-
}
187-
188-
@Override
189-
public void cancelled() {
190-
String msg = String
191-
.format("request cancel > %s ms, service=%s, "
192-
+ "method=%s, remoteAddr=%s",
193-
requestTimeout,
194-
request.getInvocation().getRpcServiceName(),
195-
request.getInvocation().getRpcMethodName(),
196-
request.getMeta().getRemoteAddress());
197-
logger.error(msg);
198-
}
199-
});
151+
newResponseCallback(request, requestTimeout));
200152
return httpResponseFuture.get(requestTimeout, TimeUnit.MILLISECONDS);
201153
}
202154

155+
/**
156+
* Build the {@link FutureCallback} used to log the asynchronous request outcome. Extracted
157+
* (package-private) from {@link #execute} so the completed / failed / cancelled logging
158+
* branches can be unit-tested directly — the convenience {@code execute(SimpleHttpRequest,
159+
* FutureCallback)} on {@link CloseableHttpAsyncClient} is {@code final} and cannot be stubbed.
160+
*
161+
* @param request the originating TRPC request (used only for log context)
162+
* @param requestTimeout the request timeout in milliseconds (used only for log context)
163+
* @return a logging-only callback; it never mutates request/response state
164+
*/
165+
FutureCallback<SimpleHttpResponse> newResponseCallback(Request request, int requestTimeout) {
166+
return new FutureCallback<SimpleHttpResponse>() {
167+
@Override
168+
public void completed(SimpleHttpResponse result) {
169+
if (logger.isDebugEnabled()) {
170+
logger.debug(result.getBodyText());
171+
}
172+
}
173+
174+
@Override
175+
public void failed(Exception ex) {
176+
String msg = String
177+
.format("request has exception > %s ms, service=%s, "
178+
+ "method=%s, remoteAddr=%s, exception=%s",
179+
requestTimeout,
180+
request.getInvocation().getRpcServiceName(),
181+
request.getInvocation().getRpcMethodName(),
182+
request.getMeta().getRemoteAddress(),
183+
ex.getMessage());
184+
logger.error(msg);
185+
}
186+
187+
@Override
188+
public void cancelled() {
189+
String msg = String
190+
.format("request cancel > %s ms, service=%s, "
191+
+ "method=%s, remoteAddr=%s",
192+
requestTimeout,
193+
request.getInvocation().getRpcServiceName(),
194+
request.getInvocation().getRpcMethodName(),
195+
request.getMeta().getRemoteAddress());
196+
logger.error(msg);
197+
}
198+
};
199+
}
200+
203201
/**
204202
* Wrap the TRPC request into an HTTP request.
205203
*

trpc-proto/trpc-proto-http/src/main/java/com/tencent/trpc/proto/http/client/Http2RpcClient.java

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
package com.tencent.trpc.proto.http.client;
1313

14+
import static com.tencent.trpc.proto.http.common.HttpConstants.VALIDATE_AFTER_INACTIVITY_MS;
1415
import static com.tencent.trpc.transport.http.common.Constants.KEYSTORE_PASS;
1516
import static com.tencent.trpc.transport.http.common.Constants.KEYSTORE_PATH;
1617

@@ -21,6 +22,7 @@
2122
import com.tencent.trpc.core.logger.LoggerFactory;
2223
import java.io.File;
2324
import javax.net.ssl.SSLContext;
25+
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
2426
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
2527
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
2628
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
@@ -32,23 +34,17 @@
3234
import org.apache.hc.core5.util.TimeValue;
3335

3436
/**
35-
* HTTP/2 (TLS) protocol client. Inherits long-connection state ({@code lastUsedNanos},
36-
* {@code consecutiveFailures}, {@link #markUsed}, {@link #markSuccess}, {@link #markFailure}
37-
* and the overridden {@link #isAvailable()}) from {@link Http2cRpcClient}; the differences
38-
* are the TLS handshake and the explicit {@link HttpVersionPolicy} negotiation.
37+
* HTTP/2 (TLS) protocol client. Inherits the long-connection connection-pool setup from
38+
* {@link Http2cRpcClient}; the differences are the TLS handshake and the explicit
39+
* {@link HttpVersionPolicy} negotiation.
3940
*
4041
* <p>The connection manager is sized and tuned identically to {@link Http2cRpcClient}: pool
41-
* limits derived from {@code maxConns}, idle / expired eviction, SO_KEEPALIVE and a hard
42-
* connection TTL.</p>
42+
* limits derived from {@code maxConns}, idle / expired eviction and SO_KEEPALIVE.</p>
4343
*/
4444
public class Http2RpcClient extends Http2cRpcClient {
4545

4646
private static final Logger logger = LoggerFactory.getLogger(Http2RpcClient.class);
4747

48-
private static final int VALIDATE_AFTER_INACTIVITY_MS = 2000;
49-
private static final long EVICT_IDLE_CONNECTIONS_SECONDS = 60L;
50-
private static final int CONNECTION_TTL_MINUTES = 10;
51-
5248
/**
5349
* The protocol type used for interaction with the server, such as HTTP1, H2, or protocol negotiation.
5450
* In trpc, the interaction is forced to use H2 or HTTP1 protocol based on the configuration.
@@ -84,20 +80,19 @@ protected void doOpen() throws TRpcException {
8480
.setMaxConnPerRoute(maxConns)
8581
.setConnPoolPolicy(PoolReusePolicy.LIFO)
8682
.setValidateAfterInactivity(TimeValue.ofMilliseconds(VALIDATE_AFTER_INACTIVITY_MS))
87-
.setConnectionTimeToLive(TimeValue.ofMinutes(CONNECTION_TTL_MINUTES))
8883
.build();
8984

9085
// 3. Configure the client to force HTTPS protocol to use HTTP1 communication and H2 protocol
9186
// to use H2 communication.
92-
httpAsyncClient = HttpAsyncClients.custom()
87+
HttpAsyncClientBuilder builder = HttpAsyncClients.custom()
9388
.setVersionPolicy(this.clientVersionPolicy)
9489
.setConnectionManager(cm)
9590
.setIOReactorConfig(IOReactorConfig.custom()
9691
.setSoKeepAlive(true)
9792
.build())
98-
.evictExpiredConnections()
99-
.evictIdleConnections(TimeValue.ofSeconds(EVICT_IDLE_CONNECTIONS_SECONDS))
100-
.build();
93+
.evictExpiredConnections();
94+
applyIdleEviction(builder);
95+
httpAsyncClient = builder.build();
10196
// 4. Start the client.
10297
httpAsyncClient.start();
10398
} catch (Exception e) {

0 commit comments

Comments
 (0)