簡體   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