Carpe Diem

備忘録

ファイルディスクリプタ数の上限を変更

概要

Too many open files

のエラーが出た際の対策として、ファイルディスクリプタの上限を変更することがあります。
方法として以下の4つがあります。

  1. ulimitで変更する
  2. /etc/security/limits.confで設定する
  3. systemdのサービスの設定でLimitNOFILEを設定する
  4. systemdの全体設定でDefaultLimitNOFILEを設定する

環境

  • Ubuntu v22.04.1
  • Nginx v1.18.0

ファイルディスクリプタ数の確認方法

ファイルディスクリプタ数は以下の方法で確認ができます。

現在ログイン中のユーザの場合

$ ulimit -n
1024

特定のプロセスの場合

$ cat /proc/{プロセスID}/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
...
Max open files            1024                 524288               files
...

Max open filesが上限です。

方法

1. ulimitで変更する

現在ログイン中のユーザのファイルディスクリプタ数を上げる際に一番手軽な方法です。

$ ulimit -n
1024

となっているので、数値を引数に入れれば設定できます。

$ ulimit -n 2048
$ ulimit -n
2048

デメリットとしては再度ログインしたり再起動するとリセットされてしまう点です。

2. /etc/security/limits.confで設定する

リセットされてしまわないように永続化する方法です。

sshやsudoなどPAM認証を介すものに関してはこちらを設定することで永続的な設定が可能となります。

/etc/security/limits.confに以下を追記します。

* soft nofile 65536
* hard nofile 65536

*にすると全ユーザが対象になります。*の代わりに特定のユーザ名を入れることで対象を絞ることもできます。

動作確認

再度ログインしてみると反映されています。

vagrant@ubuntu-jammy:~$
logout
ubuntu_jammy $ vagrant ssh
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-48-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Oct  9 07:28:30 UTC 2022

  System load:  0.00439453125     Processes:               106
  Usage of /:   3.6% of 38.70GB   Users logged in:         0
  Memory usage: 24%               IPv4 address for enp0s3: 10.0.2.15
  Swap usage:   0%


0 updates can be applied immediately.


Last login: Sun Oct  9 07:19:41 2022 from 10.0.2.2
vagrant@ubuntu-jammy:~$ ulimit -n
65536

デメリットではないですが気をつける点としてPAM認証を介すものに対して設定されるので、daemon系のプロセスには反映されません

3. systemdのサービスの設定でLimitNOFILEを設定する

前述のようなPAM認証を介さないdaemon系のプロセスについては、systemdで設定を行います。

nginxのユニットファイルは/etc/systemd/system/multi-user.target.wants/nginx.serviceにあります。

[Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed

[Install]
WantedBy=multi-user.target

ServiceディレクティブにLimitNOFILEを設定します。

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed
LimitNOFILE=60000

設定をリロードして再起動します。

$ sudo systemctl daemon-reload
$ sudo systemctl restart nginx

動作確認

期待通り上限が変更されていました。

$ ps aux | grep [n]ginx
root        2886  0.0  0.1  55200  1676 ?        Ss   07:37   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data    2887  0.0  0.5  55832  5460 ?        S    07:37   0:00 nginx: worker process
www-data    2888  0.0  0.5  55832  5460 ?        S    07:37   0:00 nginx: worker process
$ cat /proc/2886/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            8388608              unlimited            bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             3722                 3722                 processes
Max open files            60000                60000                files
...

4. systemdの全体設定でDefaultLimitNOFILEを設定する

先程の派生みたいなものですが、サービスごとの個別設定ではなくsystemdを利用するサービス全てでデフォルト値を底上げするパターンです。

/etc/systemd/system.confDefaultLimitNOFILEコメントアウトされています。

#DefaultLimitSTACK=
#DefaultLimitCORE=
#DefaultLimitRSS=
#DefaultLimitNOFILE=1024:524288
#DefaultLimitAS=

softLimit:hardLimitの順に設定されています。これをアンコメントして設定します。

DefaultLimitNOFILE=60000:524288

設定をリロードして再起動します。

$ sudo systemctl daemon-reload
$ sudo systemctl restart nginx

動作確認

期待通り上限が変更されていました。

$ cat /proc/1474/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            8388608              unlimited            bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             3722                 3722                 processes
Max open files            60000                524288               files
...

ただこれは適切なリソース制限がされなくなるので、前述の個別設定の方が適切です。

まとめ

ファイルディスクリプタ数の上限を変更する4つの方法を説明しました。