TT Lab
はじめる
学ぶ 学習パス コース

Linux障害対応

ファイルディスクリプタと上限の診断

TT Labで続きを見る

目標

ファイルディスクリプターの制限が何層あるかを確認し、fdリークを追跡するツールを手で作ります。

なぜ重要なのか

Too many open filesを見ると、ほとんどの人がulimit -n 65536を実行します。しかし、その値は自分のシェルの値であり、すでに動いているサービスには何の影響もありません。確認すべき場所は/proc/<PID>/limitsで、実際の使用量はls /proc/<PID>/fd | wc -lです(lsof -pはcwd・実行ファイル・mmapされたライブラリまで数えますが、これらは制限に含まれません)。そして、制限を上げることが答えになる場合はまれです。たいていはリークで、そのとき制限を引き上げるのは、障害を数時間先送りするだけです。リークなのか負荷なのかは、fd数の増加パターンで見分けます。

ステップ

/root/fdディレクトリで作業します。

  1. /proc/1/limitsから開いているファイルの制限を読み取り、/root/fd/limits.txtに次の2行で書いてください(プレースホルダーは値です)。
    • soft=<값>
    • hard=<값>
  2. /etc/hostnameを50回以上同時に開いているプロセスをバックグラウンドで起動し、PIDを/root/fd/holder_pid.txtに書いてください。以降のステップの間ずっと生きている必要があります。
  3. そのプロセスのfdのうち/etc/hostnameを指しているものの個数と、それらが指している異なる対象の個数を、/root/fd/distinct.txtに次の2行で書いてください(プレースホルダーは個数です)。
    • count=<개수>
    • distinct=<개수>
  4. 制限を下げた環境でファイルを開き続けてToo many open filesエラーを再現し、そのメッセージを/root/fd/emfile.txtに保存してください。
  5. システム全体のfd上限を、数字だけ/root/fd/file_max.txtに書いてください。
  6. python3 -m http.server 8099 --bind 127.0.0.1をバックグラウンドで起動し、PIDを/root/fd/http_pid.txtに書いてください。
  7. /root/fd/fdtop.sh <N>を作成してください。開いているfdの個数が上位N個のプロセスを、<fd개수> <PID>の形式で降順に出力します(プレースホルダーはfdの個数とPIDです)。ちょうどN行である必要があります。
  8. /etc/hostnameのinode番号を/root/fd/inode.txtに書いてください。

参考

本当の制限を読み取る

/proc/1/limitsから開いているファイルの制限を読み取り、/root/fd/limits.txtに次の2行で書いてください(プレースホルダーは値です)。

自分のシェルのulimitではなく、そのプロセスの/proc//limitsを見る必要があります。「Max open files」の行に、softとhardが並んでいます。

fdを50個握る

/etc/hostnameを50回以上同時に開いているプロセスをバックグラウンドで起動し、PIDを/root/fd/holder_pid.txtに書いてください。以降のステップの間ずっと生きている必要があります。

python3で同じファイルを何度も開いてリストに入れておき、sleepすればよいです。変数に入れておかないと、すぐに閉じられます。

fdの個数と対象の個数を数える

そのプロセスのfdのうち/etc/hostnameを指しているものの個数と、それらが指している異なる対象の個数を、/root/fd/distinct.txtに次の2行で書いてください(プレースホルダーは個数です)。

/proc//fdの各項目をreadlinkして、対象を確認してください。同じファイルを何度も開くとどうなるかを見てください。

EMFILEを再現する

制限を下げた環境でファイルを開き続けてToo many open filesエラーを再現し、そのメッセージを/root/fd/emfile.txtに保存してください。

サブシェルでulimit -nを下げ、その中でファイルを開き続けてください。エラーメッセージをファイルに保存します。

システム全体の上限を読み取る

システム全体のfd上限を、数字だけ/root/fd/file_max.txtに書いてください。

/proc/sys/fs/file-nrは数字が3つです。最後が最大値です。

ソケットもfdです

python3 -m http.server 8099 --bind 127.0.0.1をバックグラウンドで起動し、PIDを/root/fd/http_pid.txtに書いてください。

python3 -m http.serverを127.0.0.1で起動して、そのプロセスのfdをreadlinkしてみてください。

fd上位のプロセスを取り出す

/root/fd/fdtop.sh <N>を作成してください。開いているfdの個数が上位N個のプロセスを、<fd개수> <PID>の形式で降順に出力します(プレースホルダーはfdの個数とPIDです)。ちょうどN行である必要があります。

/proc/*/fdの項目数を数えて、並べ替えます。権限エラーが出る項目はスキップしてください。

fdからinodeまで追跡する

/etc/hostnameのinode番号を/root/fd/inode.txtに書いてください。

stat -Lでシンボリックリンクをたどると、そのfdが指しているファイルのinodeがわかります。