Linux ファイル・ディスクリプタ制限のチューニング

3月 16, 2022AmazonLinux_CentOS,OperatingSystem

概要

  • Linux オペレーティング・システムでは、ファイル・ディスクリプタという仕組みが使われます。ファイル・ディスクリプタによって、標準入出力やブロックデバイス、ソケットなどが擬似ファイルとして処理されます。ファイル・ディスクリプタは、プロセス毎に管理され、/proc/プロセス番号/fd/ に保持されます。
  • ソケットとは、ネットワーク通信で用いられるファイル・ディスクリプタです。ネットワーク通信では、コネクション毎にファイル・ディスクリプタが作成されます。クライアントからの同時接続が多いシステムの場合、ファイル・ディスクリプタも多く必要になります。
  • このファイル・ディスクリプタは、同時にオープンできる数が制限されています。Webサーバーで’Too many open files’ のエラー等に遭遇して、ファイル・ディスクリプタ制限のチューニングが必要な状況を想定しています。また、ファイル・ディスクリプタのチューニングは、目的によって方法が異なるため難解です。本記事では、ポイントを整理して、現在オープンされているファイル・ディスクリプタの数を調査する方法、現在の制限を確認する方法、制限を変更する方法を紹介します。

 

現在オープンされているファイル・ディスクリプタの数を調査する

  • 現在オープンされているファイル・ディスクリプタの数を調査するには、/proc/プロセス番号/fd/ 配下を調べる方法と、lsof コマンドを使用する方法があります。
  • httpdをモチーフとしています。先ず、プロセス番号を調べ、次に/proc/プロセス番号/fd/ 配下の数をカウントします。
$ ps -ef | grep httpd
root      3263     1  0 09:47 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    3264  3263  0 09:47 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    3265  3263  0 09:47 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    3267  3263  0 09:47 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    3268  3263  0 09:47 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    3269  3263  0 09:47 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
ec2-user  4160  4119  0 11:53 pts/1    00:00:00 grep --color=auto httpd
$ sudo ls -l /proc/3263/fd | wc -l
14
$ sudo ls -l /proc/3263/fd
total 0
lr-x------ 1 root root 64 Mar 15 09:47 0 -> /dev/null
lrwx------ 1 root root 64 Mar 15 09:47 1 -> socket:[20667]
l-wx------ 1 root root 64 Mar 15 09:47 10 -> /var/log/httpd/access_log
l-wx------ 1 root root 64 Mar 15 09:47 11 -> /var/log/httpd/ssl_access_log
l-wx------ 1 root root 64 Mar 15 09:47 12 -> /var/log/httpd/ssl_request_log
l-wx------ 1 root root 64 Mar 15 09:47 2 -> /var/log/httpd/error_log
lrwx------ 1 root root 64 Mar 15 09:47 3 -> socket:[20683]
lrwx------ 1 root root 64 Mar 15 09:47 4 -> socket:[20684]
lrwx------ 1 root root 64 Mar 15 09:47 5 -> socket:[20693]
lrwx------ 1 root root 64 Mar 15 09:47 6 -> socket:[20694]
lr-x------ 1 root root 64 Mar 15 09:47 7 -> pipe:[20739]
l-wx------ 1 root root 64 Mar 15 09:47 8 -> pipe:[20739]
l-wx------ 1 root root 64 Mar 15 09:47 9 -> /var/log/httpd/ssl_error_log
  • あるいは、lsof コマンドで同様の結果が得られます。lsof コマンド出力結果の FDカラムが数字から始まる行をカウントします。数字+r はread-onlyで開いているファイル、数字+w はwrite-onlyで開いているファイル、数字+u はread/writeで開いてるファイルを表します。FDが数字以外(cwd|rtd|txt|mem|DEL)を除外することで、カウントできます。
$ sudo lsof -c httpd | egrep -v "cwd|rtd|txt|mem|DEL"
COMMAND  PID   USER   FD      TYPE             DEVICE SIZE/OFF    NODE NAME
httpd   3263   root    0r      CHR                1,3      0t0    6758 /dev/null
httpd   3263   root    1u     unix 0xffff88801cacf000      0t0   20667 socket
httpd   3263   root    2w      REG              202,1     2841 8746116 /var/log/httpd/error_log
httpd   3263   root    3u     sock                0,8      0t0   20683 protocol: TCP
httpd   3263   root    4u     IPv6              20684      0t0     TCP *:http (LISTEN)
httpd   3263   root    5u     sock                0,8      0t0   20693 protocol: TCP
httpd   3263   root    6u     IPv6              20694      0t0     TCP *:https (LISTEN)
httpd   3263   root    7r     FIFO               0,11      0t0   20739 pipe
httpd   3263   root    8w     FIFO               0,11      0t0   20739 pipe
httpd   3263   root    9w      REG              202,1      905 8746118 /var/log/httpd/ssl_error_log
httpd   3263   root   10w      REG              202,1        0 8747163 /var/log/httpd/access_log
httpd   3263   root   11w      REG              202,1        0 8744739 /var/log/httpd/ssl_access_log
httpd   3263   root   12w      REG              202,1        0 8744749 /var/log/httpd/ssl_request_log
httpd   3264 apache    0r      CHR                1,3      0t0    6758 /dev/null
httpd   3264 apache    1u     unix 0xffff88801cacf000      0t0   20667 socket
httpd   3264 apache    2w      REG              202,1     2841 8746116 /var/log/httpd/error_log
httpd   3264 apache    3u     sock                0,8      0t0   20683 protocol: TCP
httpd   3264 apache    4u     unix 0xffff88801c508000      0t0   20753 /run/httpd/cgisock.3263
httpd   3264 apache    5u     sock                0,8      0t0   20693 protocol: TCP
httpd   3264 apache    7r     FIFO               0,11      0t0   20739 pipe
httpd   3264 apache    8w     FIFO               0,11      0t0   20739 pipe
httpd   3264 apache    9w      REG              202,1      905 8746118 /var/log/httpd/ssl_error_log
httpd   3264 apache   10w      REG              202,1        0 8747163 /var/log/httpd/access_log
httpd   3264 apache   11w      REG              202,1        0 8744739 /var/log/httpd/ssl_access_log
httpd   3264 apache   12w      REG              202,1        0 8744749 /var/log/httpd/ssl_request_log
** 省略 **
  •  httpd全体で使用しているファイル・ディスクリプタの数をカウントします。他に動作する主要なサービスがなく、現在オープンの数が後述するファイル・ディスクリプタの制限より十分に小さければ、チューニングは不要ですね。

$ sudo lsof -c httpd | egrep -v "cwd|rtd|txt|mem|DEL" | grep -v COMMAND | wc -l
85

 

現在のファイル・ディスクリプタの制限を確認する

OS 全体のファイル・ディスクリプタの制限確認

  • 先ず、現在のOSが利用できるファイル・ディスクリプタの制限を確認します。次のコマンドを実行します。
$ cat /proc/sys/fs/file-max
46423

あるいは

$ sudo sysctl -a | grep file-max
fs.file-max = 46423

 

プロセスのファイル・ディスクリプタの制限確認

  • 次に、現在のユーザーが利用できるファイル・ディスクリプタ数の制限を確認します。次のコマンドを実行します。-S はSoftLimit、-H はHardLimit です。
$ ulimit -Sn
65535
$ ulimit -Hn
65535

 

 

ファイル・ディスクリプタの制限を変更する

OS 全体のファイル・ディスクリプタの制限変更 (/etc/sysctl.conf)

  • ファイル・ディスクリプタの制限を変更します。システムが動作する合理的な数に増やします。
  • 先ず、OSが利用できるファイル・ディスクリプタの制限を変更します。次のコマンドを実行します。
    • 次の行を/etc/sysctl.confファイルに追記します。valueは、設定する制限です。
      • fs.file-max = value
    • 次のコマンドを実行して、変更を適用します。
      • /sbin/sysctl -p
$ cat /proc/sys/fs/file-max
46423

$ sudo su -

# vi /etc/sysctl.conf
-----
fs.file-max = 65535	<-- 追記
-----

# logout

$ cat /etc/sysctl.conf
# sysctl settings are defined through files in
# /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.
#
# Vendors settings live in /usr/lib/sysctl.d/.
# To override a whole file, create a new file with the same in
# /etc/sysctl.d/ and put new settings there. To override
# only specific settings, add a file with a lexically later
# name in /etc/sysctl.d/ and put new settings there.
#
# For more information, see sysctl.conf(5) and sysctl.d(5).
fs.file-max = 65535

$ sudo /sbin/sysctl -p
fs.file-max = 65535
$ cat /proc/sys/fs/file-max
65535

 

プロセスのファイル・ディスクリプタの制限変更 (/etc/security/limits.conf)

  • 次に、個々のプロセスが利用できるファイル・ディスクリプタの制限を変更します。-S はSoftLimit、-H はHardLimit であり、SoftLimitはHardLimit以下の範囲で一般ユーザが変更可能、HardLimitはrootのみ変更可能です。
  • なお、ulimit は実行したシェルおよびそのシェルから起動された子プロセスに対して、一時的に設定が変更されます。
$ ulimit -Sn 32768
$ ulimit -Hn 32768
$ ulimit -Sn
32768
$ ulimit -Hn
32768
  • ユーザーの制限を恒久的に設定する場合、/etc/security/limits.conf に制限値を記入します。ユーザー名と制限を指定します。特に再起動は必要なく、次回ログインしたユーザーは、変更後の設定が反映されます。
$ sudo vi /etc/security/limits.conf

ec2-user         soft    nofile          32768  <== 追記
ec2-user         hard    nofile          32768  <== 追記
# End of file

 

プロセス(デーモン)のファイル・ディスクリプタの制限変更 (systemd)

  • ユーザーが起動するプロセスではなく、デーモンの制限を恒久的に設定する場合、/etc/security/limits.conf では効果がありません。サービスやOS再起動時に設定が保持されません。
  • systemd にdrop-in のユニット構成ファイル (/etc/systemd/system/[サービス名].d/limits.conf) を作成し、追加の制限を定義します。これは、drpo-in という仕組みで、メインのユニット構成ファイルのパラメータを上書きすることができます。
  • デーモンに現在設定されている制限を確認するには、/proc/プロセス番号/limits にて確認可能です。

 

** 変更前 **
$ ps -ef | grep httpd
root      2789     1  0 02:38 ?        00:00:01 /usr/sbin/httpd -DFOREGROUND
apache    2823  2789  0 02:38 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    2824  2789  0 02:38 ?        00:00:04 /usr/sbin/httpd -DFOREGROUND
apache    2827  2789  0 02:38 ?        00:00:04 /usr/sbin/httpd -DFOREGROUND
apache    2828  2789  0 02:38 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    2829  2789  0 02:38 ?        00:00:04 /usr/sbin/httpd -DFOREGROUND
ec2-user  5874  5847  0 12:21 pts/0    00:00:00 grep --color=auto httpd
$ cat /proc/2789/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             10485760             bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             unlimited            unlimited            processes
Max open files            65535                65535                files
Max locked memory         unlimited            unlimited            bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       30446                30446                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

 

  • systemd にdrop-in のユニット構成ファイルを作成し、設定の再読み込みおよびサービスのrestartを行います。
  • サービス再起動後に、systemctl status httpd.service の出力結果に、Drop-In として追加したユニット構成ファイルが表示されています。
$ systemctl status httpd.service
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2022-03-16 02:38:59 UTC; 9h ago
     Docs: man:httpd.service(8)
 Main PID: 2789 (httpd)
   Status: "Total requests: 0; Idle/Busy workers 100/0;Requests/sec: 0; Bytes served/sec:   0 B/sec"
   CGroup: /system.slice/httpd.service
           tq2789 /usr/sbin/httpd -DFOREGROUND
           tq2823 /usr/sbin/httpd -DFOREGROUND
           tq2824 /usr/sbin/httpd -DFOREGROUND
           tq2827 /usr/sbin/httpd -DFOREGROUND
           tq2828 /usr/sbin/httpd -DFOREGROUND
           mq2829 /usr/sbin/httpd -DFOREGROUND

Mar 16 02:38:59 hostname systemd[1]: Starting The Apache HTTP Se....
Mar 16 02:38:59 hostname httpd[2789]: AH00558: httpd: Could not r...
Mar 16 02:38:59 hostname systemd[1]: Started The Apache HTTP Server.
Hint: Some lines were ellipsized, use -l to show in full.
$ sudo mkdir -p /etc/systemd/system/httpd.service.d
$ sudo vi /etc/systemd/system/httpd.service.d/00-limits.conf
$ cat /etc/systemd/system/httpd.service.d/00-limits.conf
[Service]
LimitNOFILE=32768:32768
$ sudo systemctl daemon-reload
$ sudo systemctl restart httpd.service
$ systemctl status httpd.service
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/httpd.service.d
           mq00-limits.conf
   Active: active (running) since Wed 2022-03-16 12:28:00 UTC; 1min 39s ago
     Docs: man:httpd.service(8)
 Main PID: 5970 (httpd)
   Status: "Total requests: 0; Idle/Busy workers 100/0;Requests/sec: 0; Bytes served/sec:   0 B/sec"
   CGroup: /system.slice/httpd.service
           tq5970 /usr/sbin/httpd -DFOREGROUND
           tq5971 /usr/sbin/httpd -DFOREGROUND
           tq5972 /usr/sbin/httpd -DFOREGROUND
           tq5974 /usr/sbin/httpd -DFOREGROUND
           tq5975 /usr/sbin/httpd -DFOREGROUND
           mq5976 /usr/sbin/httpd -DFOREGROUND

Mar 16 12:28:00 hostname systemd[1]: Stopped The Apache HTTP Server.
Mar 16 12:28:00 hostname systemd[1]: Starting The Apache HTTP Se....
Mar 16 12:28:00 hostname httpd[5970]: AH00558: httpd: Could not r...
Mar 16 12:28:00 hostname systemd[1]: Started The Apache HTTP Server.
Hint: Some lines were ellipsized, use -l to show in full.

 

  • 以下の通り、Max open files の制限が変更されました。
** 変更後 **
$ ps -ef | grep httpd
root      5970     1  0 12:28 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5971  5970  0 12:28 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5972  5970  0 12:28 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5974  5970  0 12:28 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5975  5970  0 12:28 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5976  5970  0 12:28 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
ec2-user  6329  5847  0 12:30 pts/0    00:00:00 grep --color=auto httpd
$ cat /proc/5970/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             10485760             bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             unlimited            unlimited            processes
Max open files            32768                32768                files
Max locked memory         unlimited            unlimited            bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       30446                30446                signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

 

参考資料