如何为SpringWebFlux配置netty连接超时



我正在AWS负载均衡器后面运行spring云网关(据我所知,它是在spring Webflux上构建的(,我收到了间歇性的502个错误。经过调查,这个问题似乎与负载平衡器和我的节点之间的连接超时有关。从一些调查来看,底层netty服务器的默认超时时间为10秒。我使用以下命令确定了这一点。。。

time nc -vv 10.10.xx.xxx 5100
Connection to 10.10.xx.xxx 5100 port [tcp/*] succeeded!
real    0m10.009s
user    0m0.000s
sys     0m0.000s

虽然我可以将负载均衡器上的idleTimeout设置为10秒以下,但这感觉效率很低。如果可能的话,我希望保持在30秒以上。相反,我想增加netty服务器上的连接超时。我已尝试在我的应用程序中设置server.connection-timeout属性。yml…

server:
connection-timeout: 75000

也可以通过指定秒。。。

server:
connection-timeout: 75s

但当我运行time命令查看我的连接持续多久时,超时时间没有改变,它仍然在10秒结束。。。

time nc -vv 10.10.xx.xxx 5100
Connection to 10.10.xx.xxx 5100 port [tcp/*] succeeded!
real    0m10.009s
user    0m0.000s
sys     0m0.000s

我在这里错过了什么?

server.connection-timeout配置密钥不支持Netty服务器(目前(,我已经提出了spring-boot#15368来解决这个问题。

连接超时大约是我们应该等待建立连接的最长时间。如果您希望自定义读/写超时,则有不同的选项。如果服务器在配置的持续时间内没有从客户端接收到数据,则可以添加一个ReadTimeoutHandler来关闭连接。WriteTimeoutHandler也是如此,但这次是关于服务器向客户端写入数据。

这里有一个完整的例子:

@Configuration
public class ServerConfig {
@Bean
public WebServerFactoryCustomizer serverFactoryCustomizer() {
return new NettyTimeoutCustomizer();
}
class NettyTimeoutCustomizer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Override
public void customize(NettyReactiveWebServerFactory factory) {
int connectionTimeout = //...;
int writetimeout = //...;
factory.addServerCustomizers(server -> server.tcpConfiguration(tcp ->
tcp.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeout)
.doOnConnection(connection ->
connection.addHandlerLast(new WriteTimeoutHandler(writetimeout)))));
}
}
}

现在回到你的问题,我已经用以下控制器测试了该配置:

@RestController
public class TestController {
@GetMapping(path = "/", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> textStream() {
return Flux.interval(Duration.ofSeconds(5)).map(String::valueOf);
}
}

只要间隔短于配置的写入超时,服务器就不会关闭连接。您可以使用httpie和以下命令http localhost:8080/ --stream --timeout 60验证这一点。

我已经在本地机器上测试了这个netcat命令,到目前为止我没有超时。

time nc -vv 192.168.0.28 8080
192.168.0.28 8080 (http-alt) open
^CExiting.
Total received bytes: 0
Total sent bytes: 0
nc -vv 192.168.0.28 8080  0.01s user 0.00s system 0% cpu 2:36.53 total

也许这是在操作系统级别配置的,或者网络设备被配置为关闭此类连接?我刚刚看到你添加了spring云网关标签——也许这是该项目特有的东西?

https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html当前将server.connection-timeout定义为"连接器在关闭连接之前等待另一个HTTP请求的时间。">

对于Netty来说,这不是该房产目前的作用。现在,该属性控制TCP连接握手超时,这是完全不同的。

关于这一点,还有更多信息,例如如何在https://github.com/spring-projects/spring-boot/issues/18473

具体来说,你可以使用这样的东西:

import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
@Configuration
public class NettyConfig {
@Bean
public ReactiveWebServerFactory reactiveWebServerFactory(@Value("${server.netty.idle-timeout}") Duration idleTimeout) {
final NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
factory.addServerCustomizers(server ->
server.tcpConfiguration(tcp ->
tcp.bootstrap(bootstrap -> bootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) {
channel.pipeline().addLast(
new IdleStateHandler(0, 0, idleTimeout.toNanos(), NANOSECONDS),
new ChannelDuplexHandler() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof IdleStateEvent) {
ctx.close();
}
}
}
);
}
}))));
return factory;
}
}

最新更新