繁体   English   中英

如何在reactor-netty中配置池连接空闲超时

[英]how to configure pooled connection idle timeout in reactor-netty

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

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

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

我设法配置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挂钩期间添加处理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 netty 0.9.x 中,将有一个标准的方法来为连接池中的连接配置空闲超时,请参阅此提交: https : //github.com/reactor/reactor-netty/pull/792

通过向通道管道添加 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());

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

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

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

使用这种方法你不能配置超时,但你可以禁用它:

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

对于 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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM