记录SpringCloudGateway的一个隐藏问题

简介: 线上生产环境中,一个SCG接口偶发性出现“Connection reset by peer”错误。排查发现问题是由于Netty的HTTP客户端连接池保持了已由服务端关闭的连接。解决方案是配置连接池以在超时后回收连接(超时时间应小于Tomcat的连接超时时间),并考虑将连接池获取策略从FIFO改为LIFO,以减少使用无效连接的可能性。通过修改Spring Cloud Gateway的HTTP客户端连接池配置和添加JVM启动参数可以实现这一修复。

问题现象:

今天遇到一个SCG的问题,线上生产环境在请求一个接口的时候,偶发性的会出现报错

io.netty.channel.unix.Errors$NativeIoException: readAddress(..) failed: Connection reset by peer

排查过程

看到这个错误的第一反应是连接被服务端关闭了,以为是服务端的问题,但是经过测试,不通过网关直接访问该服务时,是没有任何问题的,因此将目光聚焦到了SCG上,通过排查SCG的日志,发现确实是在网关层出现该问题,具体问题报错如上。

针对这个错误,去百度了一下,发现是因为scg底层netty的问题导致的,参考文章链接:https://blog.csdn.net/qq_22903677/article/details/128990516

然后在netty的github issues上也找到了对应的问题:https://github.com/reactor/reactor-netty/issues/938

大概意思如下:

netty为了节省开销,搞了一个http client的连接池,这个连接池维护了后端tomcat的连接,如果下次有请求过来,会先查连接池里是否有可复用的连接,如果有直接使用该连接

问题原因

问题就出现在这个连接池这,netty搞的这个连接池默认是不释放连接的,从连接池取用连接的策略默认是FIFO先入先出,也就是会取最早的连接,而tomcat连接是有最大空闲连接时间限制的,也就是说tomcat连接可能已经关闭了,但是netty的连接池里还保留这个连接,当netty使用已关闭的连接的时候就会报这个错误。

如下图:

解决办法

那么解决办法很明显了:

  1. 给netty的httpclient连接池增加限制,在连接超时后回收连接,此连接超时时间需小于tomcat连接超时时间
  2. 修改netty的httpclient连接池的获取连接策略,由FIFO改为LIFO,即每次获取最新的连接,最大限度保证获取的连接不是无效连接

具体配置如下:

修改连接池配置:

spring:
  cloud:
    gateway:
      httpclient:
        pool:
          type: fixed
          max-idle-time: 5000
          max-connections: 200
          acquire-timeout: 45000

修改连接池获取策略为LIFO:

增加jvm启动参数 -Dreactor.netty.pool.leasingStrategy=lifo

注:本人只配置了第一个修改连接池属性的参数,并未配置lifo,也可以生效;个人感觉仅配置lifo策略应该还会出现该问题,重点的配置仍然是连接池配置。

PS

一点小探究:

连接池的max-connections参数原理:

因为新增了http clinent的最大连接数的配置,不确定这个配置是否合理,因此看下这个参数的默认值,避免生产环境出现问题:

这个配置是通过SCG的HttpClientProperties类接受的

向下找到pool类

可以看到maxConnections的默认值为ConnectionProvider.DEFAULT_POOL_MAX_CONNECTIONS;

int DEFAULT_POOL_MAX_CONNECTIONS = Integer.parseInt(System.getProperty("reactor.netty.pool.maxConnections", "" + Math.max(Runtime.getRuntime().availableProcessors(), 8) * 2));

而默认最大连接数是跟处理器数量有关系,默认为16(8处理器一下),因此最大连接数设置为200不算小。

目录
相关文章
|
前端开发 Java 应用服务中间件
Gateway网关使用不规范,同事加班泪两行~
Gateway网关使用不规范,同事加班泪两行~
Gateway网关使用不规范,同事加班泪两行~
|
缓存
SpringCloud Gateway 网关的请求体body的读取和修改
SpringCloud Gateway 框架中,为了处理请求体body,实现多次读取与修改,创建了一个名为`RequestParamGlobalFilter`的全局过滤器。这个过滤器使用`@Component`和`@Slf4j`注解,实现了`GlobalFilter`和`Ordered`接口,设置最高优先级以首先读取body。它通过缓存请求体并创建装饰过的`ServerHttpRequest`来实现body的动态获取。
1845 4
|
存储 Java 网络安全
SpringCloud GateWay配置(TLS 和 SSL、Http超时配置)—官方原版
SpringCloud GateWay配置(TLS 和 SSL、Http超时配置)—官方原版
1723 0
|
4月前
|
缓存 监控 Java
说一说 SpringCloud Gateway 堆外内存溢出排查
我是小假 期待与你的下一次相遇 ~
524 5
|
消息中间件 JSON Java
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
24145 0
|
Java 微服务 Spring
SpringCloud gateway自定义请求的 httpClient
SpringCloud gateway自定义请求的 httpClient
502 3
|
安全 Java 开发者
强大!Spring Cloud Gateway新特性及高级开发技巧
在微服务架构日益盛行的今天,网关作为微服务架构中的关键组件,承担着路由、安全、监控、限流等多重职责。Spring Cloud Gateway作为新一代的微服务网关,凭借其基于Spring Framework 5、Project Reactor和Spring Boot 2.0的强大技术栈,正逐步成为业界的主流选择。本文将深入探讨Spring Cloud Gateway的新特性及高级开发技巧,助力开发者更好地掌握这一强大的网关工具。
618 6
|
Java API 网络架构
Spring Cloud Gateway的高级配置与实践
Spring Cloud Gateway的高级配置与实践
|
Prometheus 监控 Cloud Native
Spring Boot中使用Micrometer进行指标监控
Spring Boot中使用Micrometer进行指标监控
|
Java Nacos 网络架构
SpringCloud Gateway的使用 + Nacos动态路由
SpringCloud Gateway的使用 + Nacos动态路由