【CentOS7】ファイルディスクリプタをプロセス単位で設定する手順【systemd】

「httpd」「tomcat」などを運用していて多くのユーザーにアクセスされたときに、プロセスに障害が発生することがあります。

ログを調査すると「Too many open files」がエラーを出力することがあります。

原因は多くのファイルをオープンし過ぎたためなのですが、オープンできるファイル数は「ファイルディスクリプタ」で設定することができます。

ファイルディスクリプタの設定は、数多くのファイルをオープンするアプリケーションで必要になります。

 

 

ファイルディスクリプタとは?

ファイルとは、そのまま「ファイル」です。

テキストファイル、バイナリファイル、画像ファイル、オフィスファイルなどです。

 

「ディスクリプタ」とはなんでしょうか?

ディスクリプタとは「descriptor」です。

descriptor の意味は「記述子、記述語」です。

「記述子、記述語」とは、ファイルやデータの構造や性質(属性)などの情報を記載しているデータのことを言います。

 

コマンドでファイルディスクリプタを調べてみます。

[root@cent07 fd]# ls /proc/493/fd ← プロセス「493」がいくつファイルディスクリプタを利用しているかチェックします。
0 1 2 3 4
[root@cent07 fd]# ls -l /proc/493/fd
合計 0
lr-x------. 1 root root 64 8月 29 20:49 0 -> /dev/null
lrwx------. 1 root root 64 8月 29 20:49 1 -> socket:[12194]
lrwx------. 1 root root 64 8月 29 20:49 2 -> socket:[12194]
lrwx------. 1 root root 64 8月 29 20:49 3 -> socket:[11320]
l-wx------. 1 root root 64 8月 29 20:49 4 -> /run/lvmetad.pid
[root@cent07 fd]# ps -ef | grep 493
root 493 1 0 20:49 ? 00:00:00 /usr/sbin/lvmetad -f
root 2414 2186 0 21:07 pts/0 00:00:00 grep --color=auto 493
[root@cent07 fd]#

 

ここで分かることは、

  • ファイルディスクリプタは「整数」
  • /dev/null
  • socket
  • PID

ということでしょうか。

一般的にファイルディスクリプタとは

  • 0  →  stdin
  • 1  →  stdout
  • 2  →  stderr

と説明されます。

つまり「整数」です。

 

 

ファイルディスクリプタの数が足りなくなるとどうなるか?

たとえば httpd プロセスのファイルディスクリプタが足りなくなると、プロセスの挙動がおかしくなり、その結果サイトにアクセスできなくなります。

しかし制限をしなければ無制限にプロセスを起動してしまいメモリが枯渇してしまいます。

そのためサーバーのリソースにマッチしたチューニングをする必要があります。

 

 

OS全体のファイルディスクリプタ数の制限とプロセスごとのファイルディスクリプタ数の制限がある

ファイルディスクリプタ数の制限値は2種類あります。

  • OS全体のファイルディスクリプタ数
  • プロセスごとのファイルディスクリプタ数

OS全体のファイルディスクリプタ数の制限値を上げても、個々のプロセス単位でもファイルディスクリプタ数の制限値を上げないと、プロセスには何の影響もありません。

 

例えば、tomcat のような個々のプロセスでファイルディスクリプタを消費するような場合は、プロセスごとにファイルディスクリプタの制限数を変更する必要があります。

 

ファイルディスクリプタの変更手順

  • OS全体の設定
  • 個々のプロセス単位の設定

を説明します。

/etc/sysctl.conf で設定する方法

「/etc/sysctl.conf」は OS 全体で規定するファイルディスクリプタ数の制限値の設定です。

個々のプロセス単位でのファイルディスクリプタ数の制限は別になります。

OS全体の制限数を増やしたからと言って、プロセス(デーモン)1つあたりの制限には影響しません。

そのため、最初に OS 全体のファイルディスクリプタ数を増やしておいてから、この後個々のプロセス(デーモン)のファイルディスクリプタ数を変更します。

 

[root@cent07 ~]# 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).
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

 

# file descriptor

fs.file-max = 65536 ← OS全体のファイルディスクリプタの数を「65536」に設定します。

 

 

変更したら「sysctl」コマンドで設定を反映します。(OSの再起動は不要です)

[root@cent07 ~]# sysctl -p
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
fs.file-max = 65536

 

※ただし、この設定は OS 全体の設定なので各プロセス(デーモン)のファイルディスクリプタの設定はデフォルトのままです。(この後、説明します)

 

/etc/security/limits.conf で設定する方法

「/etc/security/limits.conf」でも設定できますが、「/etc/sysctl.conf」と同じく「/etc/security/limits.conf」で設定した値はログインしない「デーモンプロセス」には効果がありません。

細かく説明すると、理由はログイン時や su コマンド実行時に PAM 認証されたタイミングで /etc/security/limits.conf の設定が適用されるため、デーモンプロセスには効かないということになります。

 

「/etc/security/limits.conf」の記述方法(設定方法)はファイルに詳しくサンプルが載っているので参考にして設定します。

[root@cent07 system]# cat /etc/security/limits.conf
# /etc/security/limits.conf
#
#This file sets the resource limits for the users logged in via PAM.
#It does not affect resource limits of the system services.
#
#Also note that configuration files in /etc/security/limits.d directory,
#which are read in alphabetical order, override the settings in this
#file in case the domain is the same or more specific.
#That means for example that setting a limit for wildcard domain here
#can be overriden with a wildcard setting in a config file in the
#subdirectory, but a user specific setting here can be overriden only
#with a user specific setting in the subdirectory.
#
#Each line describes a limit for a user in the form:
#
#<domain> <type> <item> <value>
#
#Where:
#<domain> can be:
# - a user name
# - a group name, with @group syntax
# - the wildcard *, for default entry
# - the wildcard %, can be also used with %group syntax,
# for maxlogin limit
#
#<type> can have the two values:
# - "soft" for enforcing the soft limits
# - "hard" for enforcing hard limits
#
#<item> can be one of the following:
# - core - limits the core file size (KB)
# - data - max data size (KB)
# - fsize - maximum filesize (KB)
# - memlock - max locked-in-memory address space (KB)
# - nofile - max number of open file descriptors
# - rss - max resident set size (KB)
# - stack - max stack size (KB)
# - cpu - max CPU time (MIN)
# - nproc - max number of processes
# - as - address space limit (KB)
# - maxlogins - max number of logins for this user
# - maxsyslogins - max number of logins on the system
# - priority - the priority to run user process with
# - locks - max number of file locks the user can hold
# - sigpending - max number of pending signals
# - msgqueue - max memory used by POSIX message queues (bytes)
# - nice - max nice priority allowed to raise to values: [-20, 19]
# - rtprio - max realtime priority
#
#<domain> <type> <item> <value>
#

#* soft core 0
#* hard rss 10000
#@student hard nproc 20
#@faculty soft nproc 20
#@faculty hard nproc 50
#ftp hard nproc 0
#@student - maxlogins 4

# End of file
[root@cent07 system]#

 

記述方法(設定方法)を解説すると、

<domain> <type> <item> <value>

の形式で設定します。

【例】

test   soft   nofile   65536

test   hard  nofile   65536

 

test アカウントの設定を入れています。

 

【例】アカウント全体(root、ftp、httpd など全て)に適用する場合

*   soft   nofile   65536

*   hard  nofile   65536

 

※*(アスタリスク)で全ユーザーが対象になります。

 

 

 

ulimitで設定する方法

ulimit は設定ファイルではなく「コマンド」です。

ulimit コマンドで個別アカウントを指定することで個別アカウントごとにファイルディスクリプタ数を設定することができます。

ulimit コマンドとは?

ulimit コマンドは、シェルのビルトイン(builtin)コマンドです。

ビルトインコマンドとは「シェルに組み込まれているコマンド」です。

ビルトインコマンドを簡単に説明しますと、例えばビルトインコマンドではない「ls」コマンドを実行するとシェルが中継をしてくれて「/bin/ls」コマンドを実行してくれて、その結果を端末に返してくれます。

しかしビルトインコマンドを実行すると、シェルは中継をせずに自分で実行して結果を端末に返してくれます。

「ならば全部ビルトインコマンドにすればいい」と思うかもしれませんが、全部ビルトインコマンドにしてシェルに組み込むとシェルが巨大化してしまいます。

(巨大化しすぎるといろいろ管理が大変です)

 

話が飛びましたが、ulimit コマンドはプロセスに割り当てる各リソースの制限を行うために使用します。

 

 

 

起動スクリプトに ulimit コマンドを入れる方法

CentOS6 の場合は起動スクリプトに「ulimit」コマンドを入れることで個々のプロセス(デーモン)に対してファイルディスクリプタの制限値を設定することができます。

 

CentOS7 の場合は「起動スクリプト」はなくなり「systemd」に変わりました。

 

CentOS7 の場合の設定方法

CentOS7から「systemd」に変わりましたので、「httpd」を例に設定を説明します。

[root@cent07 ~]# cd /usr/lib/systemd/system
/usr/lib/systemd/system
[root@cent07 system]# vi httpd.service
[Unit] ← Unitには「依存関係」と「順序関係」が記載されます。
Description=The Apache HTTP Server 
After=network.target remote-fs.target nss-lookup.target ← UnitセクションのAfterで先に起動しておくサービスを定義してます。
Documentation=man:httpd(8)
Documentation=man:apachectl(8)

 

[Service]
Type=notify ← Typeで起動プロセスの種類を書いておきます。
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true

LimitNOFILE=65536 ← この行を追加します。
LimitNPROC=65536 ← この行を追加します。

 

[Install]
WantedBy=multi-user.target

[root@dr-falcon-elif1 system]#

 

設定を反映させるためにサービスを再起動します。

[root@cent07 ~]# systemctl restart httpd.service
[root@cent07 ~]#

 

tomcat は tomcat プロセスではなく Java が起動している

「httpd」ではなく「tomcat」プロセスに対してファイルディスクリプタの設定をしたい場合もあります。

しかし、ps コマンドを実行しても「tomcat」プロセスなるものは存在しません。

tomcat という名前のプロセスはなく、通常は java プロセスが作られます。

 

1インスタンスの tomcat のプロセス数は1なので、もし tomcat を1つだけしかインストールしていないけど、 java プロセスが2つあったら tomcat 以外の java アプリが起動しているということになります。

 

 

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

現在の設定の確認方法です。

「httpd」「tomcat」のファイルディスクリプタの制限値を確認しています。

 

  • httpd のファイルディスクリプタの上限値 : 1024
  • tomcat のファイルディスクリプタの上限値 : 1024

 

[root@cent07 system]# cat /proc/`pgrep httpd | head -1`/limits | grep 'open files'
Max open files 1024 4096 files
[root@cent07 system]# cat /proc/`pgrep java | head -1`/limits | grep 'open files'
Max open files 1024 4096 files
[root@cent07 systemm]#

 

ここで気が付くのは、「Max open files 1024 4096 files」のように数字が2つあるということです。

 

それぞれの項目は以下のようになっています。

Limit                   Soft Limit           Hard Limit     Units

Max open files     1024                  4096             files

 

「ソフトリミット(Soft Limit)」と「ハードリミット(Hard Limit)」の2種類があります。

 

  • ソフトリミット 一般ユーザーが設定したファイルディスクリプタ数の制限値
  • ハードリミット 一般ユーザーが設定できるファイルディスクリプタ数の上限

 

ハードリミットを設定すると、一般ユーザーはそのハードリミットの範囲内でしかファイルディスクリプタ数の値を変更できません。(この数値を超えることができません)

一般ユーザーがハードリミットより大きな値に変更しようとするとエラーになります。

ハードリミットをそれより大きな値に変更する場合は root 権限が必要になります。

man ulimit コマンドより

ulimit [-HSTabcdefilmnpqrstuvx [limit]]

Provides control over the resources available to the shell and to processes started by it, on systems that allow such control.
このような制御を可能にするシステム上で、シェルとそのプロセスによって開始されたプロセスが利用できるリソースを制御します。

The -H and -S options specify that the hard or soft limit is set for the given resource.
-Hと-Sオプションは、特定のリソースに対してハード制限またはソフト制限が設定されていることを指定します。

A hard limit cannot be increased by a non-root user once it is set; a soft limit may be increased up to the value of the hard limit.
ハード・リミットは、root以外のユーザーが設定すると増加させることはできません。 ソフトリミットをハードリミットの値まで増加させることができます。

If neither -H nor -S is specified, both the soft and hard limits are set.
-Hと-Sのどちらも指定されていない場合、ソフトリミットとハードリミットの両方が設定されます。

The value of limit can be a number in the unit specified for the resource or one of the special values hard, soft, or unlimited, which stand for the current hard limit, the current soft limit, and no limit, respectively.
limitの値は、リソースに対して指定されたユニット内の数値、または現在のハードリミット、現在のソフトリミット、および無制限を表すハード、ソフト、または無制限の特別な値のいずれかです。

If limit is omitted, the current value of the soft limit of the resource is printed, unless the -H option is given.
limitを省略すると、-Hオプションが指定されていない限り、リソースのソフト制限値の現在の値が出力されます。

When more than one resource is specified, the limit name and unit are printed before the value.
複数のリソースが指定された場合、値の前に制限名と単位が出力されます。

 

If limit is given, it is the new value of the specified resource (the -a option is display only).

limitを指定すると、指定されたリソースの新しい値になります(-aオプションは表示のみ)。

If no option is given, then -f is assumed.

オプションを指定しない場合、-fが仮定されます。

Values are in 1024-byte increments, except for -t, which is in seconds, -p, which is in units of 512-byte blocks, and -T, -b, -n, and -u, which are unscaled values.

-tは秒単位、-pは512バイト単位、-T、-b、-n、および-uはスケーリングされていない値です(1024バイト単位)。
The return status is 0 unless an invalid option or argument is supplied, or an error occurs while setting a new limit.

無効なオプションまたは引数が指定されていないか、新しい制限を設定中にエラーが発生しない限り、戻りステータスは0です。

In POSIX Mode 512-byte blocks are used for the `-c' and `-f' options.

POSIXモードでは、 `-c 'と` -f'オプションのために512バイトブロックが使われます。

 

 

設定変更後の反映

プロセス単位で設定を変更した後は、OS の再起動まで必要ありません。

対象のサービス(プロセス)を再起動します。

 

 

まとめ

ファイルディスクリプタの設定は「OS」「プロセス(デーモン)」の2種類があります。

また、ファイルディスクリプタの設定は「ソフト」「ハード」があります。

この組み合わせを意識する必要があります。

例えば、いくら「ftp」アカウントのファイルディスクリプタ数を「65536」にしても「OS全体」のファイルディスクリプタ数が「1024」(少なすぎますが)なら、それ以上はファイルをオープンできません。

 

Posted by 100%レンタルサーバーを使いこなすサイト管理人

コメントを残す

メールアドレスが公開されることはありません。