org.apache.http.ConnectionClosedException: 连接已关闭 - PoolingNHttpClientConnectionManager

org.apache.http.ConnectionClosedException: Connection closed - PoolingNHttpClientConnectionManager

我们在生产中经常遇到以下错误。原因是,服务器关闭了连接,而客户端正在尝试使用半关闭的陈旧连接。我们有每 80 分钟定期运行一次的驱逐策略,它将检查过期和空闲连接并关闭它们。我们仍然收到此错误。我们计划将驱逐线程间隔减少到 40 分钟。是否有任何其他解决方案可用于阻止此错误?

我们正在使用 PoolingNHttpClientConnectionManager。空闲期超时为 60 seconds.httpasyncclient 版本为 4.1.1.

org.apache.http.ConnectionClosedException: Connection closed
        at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.endOfInput(HttpAsyncRequestExecutor.java:341)
        at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:263)
        at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
        at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
        at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:123)
        at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278)
        at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
        at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590)
        at java.lang.Thread.run(Thread.java:748)

有两种选择:

  1. 在连接管理器构建时为所有连接定义一个有限的 TTL(总生存时间)限制
  2. 使用自定义 ConnectionKeepAliveStrategy 实现来强制持久连接的相对过期时间。

这里是 HttpAsyncClient 配置的示例,强制执行 2 分钟的总生存时间限制和 30 秒的相对过期时间

请注意,这可能无法完全消除问题,因为端点(客户端和服务器)可能会在没有事先握手的情况下随时关闭连接。

ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.custom()
        .build());
PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(
        ioReactor,
        ManagedNHttpClientConnectionFactory.INSTANCE,
        RegistryBuilder.<SchemeIOSessionStrategy>create()
                .register("http", NoopIOSessionStrategy.INSTANCE)
                .register("https", SSLIOSessionStrategy.getSystemDefaultStrategy())
                .build(),
        DefaultSchemePortResolver.INSTANCE,
        SystemDefaultDnsResolver.INSTANCE,
        2,
        TimeUnit.MINUTES);
CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setConnectionManager(cm)
        .setConnectionManagerShared(false)
        .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy() {
            @Override
            public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                long keepAliveDuration = super.getKeepAliveDuration(response, context);
                if (keepAliveDuration > 30000) {
                    keepAliveDuration = 30000;
                }
                return keepAliveDuration;
            }
        })
        .build();