recording retry timeout httpclient

background

Online services rely on third parties, interfaces RT traffic is large in response time is very long. Since each timeout parameter is set to 5s.

Examples

PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
// 连接池最大的连接数
connManager.setMaxTotal(6000);
// 单个路由的最大连接数,例如:www.baidu.com,图片最大高峰并发量520
connManager.setDefaultMaxPerRoute(500);

RequestConfig.Builder custom = RequestConfig.custom();
// 连接超时时间 建立连接时间 此前设置3000
custom.setConnectTimeout(800);
// 从connect Manager获取Connection 超时时间(连接池获取连接超时时间)
custom.setConnectionRequestTimeout(500);
// (获取response的返回时间)读取返回时间 此前设置40000,官方建议40s
custom.setSocketTimeout(1000);
RequestConfig config = custom.build();

// DefaultHttpRequestRetryHandler 重试策略(可自定义)
httpClient = HttpClients.custom().setRetryHandler(new DefaultHttpRequestRetryHandler(1, true)).setConnectionManager(connManager)
                .setDefaultRequestConfig(config).build();
复制代码

Construction httpClient

By debug, you can know the future build method of execution, access to InternalHttpClient object, if you do not specify execution chain, is to use RetryExec actuator, the default retry strategy is DefaultHttpRequestRetryHandler

public CloseableHttpClient build() {
    ... 省略部分代码
    // Add request retry executor, if not disabled
    if (!automaticRetriesDisabled) {
        HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
        if (retryHandlerCopy == null) {
            retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
        }
        execChain = new RetryExec(execChain, retryHandlerCopy);
    }
    ... 省略部分代码
}
复制代码

Timeout parameters

Three dimensions timeout settings

  • Connection timeout setConnectTimeout
  • Read Timeout setSocketTimeout
  • Obtaining a connection from the connection pool timeout setConnectionRequestTimeout

Retry strategy impact on the business

By default there retry strategy, or you can manually change or redefine retry strategy, but in some cases, it can retry, retry some cases is failure.

Retry analysis

For our scenario applications get the post, it can be summarized as follows:

Only InterruptedIOException retry only occurs when IOExecetion occurs, UnknownHostException, ConnectException, SSLException, may occur in the weight at which no abnormality 4 retry methods can get three retries, post methods corresponding socket output stream is not successfully write and flush test three times.

Does not retry exception:

  • InterruptedIOException, thread interrupt exception
  • UnknownHostException, find the corresponding host
  • ConnectException, found the host, connection establishment failure
  • SSLException, https abnormal certification

DefaultHttpRequestRetryHandler retry strategy

@Override
public boolean retryRequest(
        final IOException exception,
        final int executionCount,
        final HttpContext context) {
    Args.notNull(exception, "Exception parameter");
    Args.notNull(context, "HTTP context");
    if (executionCount > this.retryCount) {
        // Do not retry if over max retry count
        return false;
    }
    // 异常类是否在禁止重试中
    if (this.nonRetriableClasses.contains(exception.getClass())) {
        return false;
    } else {
        for (final Class<? extends IOException> rejectException : this.nonRetriableClasses) {
            if (rejectException.isInstance(exception)) {
                return false;
            }
        }
    }
    final HttpClientContext clientContext = HttpClientContext.adapt(context);
    final HttpRequest request = clientContext.getRequest();

    if(requestIsAborted(request)){
        return false;
    }

    if (handleAsIdempotent(request)) {
        // Retry if the request is considered idempotent
        return true;
    }

    // 根据上下文判断请求是否发送成功了,或者根据状态为是否永远可以重复发送(默认的是否) requestSentRetryEnabled 参数可以在构建httpCLient对象设置重试策略指定此属性
    // isRequestSent 是在HttpRequestExecutor中doSendRequest方法中flush成功设置context.setAttribute("http.request_sent", Boolean.TRUE);
    if (!clientContext.isRequestSent() || this.requestSentRetryEnabled) {
        // Retry if the request has not been sent fully or
        // if it's OK to retry methods that have been sent
        return true;
    }
    // otherwise do not retry
    return false;
}

// 几种类型的异常不重试,同时判断是否与异常类型的子类,是子类的话,也不重试
复制代码

In addition two timeouts, connection timeout and read timeout: java.net.SocketTimeoutException: Read timed out java.net.SocketTimeoutException: connect timed out two timeouts are SocketTimeoutException, inherited from InterruptedIOException, belonging to the above first kind interrupt thread exceptions, will not be retried.

Will retry the circumstances under which

post flush with the write request in the output stream, when, in addition to which IOExecetion InterruptedIOException, UnknownHostException, ConnectException, SSLException occur.

That could possibly go wrong step by step HttpClientConnection.flush (), with the inside you can know the object of its operation is a SocketOutputStream, and flush this class is empty achieve, so you can just look at wirte method.

Retry parameters requestSentRetryEnabled http.request_sent

//根据上下文判断请求是否发送成功了,或者根据状态为是否永远可以重复发送(默认的是否)
if (!clientContext.isRequestSent() || this.requestSentRetryEnabled) {
    return true;
}
复制代码

Prohibit retry

httpclient provided by default retry strategy for some scenarios, we can manually close retry strategy. HttpClientBuilder, which is build () method RetryExec chose the actuator is pre-conditions, i.e. no manual prohibited.

// Add request retry executor, if not disabled
if (!automaticRetriesDisabled) {
    HttpRequestRetryHandler retryHandlerCopy = this.retryHandler;
    if (retryHandlerCopy == null) {
        retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;
    }
    execChain = new RetryExec(execChain, retryHandlerCopy);
}
复制代码

reference

blog.csdn.net/gaohe7091/a…

Guess you like

Origin juejin.im/post/5dc37b6fe51d456e34358a58