【问题标题】:how to configure pooled connection idle timeout in reactor-netty如何在 reactor-netty 中配置池连接空闲超时
【发布时间】:2019-07-12 15:56:32
【问题描述】:

我正在使用带有连接池的 reactor-netty http 客户端(0.7.X 系列),并且想配置池连接的空闲超时但不知道在哪里。

更准确地说,我需要配置 reactor-netty http 客户端连接池,使其自动关闭在可配置超时内未看到任何活动的连接。这些连接是打开的,但在某些(可配置的)时间内没有任何字节被传入或传出。

如何配置 reactor-netty http 客户端抢先关闭空闲连接?

【问题讨论】:

    标签: java reactor-netty


    【解决方案1】:

    我设法配置WebClient(通过底层TcpClient)从reactor-netty 0.8.9

    的连接池中删除超时空闲连接

    我的解决方案部分基于有关IdleStateHandler 的官方文档扩展了我对创建HttpClient 实例时如何正确应用它的研究。

    我是这样做的:

    public class IdleCleanupHandler extends ChannelDuplexHandler {
        @Override
        public void userEventTriggered(final ChannelHandlerContext ctx, final Object evt) throws Exception {
            if (evt instanceof IdleStateEvent) {
                final IdleState state = ((IdleStateEvent) evt).state();
                if (state == IdleState.ALL_IDLE) { // or READER_IDLE / WRITER_IDLE
                    // close idling channel
                    ctx.close();
                }
            } else {
                super.userEventTriggered(ctx, evt);
            }
        }
    }
    
    ...
    
    public static WebClient createWebClient(final String baseUrl, final int idleTimeoutSec) {
        final TcpClient tcpClient = TcpClient.create(ConnectionProvider.fixed("fixed-pool"))
            .bootstrap(bootstrap -> BootstrapHandlers.updateConfiguration(bootstrap, "idleTimeoutConfig",
                (connectionObserver, channel) -> {
                    channel.pipeline()
                        .addLast("idleStateHandler", new IdleStateHandler(0, 0, idleTimeoutSec))
                        .addLast("idleCleanupHandler", new IdleCleanupHandler());
                }));
    
        return WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient)))
            .baseUrl(baseUrl)
            .build();
    }
    
    

    重要更新:

    我的进一步测试表明,在bootstrap 挂钩期间添加处理程序会破坏池,并且Connection 不会重用套接字(通道)。

    添加处理程序的正确方法是:

    public static WebClient createWebClient(final String baseUrl, final int idleTimeoutSec) {
        final TcpClient tcpClient = TcpClient.create(ConnectionProvider.fixed("fixed-pool"))
            .doOnConnected(conn -> {
                final ChannelPipeline pipeline = conn.channel().pipeline();
                if (pipeline.context("idleStateHandler") == null) {
                    pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, idleTimeoutSec))
                            .addLast("idleCleanupHandler", new IdleCleanupHandler());
                }
            });
    
        return WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient)))
            .baseUrl(baseUrl)
            .build();
    }
    

    注意:在reactor-netty 0.9.x 中将有一个标准的方法来为连接池中的连接配置空闲超时,请参阅此提交:https://github.com/reactor/reactor-netty/pull/792

    【讨论】:

      【解决方案2】:

      通过向通道管道添加 netty 写入和读取超时处理程序,我能够在 0.7.x 分支上完成此操作。但是,在 0.8.x 上,这种方法不再有效。

      HttpClient httpClient = HttpClient
          .create((HttpClientOptions.Builder builder) -> builder
          .host(endpointUrl.getHost())
          .port(endpointUrl.getPort())
          .poolResources(PoolResources.fixed(connectionPoolName, maxConnections, timeoutPool))
          .afterChannelInit(channel -> {
              channel.pipeline()
                      // The write and read timeouts are serving as generic socket idle state handlers.
                      .addFirst("write_timeout", new WriteTimeoutHandler(timeoutIdle, TimeUnit.MILLISECONDS))
                      .addFirst("read_timeout", new ReadTimeoutHandler(timeoutIdle, TimeUnit.MILLISECONDS));
          })
          .build());
      

      【讨论】:

      • 感谢您的回复。
      【解决方案3】:

      在 reactor-netty 0.9.x 中使用 TCP 客户端执行此操作的最简单方法是使用以下方法,我是从 @Vladimir-L 引用的 link 获得的。为您的问题配置“maxIdleTime”。

      TcpClient timeoutClient = TcpClient.create(ConnectionProvider.fixed(onnectionPoolName, maxConnections, acquireTimeout,maxIdleTime));
      

      【讨论】:

      • tcpConfiguration 至少在 reactor-netty 1.0.7 中已弃用
      【解决方案4】:

      我目前在 reactor-netty 0.8.2 因为 spring-boot-starter-webflux 并面临同样的问题,连接池在连接完成后保持打开 60 秒。

      使用这种方法,您无法配置超时,但您可以禁用它:

      WebClient.builder()
          .clientConnector(new ReactorClientHttpConnector(
              HttpClient.from(TcpClient.create()).keepAlive(false)))
          .build()
          .get()
          .uri("someurl")
          .retrieve()
          .bodyToMono(String.class)
      

      【讨论】:

        【解决方案5】:

        对于 Reactor Netty 版本 1,您需要创建一个包含空闲时间配置的 reactor.netty.resources.ConnectionProvider,然后在创建 reactor.netty.http.client.HttpClient 时使用它。

        我正在使用 Spring,所以我使用它来创建一个 Spring org.springframework.http.client.reactive.ClientHttpConnector,如下所示。

                ConnectionProvider connectionProvider = ConnectionProvider.builder("Name")
                        .maxIdleTime(Duration.ofSeconds(10))
                        .build();
                HttpClient httpClient = HttpClient.create(connectionProvider)
                        .compress(true);
                return WebClient.builder()
                        .clientConnector(new ReactorClientHttpConnector(httpClient))
                        .baseUrl(host);
        

        【讨论】:

          猜你喜欢
          • 2010-11-25
          • 2012-04-02
          • 2019-05-04
          • 1970-01-01
          • 2020-04-29
          • 1970-01-01
          • 2021-07-11
          • 2014-12-04
          • 2016-12-05
          相关资源
          最近更新 更多