什么原因导致 Nginx 写入这么多的 I/O?

什么原因导致 Nginx 写入这么多的 I/O?

我有一个运行 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 量(大概是写入套接字)吗?

相关内容