当前位置: 首页 > news >正文

Spring Cloud Gateway 服务器性能异常,以及优化策略

版本说明

<spring-boot.version>2.3.2.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>

服务器状态异常

部署模式

nginx + 3台 cloud gateway

现象

nginx连接数异常,直线上升
使用如下命令,查询服务器tcp连接状态发现情况

# 图1命令
netstat -ant|grep TIME_WAIT|wc -l
# 图二命令
netstat -apn|grep 18080 |wc -l # 18080为gateway端口

在这里插入图片描述
服务器出现大量TIME_WAIT
在这里插入图片描述

解决方案,修改内核参数

执行以下命令,编辑系统内核配置。

vi /etc/sysctl.conf

修改或加入以下内容。

# 开启SYN的cookies,当出现SYN等待队列溢出时,启用cookies进行处理
net.ipv4.tcp_syncookies = 1 
# 允许将TIME-WAIT的socket重新用于新的TCP连接。如果新请求的时间戳,比存储的时间戳更大,则系统将会从TIME_WAIT状态的存活连接中选取一个,重新分配给新的请求连接。
net.ipv4.tcp_tw_reuse = 1 
#警告:对于服务端来说,在NAT环境中,开启net.ipv4.tcp_tw_recycle = 1配置可能导致校验时间戳递增,从而影响业务,不建议开启该功能。
# 开启TCP连接中TIME-WAIT的sockets快速回收功能。需要注意的是,该机制也依赖时间戳选项,系统默认开启tcp_timestamps机制,而当系统中的tcp_timestamps和tcp_tw_recycle机制同时开启时,会激活TCP的一种行为,即缓存每个连接最新的时间戳,若后续的请求中时间戳小于缓存的时间戳时,该请求会被视为无效,导致数据包会被丢弃。
# 特别是作为负载均衡服务器的场景,不同客户端请求经过负载均衡服务器的转发,可能被认为是同一个连接,若客户端的时间不一致,对于后端服务器来说,会发生时间戳错乱的情况,因此会导致数据包丢失,从而影响业务。
net.ipv4.tcp_tw_recycle = 1
# 如果socket由服务端要求关闭,则该参数决定了保持在FIN-WAIT-2状态的时间。
net.ipv4.tcp_fin_timeout = 15

刷新配置文件,使其生效

/sbin/sysctl -p 

Gateway配置优化处理

application.yml

spring:
  application:
    name: gateway
  cloud:
    gateway:
      # http连接设置
      httpclient:
        # 全局的响应超时时间,网络链接后,后端服务多久不返回网关就报错 The response timeout.
        response-timeout: PT10S
        # 全局的TCP连接超时时间默认时间是45秒,修改为5秒
        connect-timeout: 5000
        # 链接池配置
        pool:
          # 最大连接数
          max-connections: 10000
          # 最大连接时间
          max-life-time: 10
          # 返回时间
          acquire-timeout: 10
          # 最大空闲时间
          max-idle-time: 10000
          # 设置固定链接池
          type: fixed

server:
  port: 18080
  servlet:
    context-path: /

踩坑点一:连接池类型

spring.cloud.gateway.httpclient.pool.type,该参数一共有三种类型
ELASTIC:弹性链接池,连接数上限为Integer.MAX,默认值就是这个类型
FIXED: 固定连接池,最大连接数采用spring.cloud.gateway.httpclient.pool.max-connections的配置
DISABLED:不使用任何连接池

由于使用了ELASTIC类型,连接数不可控。。。。

踩坑点二:gateway线程数参数设置

@SpringBootApplication
public class GateWayApplication {
    private static final Logger logger = LoggerFactory.getLogger(GateWayApplication.class);

    public static void main(String[] args) {
		// 用几个cpu处理select,如果不是很懂的情况下,可以注释掉
        String ioSelectCount = System.getProperty(ReactorNetty.IO_SELECT_COUNT);
        if(StringUtils.isEmpty(ioSelectCount)){
            String selectCount = "1";
            System.setProperty(ReactorNetty.IO_SELECT_COUNT, selectCount);
            logger.info("未发现设置的参数,启用自定义配置selectCount:{}", selectCount);
        }else{
            logger.info("使用默认值selectCount:{}",ioSelectCount);
        }

		// 设置工作线程数量,最好不要超过cpu * 3
        String ioWorkerCount = System.getProperty(ReactorNetty.IO_WORKER_COUNT);
        if(StringUtils.isEmpty(ioWorkerCount)){
            int cpu = Runtime.getRuntime().availableProcessors();
            // *3 还是 *2 可以根据具体情况设置,默认是 cpu核心数,线程过多,可能会导致服务器上下文切换过多导致cpu更高
            String workerCount = String.valueOf(cpu * 3);
            System.setProperty(ReactorNetty.IO_WORKER_COUNT, workerCount);
            logger.info("未发现设置的参数,启用自定义配置workerCount:{}", workerCount);
        }else{
            logger.info("使用默认值workerCount:{}",ioWorkerCount);
        }


        String poolLeasingStrategy = System.getProperty(ReactorNetty.POOL_LEASING_STRATEGY);
        if(StringUtils.isEmpty(poolLeasingStrategy)){
             // 这个参数的作用是先使用后回收的连接,而不是先使用先回收的连接
            System.setProperty("reactor.netty.pool.leasingStrategy", "lifo");
            logger.info("未发现设置的参数,启用自定义配置leasingStrategy:{}", "lifo");
        }else{
            logger.info("使用默认值leasingStrategy:lifo");
        }

        SpringApplication.run(GateWayApplication.class);
        logger.info("--------------start done--------------");
    }

踩坑点三:可选添加reactor-poll

 <dependency>
  	  <groupId>io.projectreactor.addons</groupId>
     <artifactId>reactor-pool</artifactId>
 </dependency>

功底不够,reactor源码看得不是很懂,但是发现装配时候,缺少reactor-poll相关依赖
也许会有性能提升,待验证

相关文章:

  • 云原生中间件RocketMQ-核心原理之同步_异步刷盘,同步_异步复制解析
  • 计算机网络——数据链路层の选择题整理
  • joi:定义多个自定义错误信息
  • 限流相关算法
  • java计算机毕业设计阳明湖风景区订票系统源码+数据库+系统+lw文档+mybatis+运行部署
  • Java 中所有的锁
  • 【基于Arduino的垃圾分类装置开发教程二传感器执行器操作】
  • java中static关键字具有什么功能呢?
  • springcloud 之gateway配置注意事项
  • JS BOM
  • 领英工具-领英精灵群发消息功能解析
  • [答疑]微信餐馆案例中,“启动二维码对应的程序”这个用例合理吗
  • Defocus(散焦)
  • jvm中对象内存空间的分配与回收
  • Shiro 550、721
  • “大数据应用场景”之隔壁老王(连载四)
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • echarts花样作死的坑
  • ECMAScript6(0):ES6简明参考手册
  • Git 使用集
  • js如何打印object对象
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 基于webpack 的 vue 多页架构
  • 一天一个设计模式之JS实现——适配器模式
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • # 达梦数据库知识点
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (接口封装)
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (十三)Maven插件解析运行机制
  • (算法)Travel Information Center
  • (一一四)第九章编程练习
  • (转)重识new
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .libPaths()设置包加载目录
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .NET 动态调用WebService + WSE + UsernameToken
  • .net 生成二级域名
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .net利用SQLBulkCopy进行数据库之间的大批量数据传递
  • [ JavaScript ] JSON方法
  • [ Linux 长征路第二篇] 基本指令head,tail,date,cal,find,grep,zip,tar,bc,unname
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [Asp.net mvc]国际化
  • [Bada开发]初步入口函数介绍
  • [BT]小迪安全2023学习笔记(第15天:PHP开发-登录验证)
  • [BUUCTF 2018]Online Tool
  • [C#]C# OpenVINO部署yolov8图像分类模型
  • [c]统计数字
  • [c++] 单例模式 + cyberrt TimingWheel 单例分析
  • [C语言]——内存函数
  • [go 反射] 进阶