最近Fedora 15にアップグレードした後、次のようなエラーが発生して多くのツールが失敗することがわかりました。
tail: inotify resources exhausted
tail: inotify cannot be used, reverting to polling
Inotifyの問題を報告しているのはtail
だけではありません。カーネルに問い合わせて、どのプロセスがinotifyリソースを消費しているかを調べる方法はありますか?現在のinotify関連のsysctl
設定は次のようになります。
fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.inotify.max_queued_events = 16384
プロセスがinotify_init()を介してinotifyインスタンスを作成する場合、/ procファイルシステムのfiledescriptorを表す結果のファイルは(存在しない)「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
概念を誤解していない限り、次のコマンドを実行すると、プロセスのリスト(/ procでの表現)が、使用するinotifyインスタンスの数でソートされて表示されます。
$ 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
インスタンスではなく、おそらくinotifywatchesが不足しています。誰が多くの時計を作成しているのかを知るには:
$ echo 1 > /sys/kernel/debug/tracing/events/syscalls/sys_exit_inotify_add_watch/enable`
tracing_on
がsから1であるかどうかを確認します。$ cat /sys/kernel/debug/tracing/tracing_on
0
$ echo 1 > /sys/kernel/debug/tracing/tracing_on
$ 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
/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
に変更してください。
@Jonathan Kamensが言ったように、おそらくウォッチャーが不足しています。私は 既製のスクリプト 、inotify-consumers
を持っています。
$ time inotify-consumers | head
INOTIFY
WATCHER
COUNT PID CMD
----------------------------------------
6688 27262 /home/dvlpr/apps/WebStorm-2018.3.4/WebStorm-183.5429.34/bin/fsnotifier64
411 27581 node /home/dvlpr/dev/kiwi-frontend/node_modules/.bin/webpack --config config/webpack.dev.js
79 1541 /usr/lib/gnome-settings-daemon/gsd-xsettings
30 1664 /usr/lib/gvfs/gvfsd-trash --spawner :1.22 /org/gtk/gvfs/exec_spaw/0
14 1630 /usr/bin/gnome-software --gapplication-service
real 0m0.099s
user 0m0.042s
sys 0m0.062s
ここでは、開発マシンでデフォルトの8Kウォッチャーの制限が小さすぎる理由をすばやく確認できます。何千ものフォルダーがあるnode_modules
フォルダーに遭遇すると、WebStormインスタンスだけがこれをすぐに最大化するためです。問題を保証するためにwebpackウォッチャーを追加します...
スクリプトの内容(またはGitHub上のファイル)をコピーして、$PATH
のように/usr/local/bin
のどこかに配置します。参考までに、スクリプトの主な内容はこれだけです
find /proc/*/fd \
-lname anon_inode:inotify \
-printf '%hinfo/%f\n' 2>/dev/null \
\
| xargs grep -c '^inotify' \
| sort -n -t: -k2 -r
制限を増やす方法について疑問がある場合は、永続化する方法を次に示します。
echo fs.inotify.max_user_watches=524288 | Sudo tee -a /etc/sysctl.conf
Sudo sysctl -p
どのプロセスがinotify watches(インスタンスではない)を消費するかを追跡するには、カーネルで動的ftrace機能が有効になっている場合は、それを使用できます。
必要なカーネルオプションはCONFIG_DYNAMIC_FTRACE
。
Debugfsファイルシステムがまだマウントされていない場合は、最初にマウントします。
mount -t debugfs nodev /sys/kernel/debug
このdebugfsディレクトリのtracing
サブディレクトリの下に移動します
cd /sys/kernel/debug/tracing
関数呼び出しのトレースを有効にする
echo function > current_tracer
フィルターのみSyS_inotify_add_watch
システムコール
echo SyS_inotify_add_watch > set_ftrace_filter
トレースリングバッファが空でなければクリアする
echo > trace
まだ有効になっていない場合は、トレースを有効にします
echo 1 > tracing_on
疑わしいプロセスを再起動します(私の場合、クラッシュプラン、バックアップアプリケーションでした)
Inotify_watchが使い果たされるのを見る
wc -l trace
cat trace
できた
find /proc/*/fd/* -type l -lname 'anon_inode:inotify' 2>/dev/null | cut -f 1-4 -d'/' | sort | uniq -c | sort -nr
上記のスクリプトを変更して、それらが消費しているプロセスのリストを表示しましたinotifyリソース:
ps -p `find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print | sed s/'^\/proc\/'/''/ | sed s/'\/fd.*$'/''/`
私のダブルsedを置き換える方法があると思います。
cut -f 3 -d '/'
または
sed -e 's/^\/proc\/\([0-9]*\)\/.*/\1'
そして、あなただけのpidを取得します。
また、追加した場合
2> /dev/null
findでは、findによってスローされた厄介なエラー行をすべて削除します。だからこれはうまくいくでしょう:
ps -p $(find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print 2> /dev/null | sed -e 's/^\/proc\/\([0-9]*\)\/.*/\1/')
このスクリプトを一連のサーバーに対して実行する必要があったため、これを実現するためにAnsibleプレイブックを作成しました。それはいくつかの 他の答えの概念 を単一のプレイブックに適合させ、PIDによるinotifyウォッチャーの使用を示すレポートを生成するために必要なコマンドを実行します。
$ ansible-playbook \
-i systems-inventory/cluster2.lab1 \
playbooks/show_inotify_watcher_cnt.yml \
-l ocp-master-02a.lab1*
注:このプレイブックの使用例は、以下のプレイブックの終わりに向けてのコメントです。
$ cat show_inotify_watcher_cnt.yml
###########################################################
# References
###########################################################
# - https://stackoverflow.com/questions/40230184/how-to-do-multiline-Shell-script-in-ansible
###########################################################
- hosts: compute infra masters
tasks:
- Shell:
cmd: |
cat <<EOF > /tmp/inotify_cnt.sh
#!/bin/bash
## Get the procs sorted by the number of inotify watchers
##
## From \`man find\`:
## %h Leading directories of file's name (all but the last element).
## If the file name contains no slashes (since it is in the current directory)
## the %h specifier expands to \`.'.
## %f File's name with any leading directories removed (only the last element).
lines=\$(
find /proc/*/fd \
-lname anon_inode:inotify \
-printf '%hinfo/%f\n' 2>/dev/null \
\
| xargs grep -c '^inotify' \
| sort -n -t: -k2 -r \
)
printf "\n%10s\n" "INOTIFY"
printf "%10s\n" "WATCHER"
printf "%10s %5s %s\n" " COUNT " "PID" "CMD"
printf -- "----------------------------------------\n"
for line in \$lines; do
watcher_count=\$(echo \$line | sed -e 's/.*://')
pid=\$(echo \$line | sed -e 's/\/proc\/\([0-9]*\)\/.*/\1/')
cmdline=\$(ps --columns 120 -o command -h -p \$pid)
printf "%8d %7d %s\n" "\$watcher_count" "\$pid" "\$cmdline"
done
EOF
become: yes
- file:
dest: /tmp/inotify_cnt.sh
mode: a+x
- Shell: /tmp/inotify_cnt.sh
become: yes
register: output
- debug:
var: output.stdout_lines
- Shell: |
sysctl fs.inotify
become: yes
register: output
- debug:
var: output.stdout_lines
##########
# USAGE
##########
## $ ansible-playbook -i systems-inventory/cluster2.lab1 playbooks/show_inotify_watcher_cnt.yml -l ocp-master-02a.lab1*
##
## PLAY [compute infra masters] *****************************************************************************************************************************************************
##
## TASK [Gathering Facts] ***********************************************************************************************************************************************************
## ok: [ocp-master-02a.lab1.mydomclec.local]
##
## TASK [Shell] *********************************************************************************************************************************************************************
## changed: [ocp-master-02a.lab1.mydomclec.local]
##
## TASK [file] **********************************************************************************************************************************************************************
## ok: [ocp-master-02a.lab1.mydomclec.local]
##
## TASK [Shell] *********************************************************************************************************************************************************************
## changed: [ocp-master-02a.lab1.mydomclec.local]
##
## TASK [debug] *********************************************************************************************************************************************************************
## ok: [ocp-master-02a.lab1.mydomclec.local] => {
## "output.stdout_lines": [
## "",
## " INOTIFY",
## " WATCHER",
## " COUNT PID CMD",
## "----------------------------------------",
## " 957 6553 /usr/bin/hyperkube kubelet --v=2 --address=0.0.0.0 --allow-privileged=true --anonymous-auth=true --authentication-token-",
## " 11 856 /usr/lib/systemd/systemd-udevd",
## " 11 1457 /usr/bin/python2 -Es /usr/sbin/firewalld --nofork --nopid",
## " 10 1471 /usr/sbin/rpc.gssd",
## " 5 1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22",
## " 5 1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22",
## " 5 1508 /usr/sbin/NetworkManager --no-daemon",
## " 4 1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22",
## " 4 1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22",
## " 4 1508 /usr/sbin/NetworkManager --no-daemon",
## " 4 1378 /usr/lib/polkit-1/polkitd --no-debug",
## " 3 4211 tail --follow=name /var/log/openvswitch/ovs-vswitchd.log /var/log/openvswitch/ovsdb-server.log",
## " 3 1970 /usr/sbin/crond -n",
## " 3 1378 /usr/lib/polkit-1/polkitd --no-debug",
## " 2 1893 /usr/sbin/rsyslogd -n",
## " 2 1389 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation",
## " 1 9012 virt-handler -v 3 --port 8443 --hostname-override ocp-master-02a.lab1.mydomclec.local --pod-ip-address 172.20.0.201",
## " 1 9012 virt-handler -v 3 --port 8443 --hostname-override ocp-master-02a.lab1.mydomclec.local --pod-ip-address 172.20.0.201",
## " 1 9012 virt-handler -v 3 --port 8443 --hostname-override ocp-master-02a.lab1.mydomclec.local --pod-ip-address 172.20.0.201",
## " 1 9012 virt-handler -v 3 --port 8443 --hostname-override ocp-master-02a.lab1.mydomclec.local --pod-ip-address 172.20.0.201",
## " 1 6553 /usr/bin/hyperkube kubelet --v=2 --address=0.0.0.0 --allow-privileged=true --anonymous-auth=true --authentication-token-",
## " 1 6553 /usr/bin/hyperkube kubelet --v=2 --address=0.0.0.0 --allow-privileged=true --anonymous-auth=true --authentication-token-",
## " 1 1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22",
## " 1 1388 /usr/sbin/sssd -i --logger=files",
## " 1 1359 /usr/bin/abrt-watch-log -F BUG: WARNING: at WARNING: CPU: INFO: possible recursive locking detected ernel BUG at list_de",
## " 1 1347 /usr/sbin/abrtd -d -s",
## " 0 6553 /usr/bin/hyperkube kubelet --v=2 --address=0.0.0.0 --allow-privileged=true --anonymous-auth=true --authentication-token-"
## ]
## }
##
## TASK [Shell] *********************************************************************************************************************************************************************
## changed: [ocp-master-02a.lab1.mydomclec.local]
##
## TASK [debug] *********************************************************************************************************************************************************************
## ok: [ocp-master-02a.lab1.mydomclec.local] => {
## "output.stdout_lines": [
## "fs.inotify.max_queued_events = 16384",
## "fs.inotify.max_user_instances = 128",
## "fs.inotify.max_user_watches = 65536"
## ]
## }
##
## PLAY RECAP ***********************************************************************************************************************************************************************
## ocp-master-02a.lab1.mydomclec.local : ok=7 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
##