誰が私のinotifyリソースを消費していますか?

誰が私のinotifyリソースを消費していますか?

Fedora 15に最近アップグレードした後、次のエラーが原因で多くのツールが失敗することがわかりました。

tail: inotify resources exhausted
tail: inotify cannot be used, reverting to polling

これは単にtailinotify問題を報告する以上のものです。どのプロセスがinotifyリソースを消費しているかを調べるためにカーネルを調べる方法はありますか?現在、Inotify関連のsysctl設定は次のとおりです。

fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.inotify.max_queued_events = 16384

答え1

プロセスがinotify_init()を介してinotifyインスタンスを作成すると、/ procファイルシステムのファイル記述子を表す結果ファイルは(存在しない)ファイル「anon_inode:inotify」へのシンボリックリンクであるようです。

$ cd /proc/5317/fd
$ ls -l
total 0
lrwx------ 1 puzel users 64 Jun 24 10:36 0 -> /dev/pts/25
lrwx------ 1 puzel users 64 Jun 24 10:36 1 -> /dev/pts/25
lrwx------ 1 puzel users 64 Jun 24 10:36 2 -> /dev/pts/25
lr-x------ 1 puzel users 64 Jun 24 10:36 3 -> anon_inode:inotify
lr-x------ 1 puzel users 64 Jun 24 10:36 4 -> anon_inode:inotify

概念を誤解しない限り、次のコマンドは、使用するinotifyインスタンスの数に基づいてソートされたプロセスのリスト(/ procに表示されている)を表示する必要があります。

$ for foo in /proc/*/fd/*; do readlink -f $foo; done | grep inotify | sort | uniq -c | sort -nr

犯人を探す

これは@markkcowanが以下のコメントで言及したものです。

$ find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -exec sh -c 'cat $(dirname {})/../cmdline; echo ""' \; 2>/dev/null

答え2

2022年10月31日に更新 以下でMichael Sartainの答えをサポートしてください。。彼は実装したネイティブ実行可能ファイルこれははるかに高速で、私のスクリプト(下)にはない追加機能があります。コンパイルに数秒かかる場合は、試してみる価値があります! デフォルトのinotify-infoユーティリティ


スクリプトを含む元の答え

@Jonathan Kamensが言ったように、時計が使い果たされた可能性があります。私事前作成されたスクリプト、、、inotify-consumers最悪の犯罪者を一覧表示します。

   INOTIFY   INSTANCES
   WATCHES      PER   
    COUNT     PROCESS   PID USER         COMMAND
------------------------------------------------------------
   21270         1       11076 my-user    /snap/intellij-idea-ultimate/357/bin/fsnotifier
     201         6           1 root       /sbin/init splash
     115         5        1510 my-user    /lib/systemd/systemd --user
      85         1        3600 my-user    /usr/libexec/xdg-desktop-portal-gtk
      77         1        2580 my-user    /usr/libexec/gsd-xsettings
      35         1        2475 my-user    /usr/libexec/gvfsd-trash --spawner :1.5 /org/gtk/gvfs/exec_spaw/0
      32         1         570 root       /lib/systemd/systemd-udevd
      26         1        2665 my-user    /snap/snap-store/558/usr/bin/snap-store --gapplication-service
      18         2        1176 root       /usr/libexec/polkitd --no-debug
      14         1        1858 my-user    /usr/bin/gnome-shell
      13         1        3641 root       /usr/libexec/fwupd/fwupd
...

   21983  WATCHES TOTAL COUNT

INotify instances per user (e.g. limits specified by fs.inotify.max_user_instances): 

INSTANCES    USER
-----------  ------------------
41           my-user
23           root
1            whoopsie
1            systemd-ti+
...

ここでは、開発システムで8K Observerの基本的な制限が小さすぎる理由をすばやく理解できます。node_modulesWebStormインスタンスは、数千のフォルダがあるフォルダに会うときにこの制限をすばやく最大化するためです。問題がある場合は、Webパックウォッチャーを追加してください...

もともと作成したときは他の選択肢よりはるかに高速でしたが、Simon Matterはロードが多いBig Iron Linux(数百コア)に対していくつかのスピードアップを追加してスピードを10分(!)から15分に減らし、彼のモンスター装備に数秒。

後で、Brian Dowlingがプロセスあたりのインスタンス数に貢献しました。、比較的長い実行時間を犠牲にします。これは、実行時間が約1秒の通常のマシンではマイナーな作業ですが、ビッグアイロンがある場合は必要です。以前のバージョンこれはシステム時間の約1/10です:)

使い方

inotify-consumers --help

答え3

inotifyが不足する可能性があります。よりインスタンスではなく。誰が時計をたくさん作るのかを知るには:

  1. 追跡を追加するには、監視を有効にしてください。
$ echo 1 > /sys/kernel/debug/tracing/events/syscalls/sys_exit_inotify_add_watch/enable`
  1. tracing_onsが1であることを確認してください。
$ cat /sys/kernel/debug/tracing/tracing_on
0
$ echo 1 > /sys/kernel/debug/tracing/tracing_on
  1. 多数のクロックを生成すると疑われるinotifyインスタンスを使用してプロセスを再起動します(Petr Uzelの回答で説明されているように決定されます)。
  2. ftrace 設定
$ cat /sys/kernel/debug/tracing/current_tracer
nop

$ cat /sys/kernel/debug/tracing/set_ftrace_filter
#### all functions enabled ####

$ echo function              > /sys/kernel/debug/tracing/current_tracer
$ echo SyS_inotify_add_watch > /sys/kernel/debug/tracing/set_ftrace_filter
  1. ファイルを読んで、/sys/kernel/debug/tracing/traceいくつかの時計がどのプロセスによって生成されたかを確認してください。

完了したら、echo 0アクティベーションファイル(またはアクティベーションが必要な場合はtracing_onファイル)に移動してトレースをオフにしても、トレースを続行してもパフォーマンスが低下しません。

メモ:以前のバージョンのLinuxカーネルでは/sysエンドポイントと呼ばれていましたが、tracing_enabled今ではと呼ばれていますtracing_on。以前のバージョンのカーネルを使用している/sys/kernel/debug/tracing/tracing_on場合/sys/kernel/debug/tracing/tracing_enabled

答え4

私はこの問題に直面しており、これらの答えのどれも「どれくらい多いか」を教えてくれません。より現在、各プロセスで使用されていますか? 「テキストの一行でどれだけの数がわかりますか。はいこれはストーリーの一部に過ぎず、コンテンツトラッキングは新しい時計が開いていることを確認するためにのみ役立ちます。

簡単に言うと:inotifyその後、開いているインスタンスのリストと時計数量これを生成したpidとバイナリとともに、時計の数に基づいて降順にソートされます。

sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); exe=$(sudo readlink $(dirname $(dirname $fdi))/exe); echo -e $count"\t"$fdi"\t"$exe; done | sort -nr > watches

それは混乱の大きなボールでした。だからそれが私がそこに到達した方法です。まず、tailテストファイルに対して実行し、開いているファイル記述子を見てみました。

joel@gladstone:~$ tail -f test > /dev/null &
[3] 22734
joel@opx1:~$ ls -ahltr /proc/22734/fd
total 0
dr-xr-xr-x 9 joel joel  0 Feb 22 22:34 ..
dr-x------ 2 joel joel  0 Feb 22 22:34 .
lr-x------ 1 joel joel 64 Feb 22 22:35 4 -> anon_inode:inotify
lr-x------ 1 joel joel 64 Feb 22 22:35 3 -> /home/joel/test
lrwx------ 1 joel joel 64 Feb 22 22:35 2 -> /dev/pts/2
l-wx------ 1 joel joel 64 Feb 22 22:35 1 -> /dev/null
lrwx------ 1 joel joel 64 Feb 22 22:35 0 -> /dev/pts/2

したがって、4は私たちが調査したいfdです。その中に何があるか見てみましょうfdinfo

joel@opx1:~$ cat /proc/22734/fdinfo/4
pos:    0
flags:  00
mnt_id: 11
inotify wd:1 ino:15f51d sdev:ca00003 mask:c06 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:1df51500a75e538c

一番下の時計アイテムと同じです!

もう少し時計を使ってみましょう。今回はinotifywaitユーティリティを使って内部内容を観察してみましょう/tmp

joel@gladstone:~$ inotifywait /tmp/* &
[4] 27862
joel@gladstone:~$ Setting up watches.
Watches established.
joel@gladstone:~$ ls -ahtlr /proc/27862/fd | grep inotify
lr-x------ 1 joel joel 64 Feb 22 22:41 3 -> anon_inode:inotify
joel@gladstone:~$ cat /proc/27862/fdinfo/3
pos:    0
flags:  00
mnt_id: 11
inotify wd:6 ino:7fdc sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:dc7f0000551e9d88
inotify wd:5 ino:7fcb sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:cb7f00005b1f9d88
inotify wd:4 ino:7fcc sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:cc7f00006a1d9d88
inotify wd:3 ino:7fc6 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:c67f00005d1d9d88
inotify wd:2 ino:7fc7 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:c77f0000461d9d88
inotify wd:1 ino:7fd7 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:d77f00000053c98b

ああ!もっとアイテム!したがって、私たちは6つのものを持つべきです/tmp

joel@opx1:~$ ls /tmp/ | wc -l
6

素晴らしい。私の新しいinotifywaitもの一つリストには6つの項目しかありませんがfd(ここでは別の行で計算される項目)、fdinfoファイルには6つの項目があります。したがって、そのファイルを参照して、特定のプロセスの特定のfdが使用している時計の数を見つけることができますfdinfo。これを上記の一部と一緒に使用して、通知監視が設定されているプロセスのリストを取得し、それを使用して各プロセスを計算しますfdinfo。これは上記と似ているので、ここに1行だけ捨て​​ます。

sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); echo -e $count"\t"$fdi; done

これにはいくつかの重いものがありますが、基本はawk出力からパスを構築し、pidとfd番号を取得し、後者からu / r / wフラグを削除するために使用することです。次に、ビルドされたパスごとに行数を数え、数とpidを出力します。fdinfolsoffdinfoinotify

このpidが表すプロセスを同じ場所に置くことは本当に良いでしょうか?私はそう思った。だから、特に混乱している状況では、 pathdirnamefdinfopack を 2 回呼び出してここに/proc/<pid>追加し、次のように実行することにしました。/exereadlinkそれプロセスのexe名を取得します。それもそこに入れて、時計の数に合わせてソートし、安全な保存のためにファイルにリダイレクトすると、次のような結果が得られます。

sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); exe=$(sudo readlink $(dirname $(dirname $fdi))/exe); echo -e $count"\t"$fdi"\t"$exe; done | sort -n > watches

それを実行するいいえsudoは上記で開始したプロセスを示しており、次のような結果が得られます。

joel@gladstone:~$ cat watches 
6   /proc/4906/fdinfo/3 /usr/bin/inotifywait
1   /proc/22734/fdinfo/4    /usr/bin/tail

完璧!プロセス、fds、および数のリストよりそれぞれが使用されており、正確に私に必要なものです。

関連情報