问题陈述
语境
- 我是一名软件工程师,正在测试运行餐厅菜单项的订单排列,以确认它们通过 POS 成功下单
- 简而言之,这会将 JSON 有效负载发布到端点,然后使用 POS 验证订单以定义成功/失败/其他
- POS 以及因此每秒事务数 (TPS) 可能会有所不同,但每个后端使用相同的核心处理
- 这可以高达每项约 22,000 个排列,以易于管理的 JSON 大小,需要尽快处理
- 网络可能因餐厅和/或地区而异,其中一个正在测试
- 例如,有些延迟比其他延迟高得多
- 因此,HTTPClient 应该能够智能地协商相同的内容和端点,而不管这一点
直接问题
- 我正在使用 Apache 的 HTTP Client 5 w/ PoolingAsyncClientConnectionManager 来执行菜单内容的 GET 和 POST 来检查订单是否成功
- 这是开箱即用的,但有时会失去与/的连接
Stream Refused
,特别是:org.apache.hc.core5.http2.H2StreamResetException: Stream refused
- 我可以找到没有单独的调整似乎适用于具有可变延迟的所有网络环境
- 跟踪堆栈跟踪似乎表明流已经关闭,因此需要一种方法来保持它打开或不执行已经关闭的连接
if (connState == ConnectionHandshake.GRACEFUL_SHUTDOWN) {
throw new H2StreamResetException(H2Error.PROTOCOL_ERROR, "Stream refused");
}
解决问题的一些尝试
- 尝试使用搜索引擎寻找答案,但 HTTPClient5 的点击率很少
- 试图使用官方文档,但这很少
- 将每条路线的最大连接数更改为减少的数量,将不活动验证或连接时间更改为有效
- 不活动检查可能会修复 POST,但会停止某些事务的 GET
- 并且对一个区域/餐厅的调整可能适用于 1 然后中断另一个,只有网络作为变量
PoolingAsyncClientConnectionManagerBuilder builder = PoolingAsyncClientConnectionManagerBuilder
.create()
.setTlsStrategy(getTlsStrategy())
.setMaxConnPerRoute(12)
.setMaxConnTotal(12)
.setValidateAfterInactivity(TimeValue.ofMilliseconds(1000))
.setConnectionTimeToLive(TimeValue.ofMinutes(2))
.build();
- 切换到具有不同超时的自定义 RequestConfig
private HttpClientContext getHttpClientContext() {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(Timeout.of(10, TimeUnit.SECONDS))
.setResponseTimeout(Timeout.of(10, TimeUnit.SECONDS))
.build();
HttpClientContext httpContext = HttpClientContext.create();
httpContext.setRequestConfig(requestConfig);
return httpContext;
}
用于分析的初始代码段
(除了上述带更改尝试的部分)
- 包装器处理初始化并获得响应
public SimpleHttpResponse getFullResponse(String url, PoolingAsyncClientConnectionManager manager, SimpleHttpRequest req) {
try (CloseableHttpAsyncClient httpclient = getHTTPClientInstance(manager)) {
httpclient.start();
CountDownLatch latch = new CountDownLatch(1);
long startTime = System.currentTimeMillis();
Future<SimpleHttpResponse> future = getHTTPResponse(url, httpclient, latch, startTime, req);
latch.await();
return future.get();
} catch (IOException | InterruptedException | ExecutionException e) {
e.printStackTrace();
return new SimpleHttpResponse(999, CommonUtils.getExceptionAsMap(e).toString());
}
}
- 使用实际的处理程序和探测代码
private Future<SimpleHttpResponse> getHTTPResponse(String url, CloseableHttpAsyncClient httpclient, CountDownLatch latch, long startTime, SimpleHttpRequest req) {
return httpclient.execute(req, getHttpContext(), new FutureCallback<SimpleHttpResponse>() {
@Override
public void completed(SimpleHttpResponse response) {
latch.countDown();
logger.info("[{}][{}ms] - {}", response.getCode(), getTotalTime(startTime), url);
}
@Override
public void failed(Exception e) {
latch.countDown();
logger.error("[{}ms] - {} - {}", getTotalTime(startTime), url, e);
}
@Override
public void cancelled() {
latch.countDown();
logger.error("[{}ms] - request cancelled for {}", getTotalTime(startTime), url);
}
});
}
直接问题
- 有没有办法配置客户端,以便它可以自行处理这些差异,而无需显式修改每个端点上下文的配置?