【问题标题】:How to configure netty connection-timeout for Spring WebFlux如何为 Spring WebFlux 配置 netty 连接超时
【发布时间】:2019-05-04 09:13:44
【问题描述】:

我在 AWS 负载均衡器后面运行 spring 云网关(我理解它是基于 Spring Webflux 构建的),我收到间歇性的 502 错误。经调查,问题似乎与负载均衡器和我的节点之间的连接超时有关。从一些调查看来,底层网络服务器的默认超时时间为 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 服务器上的连接超时。我试图在我的 application.yml 中设置 server.connection-timeout 属性...

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

我在这里错过了什么?

【问题讨论】:

    标签: spring-webflux spring-cloud-gateway reactor-netty


    【解决方案1】:

    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实际配置空闲/保持活动超时的示例

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

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

    【讨论】:

      【解决方案2】:

      Netty 服务器不支持server.connection-timeout 配置密钥(目前),我已经提出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-cloud-gateway 标签 - 也许这是该项目特有的东西?

      【讨论】:

      • 我已经实现了这个,但我仍然得到相同的结果。我应该使用 CONNECT_TIMEOUT 属性吗?本质上,根据我为这个场景阅读的所有内容,我需要相当于 Apache KeepAlive。我可以在 Netty 中设置 KeepAlive 属性吗?
      • 那是一个不同的问题 - 我已经编辑了我的答案
      • 感谢您为此提供的所有帮助,Brian。不幸的是,我仍然遇到同样的问题。在我应用了您推荐的方法后,服务器仍然会在 10 秒后终止连接。我正在使用提到的“time nc”命令对此进行测试。
      • 我已经编辑了我的答案(代码 sn-p 错误)。但我无法重现您的问题。请参阅我编辑的答案的最后一部分。
      • 我需要能够在不拨打电话的情况下保持与运行 netty 的服务器上的端口的连接打开。 Tomcat 开箱即用,默认为 60 秒。这基本上就是我要找的
      猜你喜欢
      • 2019-01-03
      • 2018-06-14
      • 2019-07-12
      • 2018-07-26
      • 2015-12-20
      • 1970-01-01
      • 2019-11-23
      • 2018-02-24
      • 2021-05-16
      相关资源
      最近更新 更多