最近有一个项目访问量突然变大,但发现前端的nginx负载会很高,导致出现4xx和5xx的异常,响应时间也变长了。今天有时间,解决了一下。下面记录一下解决思路和方法。 我们这个项目部署在azure。最前端是azure 的负载均衡器(lb),lb后面是2台nginx主机,型号是D2v3(2核8G)。在我们实际使用中,一台nginx主机rpm达到30k,cpu,内存,网络都是没有任何压力的。所以一台主机支持的最大访问量应该远远大于30k。但今天这个项目rpm撑到3k的时候,系统负载就很高了。这个项目后端应用向客户端下发一些数据,所以会比一般的项目流量大上很多。

下面是处理过程: 1、查看监控 通过grafana发现,系统cpu负载已经超过了2,最高的时候都超过了3,并且cpu消耗在io上的时间平均占到了20%左右。通过对比同时段的磁盘读写情况,基本可以断定是磁盘IO不够导致的。 但是磁盘IO为什么会不够呢? 2、磁盘IO慢,首先想到的是不是因为日志写的太多了。所以尝试给nginx设置日志buffer和刷新时间。 给access_log 增加两个参数buffer=512k flush=2s。表示日志攒够512k写一次磁盘。如果buffer没写满,强制2秒写一次磁盘。 修改后,观察效果,发现变化不大。所以断定,应该不是写日志导致的。 3、通过iostat命令来确定是那块磁盘有问题。 sda是系统分区所用磁盘,系统和软件会装在这个目录。sdb是azure自带的临时目录所用磁盘,重启主机后会情况。sdd是我们的数据目录所用磁盘,日志会放到这个目录。通过iostat发现,io压力主要集中在sda上。这就进一步能确定iowait跟nginx日志无关。 因为通过iotop发现确实是nginx进程在进行大量的写操作,所以断定应该是nginx proxy时将数据临时写入本地磁盘了。 4、nginx有几个相关的参数。

proxy_buffering:   设置是否缓存后端的responses。默认值是on,开启缓存。
proxy_temp_file_write_size:  开启缓存后,此值限制每次写入临时文件的大小。默认8k或者16k。
proxy_max_temp_file_size: 此值限制缓存文件的最大值。默认1G
proxy_temp_path: 指定缓存文件目录。可以在http,server和location分别定义。

5、根据azure的文档,os磁盘性能不是特别好,建议只运行系统。所以我把nginx的缓存目录全部改到我们的数据目录上。经测试,性能会好一些,但系统负载和iowait依然比较搞,但是异常少了很多。 6、彻底解决这个问题,应该是上性能更好的ssd。但是出于成本的考虑,并且项目访问总量不是也别大,估计同时需要缓存的文件不会很多,所以我决定将这个项目的proxy 缓存目录设置到内存盘里。 7、现在linux一般会开启tmpfs,就是系统将内存挂载到系统目录/dev/shm上。这个目录对应的是系统内存。默认大小为系统总内存的一半,但是并不真正占用这么多内存,其他应用依然可以使用这部分内存。相比自己创建ramdisk,少了格式化的操作,可谓是开箱即用。 8、为这是项目指定proxy_temp_path 到/dev/shm目录里

proxy_temp_path /dev/shm/proxy_temp 1 2;

修改后,iowait瞬间将为0,系统负载也降到0.1以下。/dev/shm只多了2g左右空间使用。 9、做好内存相关的监控,防止内存缓存文件撑爆内存。 至此,这件事情完美解决。