nginx では1プロセスで多くのアクセスを捌くので、アクセス数が増えるとToo many open filesエラーが発生することがあります。
ここでは対処法と調べた内容を残しておきます。
1. fs.file-max の確認
まず fs.file-max の値を確認しておきます。fs.file-max は、システム全体でのファイルディスクリプタの上限数となっており、この値以上のファイルディスクリプタは確保することができません。
現在設定されている値は以下で確認できます。
$ cat /proc/sys/fs/file-max 167488
通常は上記の値で問題無いと思いますが、もしこの値が不足しているようなら設定値を更新します。
$ sudo -s # echo 320000 > /proc/sys/fs/file-max # cat /proc/sys/fs/file-max 320000
再起動時に有効となるように /etc/sysctl.conf に記述しておきます。
$ sudo vim /etc/sysctl.conf fs.file-max=320000
2. worker_rlimit_nofile の指定
次はプロセス毎のファイルディスクリプタ上限数を増やします。
nginx ではプロセス毎のファイルディスクリプタ上限数を指定する設定項目 worker_rlimit_nofile が用意されているので、これを記述します。設定する値は worker_connections の3〜4倍くらいが良いでしょう。
$ sudo vim /etc/nginx/nginx.conf worker_rlimit_nofile 4096; (snip) events { worker_connections 1024; }
設定変更後は nginx をリスタートしておきます。
$ sudo /etc/init.d/nginx restart
設定値が反映されているか確認しておきます。ワーカープロセスのプロセスID で limits を確認します。下記では「Max open files」の行がこれに当たるのですが、Soft Limit と Hard Limit 双方とも worker_rlimit_nofile で指定した値が設定されていることが分かります。
$ ps ax | grep nginx | grep worker 17064 ? S 0:00 nginx: worker process $ cat /proc/17604/limits Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 10485760 unlimited bytes Max core file size 0 unlimited bytes Max resident set unlimited unlimited bytes Max processes 8191 8191 processes Max open files 4096 4096 files Max locked memory 32768 32768 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 8191 8191 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0
プロセス毎のファイルディスクリプタ上限数を設定する方法として、ulimit コマンドや /etc/security/limits.conf による記述などがあるのですが、これらは環境によってはデーモン起動では適用されなかったり、起動ファイルに記述する必要があるなど注意が必要です。
nginx ではワーカープロセス初期化処理にて worker_rlimit_nofile で指定した値をsetrlimit(2) で設定するので、ulimit などで指定された値は上書きされます。(ソフトリミット、ハードリミット両方)
参照
おまけ
調べている中で色々と試したのでメモ。
もし同じようなことを試すなら、壊しても問題無い環境で行ないましょう。(私は AWS で EC2 インスタンス(AmazonLinux)を起動して試しました。)
fs.file-max を 0 にする。
$ sudo -s
# echo 0 > /proc/sys/fs/file-max
# cat /proc/sys/fs/file-max
0
- 元のシェルは動作している
# ls -a
. ..
- 一般ユーザに戻るとだめ
# exit
$ ls -la
-bash: start_pipeline: pgrp pipe: Too many open files in system
-bash: /bin/ls: Too many open files in system
- SSH でログインできない
ローカルから別コネクションでSSHでログインしようとしたのですが、ダメでした。
% ssh ec2-user@xxx.xxx.xxx.xxx ssh_exchange_identification: Connection closed by remote host
結局、Management Console からインスタンスを stop & start することに。。。
- /var/log/messages にログが記録される。
再起動後に /var/log/messages を見ると下記のようなログが記録されていました。
Feb 11 13:36:51 ip-10-121-3-15 kernel: [ 221.357976] VFS: file-max limit 0 reached
nginx で worker_rlimit_nofile が適用される箇所
nginx が worker_rlimit_nofile で指定した値をカーネルに設定する箇所をソースコードから探してみました。(nginx1.2.7)
src/os/unix/ngx_process_cycle.c の861行目付近でこの処理が行われています。root でマスタープロセスを実行している場合は、この箇所ではまだ root ユーザで動作しているので、ソフトリミット、ハードリミット共に worker_rlimit_nofile で指定した値が設定されています。