我的编程空间,编程开发者的网络收藏夹
学习永远不晚

浅谈springcloud gateway 连接保活问题

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

浅谈springcloud gateway 连接保活问题

项目中使用了springcloud gateway作为网关,上游与负载均衡服务器连接。

近期通过监控系统观察,发现网关与上游负载均衡服务器保持的TCP连接有300+,初步怀疑是调用方未释放连接

用如下方法进行分析:

1)周期性采集当前建立的连接及端口数据

首先是每隔10分钟连续采集2两个小时,发现在两个小时之内新出现的端口不到12个,再逐步缩短采样周期,到最后每秒采集一次,分析发现每秒种建立一个连接,同时关闭一个连接,当仍存在300+连接,这些连接对应的端口称为不活跃端口,记录下这300+不活跃端口。

2)为了进一步分析,用whireshark抓包

发现绝大部分情况下都是正常的连接和关闭,但这300+个不活跃端口对应的连接上没有任何数据,这300+个不活跃对应的连接称为不活跃连接。同步赶紧上马接口调用实时监控功能,发现实际的调用数量却非常少(每分钟不足10个)。

3)与上游的负载均衡工程师一起检查

从负载均衡服务器看到的活跃连接也是个位数,并且并未找到在网关上的不活跃端口。也就是说在负载均衡服务器已经已经拆除了与网关上的不活跃连接对应的连接。咨询负载均衡工程师,负载均衡设备对于1超过1个小时的不活跃连接会主动拆除。

经过以上分析,确定是外部系统经过负载均衡设备与网关建立连接后,并未进行任何操作,但网关会一直维护这个连接,导致网关的连接数持续上升。

为解决这个问题,需要首先回顾一下传统的TCP长连接维护机制

针对长连接的维护,传统的TCP服务采用心跳来维持,比如服务端每分钟发送一个心跳报文,并启动计数器并设置为1,客户端收到后回应一个报文,服务端收到回复报文后重置计数器,如果为收到应答,则一分钟再发送一个心跳报文,同时计数器加1,连续发送三个心跳报文并且未收到映带,则服务端则认为客户端已经失联,会主动拆除这个连接,以避免不必要的资源占用。

我们现在使用的springcloud gateway,显然很难直接修改源码增加以上的心跳机制,所以我又想到了操作系统协议栈的连接保活机制。

TCP协议栈的保活机制与应用层的长连接维护机制类似(当然,应用层的TCP长连接维护机制就是从协议栈的保护机制学习来的'&'),只不过是在协议栈层面完成,这样避免了应用层实现负载的长连接维护

保活机制如下:

1)服务器端判断一个连接在指定的时间内

(缺省为2小时)没有任何数据,则发送一个探测报文,并启动定时器

2)如果客户端在正常运行并且网络可达

则客户端则回复一个响应报文,服务端认为客户端正常,则重新开始计时。

如果客户端主机崩溃或网络不可达,服务端将收不到应答,定时器超时后(一般为75秒),服务端将再次发送探测报文,如此连续发送若干次(一般为10次),如果均未收到应答,则服务端将主动关闭连接。

当然,如果中间有任何一次服务端收到应答,则认为连接正常,不再发送探测报文。

使用如下命令可以查看以上保活时间、发送探测报文的间隔和次数:


#sysctl -a|grep keepalive
net.ipv4.tcp_keepalive_time = 7200(单位为秒)
net.ipv4.tcp_keepalive_probes = 9 
net.ipv4.tcp_keepalive_intvl = 75  (单位为秒)

关于保活参数中两个小时的时间设置存在争议,通常人们希望这个值可以小很多,比如分钟级,但保活间隔时间是系统级别的变量,如果改变该值会影响所有使用该功能的用户。

所以,Host Requirements RFC提出一个实现方式,保活间隔是可配置的,但缺省不小于两个小时,并且需要应用程序设置才启用。

如果使用协议栈的保活功能,那么缺省的两个小时的时间还是太长,如果缩短这个时间会有什么影响,并无把握。

所以还是先想其他办法,从网上看到可以通过以下代码修改网关对长连接的维护办法,以下代码是设置保活时间为3分钟,如果3分钟内连接上没有数据,网关将主动关闭连接:

配置文件:


server:
    netty:
        idie-timeout: 300
@Configuration
public class NettyConfig {
    @Bean
    publiWebServerFactoryCustomizer<NettyReactiveWebServerFactory> idleTimeoutCustomizer(
        @Value("${server.netty.idle-timeout}") Duration idleTimeout) {
        return factory -> 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) {
                                   private final AtomicBoolean closed = new AtomicBoolean();
                                   @Override
                                   protected void channelIdle(
                                       ChannelHandlerContext ctx, IdleStateEvent evt) {
                                           if (closed.compareAndSet(false, true)) {
                                               ctx.close();
                                           }
                                       }
                                   }
                               );
                           }
                       }))));
    }
}

系统上线后,通过监控系统发现网关连接数并未持续增长,刚松一口气,线上业务系统频频报错,请求网关失败,赶紧安排网络抓包,然后马上回退恢复业务。

然后对网络抓包进行分析,截图如下:

从抓包结果来看,客户端和网关经过3次握手后,建立了连接,但后面的建立SSL的过程中,网关返回了400 Bad Request,所以导致业务系统请求失败(业务系统使用https请求网关),怀疑是上面的代码中的配置覆盖了配置文件中SSL的相关配置,所以导致SSL连接未建立。

我们优秀的工程师,本着锲而不舍的精神对gateway进行源码分析,经过对代码的分析,发现确实是这个配置覆盖了原有的SSL配置,导致SSL配置未生效所致,所以对以上代码进行改写,具体如下:


@Configuration
public class NettyConfig {
    @Bean
    publiWebServerFactoryCustomizer<NettyReactiveWebServerFactory> idleTimeoutCustomizer(
        @Value("${server.netty.idle-timeout}") Duration idleTimeout) {
        return factory -> factory.addServerCustomizers(
            server -> server.tcpConfiguration(
                tcp->tcp.bootstrap(bootstrap->{
                  //增加如下代码,从而可保持原有配置并追加保活
                   BootstrapHandlers.updateConfiguration(bootstrap, "IdleStateHandler",
                      (connectionObserver, channel) ->{
                       channel.pipeline().addLast(new IdleStateHandler(0, 0,
                           idleTimeout.toNanos(), NANOSECONDS) {
                                 private final AtomicBoolean closed = new AtomicBoolean();
                                 @Override
                                 protected void channelIdle(ChannelHandlerContext ctx,
                                     IdleStateEvent evt) {
                                     if (closed.compareAndSet(false, true)) {
                                         ctx.close();
                                     }
                                 }
                             });
                         });
                        return bootstrap;
                    }
                )));
    }
}

进行测试验证,一切OK!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

浅谈springcloud gateway 连接保活问题

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何解决springcloud gateway连接保活问题

这篇文章主要介绍“如何解决springcloud gateway连接保活问题”,在日常操作中,相信很多人在如何解决springcloud gateway连接保活问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答
2023-06-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录