누가 내 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 인스턴스는 수천 개의 폴더가 있는 폴더를 만날 때 이 제한을 신속하게 최대화하기 때문입니다. 문제가 있는 경우 웹팩 감시자 추가...

원래 만들었을 때는 다른 대안보다 훨씬 빨랐지만 Simon Matter는 로드가 많은 Big Iron Linux(수백 코어)에 대해 몇 가지 속도 향상을 추가하여 속도를 10분(!)에서 15분으로 줄이고 그의 몬스터 장비에 몇 초.

나중에,Brian Dowling이 프로세스당 인스턴스 수에 기여했습니다., 상대적으로 긴 실행 시간을 희생합니다. 이는 실행 시간이 약 1초인 일반 기계에서는 사소한 일이지만 Big Iron이 있는 경우 필요할 수 있습니다.이전 버전이는 시스템 시간의 약 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

아하! 더 많은 항목! 따라서 우리는 여섯 가지를 가져야 합니다 /tmp:

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

훌륭한. 내 새 inotifywait하나목록에는 항목이 6개만 있지만 fd(여기서 다른 한 줄로 계산되는 항목) fdinfo파일에는 항목이 6개 있습니다. 따라서 해당 파일을 참조하여 특정 프로세스의 특정 fd가 사용하는 시계 수를 알아낼 수 있습니다 fdinfo. 이제 이를 위의 일부와 함께 사용하여 알림 모니터링이 설정된 프로세스 목록을 얻고 이를 사용하여 각 프로세스를 계산합니다 fdinfo. 이는 위와 유사하므로 여기에 한 줄만 버립니다.

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가 나타내는 프로세스를 같은 장소에 두면 참 좋겠죠? 나는 그렇게 생각했다. 그래서 특히 혼란스러운 상황에서 나는 path dirname에서 fdinfopack 을 두 번 호출하고 여기에 /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 및 개수 목록보다각각은 사용되고 있으며 정확히 나에게 필요한 것입니다.

관련 정보