具体问题列表
1.流量上涨导致系统响应缓慢
1.1 问题及背景
小公司小项目,经过运营同事的努力,流量缓慢上涨,突然有一天,大量客户反馈系统很慢很卡,于是对后端Java系统进行排查。
话说前头,这种情况其实直接加钱升级服务器,升级数据库,服务器扩容,完全可以解决。但还是尽量尝试找一下解决的办法,对项目和程序员都有好处。
1.2 解决过程记录
给系统加上统一的接口入参打印和耗时打印日志,收集到SLS(阿里云的日志收集服务),找到耗时比较高的接口。
通过Arthas定位到接口耗时的比较高的方法。参阅接口耗时问题排查。
发现是从
Redis
中获取数据时的遇到的问题,但是在阿里云Redis
控制台又没看到慢日志的打印,此时慢日志的参数设置是默认值slowlog-log-slower-than=20000(20ms)
。猜测是网络问题。接着排查服务器中网络的问题。参阅网络连接相关问题排查。
发现当请求量大的时候,Java进程产生了大量的
TIME_WAIT
(大概是四五千个),处于ESTABLISHED
状态的才几百个,感觉不对劲。于是找到TIME_WAIT
与之对应的远程ip均来自同一网段,猜测应该是来自于阿里云的CLB(负载均衡服务)
集群。猜测应该是CLB集群
和Java服务
之间没有复用连接。检查
Java服务
的配置文件,使用Spring Boot
的tomcat
,项目配置如下:server: tomcat: keep-alive-timeout: 15000 connection-timeout: 15000 max-keep-alive-requests: 100
可以发现
Java服务
是配置了keep-alive
的,但是依旧产生了TIME_WAIT
。然后想到
TIME_WAIT
是来自于主动关闭连接的一方,于是猜测可能前端在请求头
中加上了Connection: close
参数,于是将前端请求头打印在统一日志中,在SLS
中看到,确实Java服务
收到的请求中,请求头都是带Connection: close
。怀疑是
CLB
的配置不对,于是在CLB
控制台查找,并翻阅官方文档,发现并没有相关配置可以控制。询问前端同事,前端使用的是
HTTP/2.0
的库,又检查后端配置文件,发现没有启用HTTP/2.0
,于是修改配置文件如下:
server:
http2:
enabled: true
改之前
通过curl
发起测试请求,请求及响应如下:
# curl请求如下
curl --location --request GET 'http://your_ip:your_port/your_end_point' \
--header 'Content-Type: application/json' \
--data-raw '{
"your_field": "your_value"
}' \
--http2
# 响应正常,此处不展示
# 日志输出如下:
{"protocol":"HTTP/1.1","connection":"Upgrade, HTTP2-Settings"}
# 可见依旧使用 HTTP/1.1 的请求
改之后
通过同样curl
发起测试请求,请求及响应如下:
# curl请求如下
curl --location --request GET 'http://your_ip:your_port/your_end_point' \
--header 'Content-Type: application/json' \
--data-raw '{
"your_field": "your_value"
}' \
--http2
# 响应正常,此处不展示
# 日志输出如下:
{"protocol":"HTTP/2.0","connection":"Upgrade, HTTP2-Settings"}
# 可成功使用 HTTP/2.0 的请求
经过测试,不影响其他接口,后端发版上线。
上线后查看日志,发现请求头输出依旧如下,问题没有得到解决。
{"protocol":"HTTP/1.1","connection":"close"}
再次找到前端同事,前端同事排查,发现前端使用的请求框架有问题,交给前端同事处理便没了下文(因为大家都忙,暂时选择加机器解决)。
转头一想:
- 上述案例中,客户端请求打到负载均衡,确实也没有必要设置
keep-alive
,但是负载均衡和后端服务器之间,应该是要复用连接的,但是没有办法配置CLB
,所以这条路也没有办法走下去,除非自建Nginx集群
,但当时用云服务,就是为了图方便省事,并且小公司目前也没有那么多时间精力和人力去做基建,遂暂时搁置。 - 前端的请求,是不是经过
CLB
转发之后,从HTTP/2.0
变成了HTTP/1.1
呢?后续经过本地联调, 发现不是CLB
的问题,所以又只能搁置,毕竟不在我的控制范围内了。 - 问过
GPT
后,其说在并发大的系统中,存在大量的TIME_WAIT
也很正常,也不至于导致请求一个Redis
要好几秒,查看Redis
的控制台监控,那时连接数也才三四百,CPU利用率
也才5%
,Redis内存利用率
也只有百分之几,于是猜测可能是项目的配置上有问题。
- 上述案例中,客户端请求打到负载均衡,确实也没有必要设置
后面抽时间对项目的Redis配置又进行了一番调参测试和debug,确实发现一些问题,先留坑,后面空了再写。