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-
·
版本说明
<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相关依赖
也许会有性能提升,待验证
更多推荐
已为社区贡献5条内容
所有评论(0)