java · 2023-09-12 0

服务器io偏高排查记录

有个朋友从阿里云买了一台低配的轻量应用服务器,内存只有1GB,在上面部署安装了ubuntu,apache http server 2,php和mysql,使用wordpress搭了一个个人博客,系统稳定运行了一段时间。

这个朋友是写Java的,用Spring Boot开发了一个Java应用,也部署到了这台轻量服务器。为了复用域名和证书,使用了apache2的proxypass转发特定路径的请求到这个Java应用。apache2的配置大概如下:

ProxyPass "/webapp1/" "http://localhost:8080/webapp1/"
ProxyPassReverse "/webapp1/" "http://localhost:8080/webapp1/"
ProxyPreserveHost On
ProxyPassReverseCookieDomain "localhost" "xxxx.com"
ProxyPassReverseCookiePath "/webapp1/" "/webapp1/"

配置完后,重启apache2后,应用可以正常访问了。但是没过一会儿,发现Java应用无法访问了,原来的个人博客也打不开了,都提示响应超时。自己排查了很久,无从下手,于是找我来帮忙。

我首先登录了阿里云轻量应用服务器的控制台,查看实例的监控数据,发现IO突然增高,磁盘每秒读次数从个位数窜到了2000多,cpu使用率也从接近0涨到了30%左右,其他指标,比如网络流量,网络带宽都是正常的水位没有变化。

由于阿里云轻量服务器的控制台监控数据比较少,因此,我远程登录到了服务器上,发现ssh登录响应也很慢,好不容易登录进去,执行top命令,发现内存使用90%,load大概5-7左右。

仔细看了每个进程的cpu和内存占比,发现有一个进程【kswapd0】很奇怪,使用cpu特别高。网上搜索了下,这个进程是Ubuntu系统里负责换页(RAM内存和交换分区)管理的。也就意味着RAM内存不够用了。使用top命令查看进程内存的使用,发现mysqld这个进程占了40%多的内存(400多MB),再加上部署的Java Spring Boot应用(也是吃内存的大户),肯定是把1GB的内存吃光了。

当时觉得mysql服务使用400多MB内存有点奇怪,因为没多少数据量,博客的并发连接也很低,竟然占了这么多内存。于是继续网上搜索,发现mysql内存占用高,可能有很多原因,排除数据量和并发度,有一个原因是开启了mysql的performance schema(https://dev.mysql.com/doc/refman/8.0/en/performance-schema-quick-start.html)导致吃内存的,performance schema主要是用于性能监测。个人使用其实没必要,可以关闭此特性。于是修改了my.conf配置文件:

[mysqld]
performance_schema=OFF

使用

sudo service mysql stop/start

重启mysql服务,通过top再次查看内存占比,只有17%左右了(大概170多MB),问题解决了。当然还可以继续调整mysql的配置来降低内存使用,不过已经没有必要了,性价比不高。

当然排查过程不是一帆风顺的。比如:
1)由于系统load高,曾经多次ssh登录不上去,想要通过安装iotop来查看导致io高的进程也因为系统load高而无法安装。关键时刻还是手动重启了几次服务器。
2)由于在配置apache2的proxypass来转发请求时,使用a2enmod开启了apache的几个模块,因此最开始怀疑是开启的模块有问题导致的。

当然,以上只是排查过程的记录,还有一些知识点值得后续深入了解,比如内存吃紧导致换页进程工作造成磁盘读升高,系统为啥没有杀死吃内存的进程,Java进程为啥没OOM,MySQL的performance schema的机制等等。

以上,容我喝完朋友的咖啡,再去细细研究。