我有一个运行 nginx 的高流量网络服务器(每秒最多加载约 50 个页面),它将 HTML 请求传递到 PHP-FPM 后端并直接提供静态资产。
在此负载下,我从 nginx 工作进程中获得了非常多的磁盘 I/O。我的页面提供大量每隔几个小时就会更改的静态图像,因此预计会有大量磁盘读取,但实际上我看到写入比读取更多,nginx 进程的持续写入速率约为 10 MB/s(由 iotop 提供)。
我的 docker 容器活跃了 12 天,我获得了其中一个 nginx 进程的 I/O 历史记录:
$ cat /proc/nginx-pid/io
rchar: 34537119315778
wchar: 27295224195419
syscr: 2217567839
syscw: 2285538495
read_bytes: 1499124252672
write_bytes: 7338930909184
cancelled_write_bytes: 141058945024
这意味着 12 天内读取了 1.5TB 的数据,考虑到我的静态资产和流量,这是有道理的,但 nginx 向磁盘写入 7.3TB 的数据对我来说似乎太疯狂了。
time strace -p $nginx_pid -c
以下是60 秒内的输出:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
33.05 0.840451 5 178693 2446 write
16.52 0.420117 4 104554 pread64
10.09 0.256603 6 39772 1 readv
9.24 0.234970 11 20994 pwritev
6.60 0.167708 16 10700 188 open
4.92 0.125204 3 37249 epoll_wait
4.47 0.113708 3 41601 20572 read
3.70 0.094091 23 4154 4154 connect
3.16 0.080408 5 15515 close
1.77 0.045090 11 4260 writev
1.42 0.036188 9 4139 rename
0.92 0.023423 6 4139 chmod
0.68 0.017227 2 10515 fstat
0.57 0.014555 3 5131 epoll_ctl
0.53 0.013573 3 4154 socket
0.53 0.013569 3 4903 recvfrom
0.35 0.008942 2 5892 getpid
0.31 0.007828 2 4156 getsockopt
0.28 0.007092 2 3725 getsockname
0.28 0.007003 2 4154 ioctl
0.24 0.006143 5 1258 1 stat
0.19 0.004889 4 1324 670 accept4
0.12 0.003023 4 690 pwrite64
0.04 0.001125 2 631 setsockopt
------ ----------- ----------- --------- --------- ----------------
100.00 2.542930 512303 28032 total
2.55user 7.57system 1:00.56elapsed 16%CPU (0avgtext+0avgdata 840maxresident)k
0inputs+0outputs (0major+273minor)pagefaults 0swaps
一些相关的 nginx 配置:
worker_processes 8;
worker_rlimit_nofile 20000;
worker_connections 5000;
multi_accept on;
use epoll;
access_log off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
open_file_cache max=10000 inactive=60s;
open_file_cache_valid 5s;
open_file_cache_min_uses 6;
fastcgi_buffers 8 16k;
我不明白为什么我应该期望 nginx 进程写入这么多,特别是在禁用访问日志的情况下。运行lsof -p nginx-pid
显示该进程打开的大多数文件都是正在服务的套接字和图像。只有套接字以写权限打开,所以我猜所有写入都必须通过这些套接字进行?
我的磁盘已使用该relatime
选项安装,因此我并不期望每次读取这些图像时都会写入磁盘。FastCGI 缓冲区大小应该能够处理 128K 的页面响应大小,这对于我的目的来说应该足够大。没有关于正在使用的临时文件的日志警告。
我确实有一个 FastCGI 缓存设置:
fastcgi_cache_path /shm/nginx/fastcgi levels=1:2 keys_zone=microcache:10m max_size=10m inactive=1m;
fastcgi_cache_key $scheme$request_method$host$request_uri;
fastcgi_cache microcache;
fastcgi_cache_valid 200 5s;
fastcgi_cache_lock on;
fastcgi_cache_lock_timeout 5s;
fastcgi_cache_lock_age 5s;
所有这些文字都与此有关吗?似乎相当多。
我遗漏了什么?对于活动的 Web 服务器来说,这是正常的 I/O 量(大概是写入套接字)吗?