前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊AsyncHttpClient的KeepAliveStrategy

聊聊AsyncHttpClient的KeepAliveStrategy

原创
作者头像
code4it
发布2023-12-11 20:05:57
1700
发布2023-12-11 20:05:57
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究一下AsyncHttpClient的KeepAliveStrategy

KeepAliveStrategy

org/asynchttpclient/channel/KeepAliveStrategy.java

代码语言:javascript
复制
public interface KeepAliveStrategy {

  /**
   * Determines whether the connection should be kept alive after this HTTP message exchange.
   *
   * @param ahcRequest    the Request, as built by AHC
   * @param nettyRequest  the HTTP request sent to Netty
   * @param nettyResponse the HTTP response received from Netty
   * @return true if the connection should be kept alive, false if it should be closed.
   */
  boolean keepAlive(Request ahcRequest, HttpRequest nettyRequest, HttpResponse nettyResponse);
}

KeepAliveStrategy接口定义了keepAlive方法用于决定是否对该connection进行keep alive

DefaultKeepAliveStrategy

org/asynchttpclient/channel/DefaultKeepAliveStrategy.java

代码语言:javascript
复制
/**
 * Connection strategy implementing standard HTTP 1.0/1.1 behavior.
 */
public class DefaultKeepAliveStrategy implements KeepAliveStrategy {

  /**
   * Implemented in accordance with RFC 7230 section 6.1 https://tools.ietf.org/html/rfc7230#section-6.1
   */
  @Override
  public boolean keepAlive(Request ahcRequest, HttpRequest request, HttpResponse response) {
    return HttpUtil.isKeepAlive(response)
            && HttpUtil.isKeepAlive(request)
            // support non standard Proxy-Connection
            && !response.headers().contains("Proxy-Connection", CLOSE, true);
  }
}

DefaultKeepAliveStrategy实现了KeepAliveStrategy接口,其keepAlive方法判根据HTTP 1.0/1.1协议的规定进行判断,需要request、response都是keep alive,且response header不包含Proxy-Connection: close才返回true

HttpUtil

io/netty/handler/codec/http/HttpUtil.java

代码语言:javascript
复制
    /**
     * Returns {@code true} if and only if the connection can remain open and
     * thus 'kept alive'.  This methods respects the value of the.
     *
     * {@code "Connection"} header first and then the return value of
     * {@link HttpVersion#isKeepAliveDefault()}.
     */
    public static boolean isKeepAlive(HttpMessage message) {
        return !message.headers().containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE, true) &&
               (message.protocolVersion().isKeepAliveDefault() ||
                message.headers().containsValue(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE, true));
    }

isKeepAlive方法在HttpMessage没有connection: close的header,且http协议默认keep alive或者header包含了connection: keep-alive才返回true

handleHttpResponse

org/asynchttpclient/netty/handler/HttpHandler.java

代码语言:javascript
复制
  private void handleHttpResponse(final HttpResponse response, final Channel channel, final NettyResponseFuture<?> future, AsyncHandler<?> handler) throws Exception {

    HttpRequest httpRequest = future.getNettyRequest().getHttpRequest();
    logger.debug("\n\nRequest {}\n\nResponse {}\n", httpRequest, response);

    future.setKeepAlive(config.getKeepAliveStrategy().keepAlive(future.getTargetRequest(), httpRequest, response));

    NettyResponseStatus status = new NettyResponseStatus(future.getUri(), response, channel);
    HttpHeaders responseHeaders = response.headers();

    if (!interceptors.exitAfterIntercept(channel, future, handler, response, status, responseHeaders)) {
      boolean abort = abortAfterHandlingStatus(handler, status) || //
              abortAfterHandlingHeaders(handler, responseHeaders) || //
              abortAfterHandlingReactiveStreams(channel, future, handler);

      if (abort) {
        finishUpdate(future, channel, true);
      }
    }
  }

HttpHandler的handleHttpResponse方法会通过KeepAliveStrategy的keepAlive来判断是否需要keep alive,然后写入到NettyResponseFuture中

exitAfterHandlingConnect

org/asynchttpclient/netty/handler/intercept/ConnectSuccessInterceptor.java

代码语言:javascript
复制
  public boolean exitAfterHandlingConnect(Channel channel,
                                          NettyResponseFuture<?> future,
                                          Request request,
                                          ProxyServer proxyServer) {

    if (future.isKeepAlive())
      future.attachChannel(channel, true);

    Uri requestUri = request.getUri();
    LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, requestUri.getScheme());

    channelManager.updatePipelineForHttpTunneling(channel.pipeline(), requestUri);
    future.setReuseChannel(true);
    future.setConnectAllowed(false);
    requestSender.drainChannelAndExecuteNextRequest(channel, future, new RequestBuilder(future.getTargetRequest()).build());

    return true;
  }

exitAfterHandlingConnect方法在NettyResponseFuture的keep alive为true时执行future.attachChannel(channel, true)

attachChannel

org/asynchttpclient/netty/NettyResponseFuture.java

代码语言:javascript
复制
  public void attachChannel(Channel channel, boolean reuseChannel) {

    // future could have been cancelled first
    if (isDone()) {
      Channels.silentlyCloseChannel(channel);
    }

    this.channel = channel;
    this.reuseChannel = reuseChannel;
  }

  public boolean isReuseChannel() {
    return reuseChannel;
  }  

attachChannel这里维护了reuseChannel属性

getOpenChannel

org/asynchttpclient/netty/request/NettyRequestSender.java

代码语言:javascript
复制
  private Channel getOpenChannel(NettyResponseFuture<?> future, Request request, ProxyServer proxyServer,
                                 AsyncHandler<?> asyncHandler) {
    if (future != null && future.isReuseChannel() && Channels.isChannelActive(future.channel())) {
      return future.channel();
    } else {
      return pollPooledChannel(request, proxyServer, asyncHandler);
    }
  }

  private Channel pollPooledChannel(Request request, ProxyServer proxy, AsyncHandler<?> asyncHandler) {
    try {
      asyncHandler.onConnectionPoolAttempt();
    } catch (Exception e) {
      LOGGER.error("onConnectionPoolAttempt crashed", e);
    }

    Uri uri = request.getUri();
    String virtualHost = request.getVirtualHost();
    final Channel channel = channelManager.poll(uri, virtualHost, proxy, request.getChannelPoolPartitioning());

    if (channel != null) {
      LOGGER.debug("Using pooled Channel '{}' for '{}' to '{}'", channel, request.getMethod(), uri);
    }
    return channel;
  }  

getOpenChannel先判断NettyResponseFuture是否是reuse的,以及是否active,若是则直接返回future.channel(),否则通过pollPooledChannel从连接池中获取

小结

AsyncHttpClient的KeepAliveStrategy定义了keepAlive方法用于决定是否对该connection进行keep alive;HttpHandler的handleHttpResponse方法会通过KeepAliveStrategy的keepAlive来判断是否需要keep alive,然后写入到NettyResponseFuture中;getOpenChannel先判断NettyResponseFuture是否是reuse的,以及是否active,若是则直接返回future.channel(),否则通过pollPooledChannel从连接池中获取。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • KeepAliveStrategy
  • DefaultKeepAliveStrategy
  • HttpUtil
  • handleHttpResponse
  • exitAfterHandlingConnect
  • attachChannel
  • getOpenChannel
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档