首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为Spring WebFlux配置netty连接超时

如何为Spring WebFlux配置netty连接超时
EN

Stack Overflow用户
提问于 2018-12-03 12:45:41
回答 2查看 7.7K关注 0票数 5

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

代码语言:javascript
复制
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服务器上的连接超时。我已尝试在我的application.yml中设置server.connection-timeout属性...

代码语言:javascript
复制
server:
  connection-timeout: 75000

也可以通过指定秒...

代码语言:javascript
复制
server:
  connection-timeout: 75s

但是当我运行time命令来查看我的连接持续了多长时间时,这并没有改变超时,它仍然在10秒内结束……

代码语言:javascript
复制
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

这里我漏掉了什么?

EN

回答 2

Stack Overflow用户

发布于 2018-12-03 17:11:49

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

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

下面是一个完整的例子:

代码语言:javascript
复制
@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)))));
        }
    }

}

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

代码语言:javascript
复制
@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命令,到目前为止还没有超时。

代码语言:javascript
复制
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-cloud-gateway标签--也许这是特定于该项目的东西?

票数 8
EN

Stack Overflow用户

发布于 2019-10-02 13:54:37

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

对于Netty来说,这不是该属性目前所做的事情。现在,该属性控制TCP连接握手超时,这是完全不同的事情。

这里有更多关于这方面的信息,这是一个如何在https://github.com/spring-projects/spring-boot/issues/18473上实际配置空闲/保活超时的示例

具体地说,您可以使用类似以下内容:

代码语言:javascript
复制
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;
    }

}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53587611

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档