记录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不算小。

目录
相关文章
|
前端开发
dataTable列内容过长隐藏
dataTable列内容过长隐藏
148 0
|
安全 Linux 数据安全/隐私保护
6.4.2 文件隐藏属性
6.4.2 文件隐藏属性
73 0
MPAndroidChart_并列柱状图,及如何实现点击隐藏掉不需要的条目。
在比赛中遇到了MP的并列柱状图,看网上对这方面记录并不是很多,所以今天就做一个教程吧。
206 0
MPAndroidChart_并列柱状图,及如何实现点击隐藏掉不需要的条目。
记录列表滚动位置
记录列表滚动位置
|
JavaScript
使用jQuery 中的显示与隐藏动画效果实现折叠下拉菜单的收缩和展开,在页面的列表中有若干项,列表的每项中有一个二级列表,二级列表默认为隐藏状态。点击列表的项,切换二级列表的显示或隐藏状态
使用jQuery 中的显示与隐藏动画效果实现折叠下拉菜单的收缩和展开,在页面的列表中有若干项,列表的每项中有一个二级列表,二级列表默认为隐藏状态。点击列表的项,切换二级列表的显示或隐藏状态
437 0
使用jQuery 中的显示与隐藏动画效果实现折叠下拉菜单的收缩和展开,在页面的列表中有若干项,列表的每项中有一个二级列表,二级列表默认为隐藏状态。点击列表的项,切换二级列表的显示或隐藏状态
|
C# 编译器
C#隐藏方法
不能删除基类的任何成员,但可以用与基类成员相同的成员来屏蔽基类成员 屏蔽数据成员:派生类中声明名称和类型相同的成员 屏蔽函数成员:在派生类中声明新的带有函数签名的成员 让编译器知道:添加new关键字,否则会警告pet petpu.
708 0
动态隐藏行
动态隐藏行
853 0
|
Web App开发 测试技术