简体   繁体   English

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

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

I am using reactor-netty http client (0.7.X series) with connection pooling and would like to configure pooled connection's idle timeout but don't know where.我正在使用具有连接池的 reactor-netty http 客户端(0.7.X 系列),并且想配置池连接的空闲超时,但不知道在哪里。

More precisely, I need to configure reactor-netty http client connection pool in such a way that it will automatically close connections that did not see any activity within configurable timeout.更准确地说,我需要以这样一种方式配置 reactor-netty http 客户端连接池,它会自动关闭在可配置超时内没有看到任何活动的连接。 These connections are open but no bytes were transferred in or out for some (configurable) amount of time.这些连接是打开的,但在某些(可配置的)时间内没有字节传入或传出。

How can I configure reactory-netty http client to close idle connections preemptively?如何配置 reactor-netty http 客户端以抢先关闭空闲连接?

I managed to configure WebClient (via underlying TcpClient ) to remove idle connections on timeout from connection pool in reactor-netty 0.8.9我设法配置WebClient (通过底层TcpClient )以从reactor-netty 0.8.9 中的连接池中删除超时时的空闲连接

My solution is partially based on the official documentation about IdleStateHandler extended with my research on how to properly apply it when creating an instance of HttpClient .我的解决方案部分基于关于IdleStateHandler的官方文档,扩展了我对如何在创建HttpClient实例时正确应用它的研究。

Here is how I did that:这是我如何做到的:

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();
}


IMPORTANT UPDATE:重要更新:

My further testing has indicated that adding handlers during bootstrap hook distructs the pool and sockets (channels) are not reused by Connection .我的进一步测试表明,在bootstrap挂钩期间添加处理bootstrap破坏池和套接字(通道)不会被Connection重用。

The right way to add the handlers is:添加处理程序的正确方法是:

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();
}

Note: in reactor-netty 0.9.x there will be a standard way to configure idle timeout for connections in the connection pool, see this commit: https://github.com/reactor/reactor-netty/pull/792注意:在reactor-netty netty 0.9.x 中,将有一个标准的方法来为连接池中的连接配置空闲超时,请参阅此提交: https : //github.com/reactor/reactor-netty/pull/792

I was able to accomplish this on the 0.7.x branch by adding netty write and read time-out handlers to the channel pipeline.通过向通道管道添加 netty 写入和读取超时处理程序,我能够在 0.7.x 分支上完成此操作。 However, on 0.8.x, this approach no longer works.但是,在 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());

The easiest way to do this in reactor-netty 0.9.x with TCP client is by using the below approach, I got this from the link referred by @Vladimir-L.在具有 TCP 客户端的 reactor-netty 0.9.x 中执行此操作的最简单方法是使用以下方法,这是我从 @Vladimir-L 引用的链接中获得的。 Configure "maxIdleTime" for your question.为您的问题配置“maxIdleTime”。

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

I am currently at reactor-netty 0.8.2 because of spring-boot-starter-webflux and faced the same issue, the connection pool kept connections open for 60 seconds after they were finished.由于 spring-boot-starter-webflux 我目前在 reactor-netty 0.8.2 并面临同样的问题,连接池在连接完成后保持连接打开 60 秒。

With this approach you can't configure the timeout, but you can disable it:使用这种方法你不能配置超时,但你可以禁用它:

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

For Reactor Netty version 1 you need to create a reactor.netty.resources.ConnectionProvider which will contain the idle time configuration and then use that when creating the reactor.netty.http.client.HttpClient .对于 Reactor Netty 版本 1,您需要创建一个reactor.netty.resources.ConnectionProvider ,它将包含空闲时间配置,然后在创建reactor.netty.http.client.HttpClient时使用它。

I'm using Spring so I then use that to create a Spring org.springframework.http.client.reactive.ClientHttpConnector as shown below.我正在使用 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