Linuxでの「ファイルの開きすぎ」エラーを解決する方法

Linuxで「ファイルの開きすぎ」というエラーメッセージが表示された場合、プロセスがファイルを開くことができる上限、通常1024に達しています。「ulimit -n 2048」というコマンドで、一時的に上限を2048ファイルに増やすことができます。systemd設定ファイルを編集することで、上限を永続的に増やすことができます。

Linuxコンピューターでは、システムリソースはユーザー間で共有されます。自分の割り当て分より多く使用しようとすると、上限に達します。また、他のユーザーやプロセスをボトルネックにする可能性もあります。

ファイルの開きすぎエラーとは

Linuxコンピューターのカーネルは、膨大な数の他のジョブの中でも、常にRAMやCPUサイクルなど、限られたシステムリソースを誰がどれだけ使用しているかを監視しています。マルチユーザーシステムでは、人やプロセスが適切な量を超えてシステムリソースを使用していないことを確認するために、常に注意を払う必要があります。

たとえば、誰かがCPU時間を独占して、他の全員がコンピューターが遅いと感じるのは公平ではありません。Linuxコンピューターを使用する唯一の人であっても、プロセスが使用できるリソースには制限があります。結局のところ、あなたも他のユーザーと同じです。

RAM、CPUサイクル、ハードドライブの空き容量など、よく知られていて明白なシステムリソースがいくつかあります。しかし、監視されており、各ユーザー、または各ユーザーが所有するプロセスに上限が設定されているリソースは他にもたくさんあります。その1つが、プロセスが同時に開くことができるファイルの数です。

ターミナルウィンドウで「ファイルの開きすぎ」というエラーメッセージが表示されたり、システムログでそれが見つかった場合、上限に達しており、プロセスはそれ以上のファイルを開くことが許可されません。

なぜそんなに多くのファイルが開いているのか

Linuxが処理できる開いているファイルの数には、システム全体で制限があります。後で説明しますが、非常に大きな数ですが、それでも制限があります。各ユーザープロセスには、使用できる割り当てがあります。各プロセスは、システム合計から割り当てられた少量を受け取ります。

実際に割り当てられるのは、ファイルハンドル数です。開かれるファイルごとにハンドルが必要です。かなり寛大な割り当てであっても、システム全体でファイルハンドルは、最初に想像したよりも早く使い果たされる可能性があります。

Linuxは、すべてを抽象化してファイルのように見せます。時には、単なる古いファイルであることもあります。しかし、ディレクトリを開くなどの他のアクションでもファイルハンドルを使用します。Linuxは、ブロック特殊ファイルをハードウェアデバイスのドライバーの一種として使用します。文字特殊ファイルは非常に似ていますが、パイプやシリアルポートなど、スループットの概念があるデバイスでよく使用されます。

ブロック特殊ファイルは一度にデータのブロックを処理し、文字特殊ファイルは各文字を個別に処理します。これらの特殊ファイルの両方にアクセスできるのは、ファイルハンドルを使用している場合のみです。プログラムで使用されるライブラリはファイルハンドルを使用し、ストリームはファイルハンドルを使用し、ネットワーク接続はファイルハンドルを使用します。

これらの異なる要件をすべて抽象化してファイルのように表示することで、それらとのインターフェースが簡素化され、パイプやストリームなどの機能が機能するようになります。

Linuxが裏でファイルを開いてファイルハンドルを使用して自分自身を実行していることがわかります。ユーザープロセスは言うまでもありません。開いているファイルの数は、あなたが開いたファイルの数だけではありません。オペレーティングシステムのほとんどすべてがファイルハンドルを使用しています。

ファイルハンドルの上限を確認する方法

システム全体のファイルハンドルの最大数は、このコマンドで確認できます。

cat /proc/sys/fs/file-max

これは、9200兆という途方もない数を返します。それが理論上のシステムの最大値です。64ビット符号付き整数で保持できる最大値です。貧弱なコンピューターが同時にこれほど多くのファイルを開くことができるかどうかは、まったく別の問題です。

ユーザーレベルでは、開くことができるファイルの最大数に明示的な値はありません。しかし、おおよその値を出すことができます。1つのプロセスが開くことができるファイルの最大数を見つけるには、ulimitコマンドと-n(開いているファイル)オプションを使用します。

ulimit -n

そして、ユーザーが持つことができるプロセスの最大数を見つけるために、ulimit-u(ユーザープロセス)オプションを使用します。

ulimit -u

1024と7640を掛けると、7,823,360になります。もちろん、これらのプロセスの多くはすでにあなたのデスクトップ環境や他のバックグラウンドプロセスで使用されているでしょう。したがって、それは別の理論上の最大値であり、現実的には達成することはありません。

重要な数字は、プロセスが開くことができるファイルの数です。デフォルトでは、これは1024です。同じファイルを1024回同時に開くことは、1024個の異なるファイルを同時に開くことと同じであることに注意してください。すべてのファイルハンドルを使い果たしたら、終了です。

プロセスが開けるファイルの数を調整できます。この数を調整する際には、実際に考慮すべき値が2つあります。1つは現在設定されている値、または設定しようとしている値です。これをソフトリミットと呼びます。ハードリミットもあり、これはソフトリミットを上げることができる最大値です。

これを考える方法は、ソフトリミットが本当に「現在の値」であり、上限が現在の値が到達できる最大値であるということです。通常のroot以外のユーザーは、ハードリミットまでの任意の値にソフトリミットを引き上げることができます。rootユーザーはハードリミットを増やすことができます。

現在のソフトリミットとハードリミットを確認するには、ulimit-S(ソフト)および-H(ハード)オプション、および-n(開いているファイル)オプションを使用します。

ulimit -Sn

ulimit -Hn

ソフトリミットが適用される状況を作成するために、失敗するまで繰り返しファイルを開くプログラムを作成しました。その後、使用したすべてのファイルハンドルを解放する前に、キーストロークを待ちます。そのプログラムはopen-filesと呼ばれます。

./open-Files

1021個のファイルを開き、1022個目のファイルを開こうとすると失敗します。

1024から1021を引くと3になります。他の3つのファイルハンドルはどうなったのでしょうか?STDINSTDOUTSTDERRストリームに使用されました。これらは各プロセスに対して自動的に作成されます。これらは常に0、1、2のファイル記述子値を持ちます。

lsofコマンドと-p(プロセス)オプションとopen-filesプログラムのプロセスIDを使用して、これらを確認できます。便利にも、そのプロセスIDをターミナルウィンドウに出力します。

lsof -p 11038

もちろん、実際の状況では、どのプロセスがすべてのファイルハンドルを独占したのかわからない場合があります。調査を開始するには、このパイプコマンドのシーケンスを使用できます。コンピューター上で最も多くのファイルハンドルを使用している15人のユーザーが表示されます。

lsof | awk '{ print $1 " " $2; }' | sort -rn | uniq -c | sort -rn | head -15

より多くのエントリまたはより少ないエントリを表示するには、headコマンドの-15パラメーターを調整します。プロセスを特定したら、制御不能になってファイルを開きすぎているのか、それとも本当にそれらのファイルが必要なのかを確認する必要があります。必要な場合は、ファイルハンドルの上限を増やす必要があります。

ソフトリミットを増やす方法

ソフトリミットを増やしてプログラムを再度実行すると、より多くのファイルが開かれるはずです。ulimitコマンドと-n(開いているファイル)オプションを2048の数値とともに使用します。これが新しいソフトリミットになります。

ulimit -n 2048

今回は2045個のファイルが正常に開かれました。予想通り、これは2048より3つ少なく、STDINSTDOUTSTDERRに使用されるファイルハンドルが原因です。

ファイル制限を永続的に変更する方法

ソフトリミットを増やすと、現在のシェルにのみ影響します。新しいターミナルウィンドウを開き、ソフトリミットを確認します。古いデフォルト値が表示されます。しかし、プロセスが開くことができるファイルの最大数の新しいデフォルト値をグローバルに設定し、永続的にして再起動に耐えることができます。

古いアドバイスでは、「/etc/sysctl.conf」や「/etc/security/limits.conf」などのファイルを編集することをよくお勧めします。しかし、systemdベースのディストリビューションでは、これらの編集は一貫して機能しません。特にグラフィカルログインセッションの場合。

ここで示す手法は、systemdベースのディストリビューションでこれを行う方法です。作業する必要があるファイルが2つあります。1つ目は「/etc/systemd/system.conf」ファイルです。sudoを使用する必要があります。

sudo gedit /etc/systemd/system.conf

「DefaultLimitNOFILE」という文字列を含む行を検索します。行の頭にあるハッシュ「#」を削除し、最初の数字をプロセスの新しいソフトリミットにする数字に編集します。4096を選択しました。その行の2番目の数字がハードリミットです。これは調整しませんでした。

ファイルを保存してエディタを閉じます。

「/etc/systemd/user.conf」ファイルでもその操作を繰り返す必要があります。

sudo gedit /etc/systemd/user.conf

「DefaultLimitNOFILE」という文字列を含む行に同じ調整を加えます。

ファイルを保存してエディタを閉じます。コンピューターを再起動するか、systemctlコマンドとdaemon-reexecオプションを使用して、systemdを再実行して新しい設定を読み込む必要があります。

sudo systemctl daemon-reexec

ターミナルウィンドウを開いて新しい制限を確認すると、設定した新しい値が表示されます。私たちのケースでは、それは4096でした。

ulimit -n

ファイル好きのプログラムを再実行することで、これがライブの動作値であるかどうかをテストできます。

./open-Files

プログラムはファイル番号4094を開くのに失敗し、4093がファイルとして開かれたことを意味します。それは期待される値であり、4096より3つ少ないです。

すべてがファイルであることを覚えておく

これがLinuxがファイルハンドルに大きく依存している理由です。これで、それらが不足し始めたら、クォータを増やす方法がわかります。