Quem está consumindo meus recursos inotify?

46

Após uma atualização recente para o Fedora 15, estou descobrindo que várias ferramentas estão falhando com erros ao longo das linhas:

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

Não é apenas tail que está relatando problemas com o inotify. Existe alguma maneira de interrogar o kernel para descobrir que processo ou processos estão consumindo os recursos inotify? As configurações atuais de sysctl relacionadas ao inotify são assim:

fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.inotify.max_queued_events = 16384
    
por larsks 23.06.2011 / 17:39

6 respostas

37

Parece que, se o processo cria uma instância inotify via inotify_init (), o arquivo resultante que representa o filedescriptor no sistema de arquivos / proc é um link simbólico para o arquivo 'anon_inode: inotify' (não existente).

$ 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

A menos que eu tenha entendido mal o conceito, o comando a seguir deve mostrar a lista de processos (sua representação em / proc), classificados pelo número de instâncias de inotificação que eles usam.

for foo in /proc/*/fd/*; do readlink -f $foo; done | grep inotify | sort | uniq -c | sort -nr
    
por 24.06.2011 / 10:43
21

Você provavelmente está ficando sem inotify watches em vez de instâncias. Para descobrir quem está criando muitos relógios:

  1. Do echo 1 >> /sys/kernel/debug/tracing/events/syscalls/sys_exit_inotify_add_watch/enable para ativar o rastreamento de suplementos de exibição;
  2. Execute cat /sys/kernel/debug/tracing/tracing_enabled para garantir que esteja definido como 1 e, se não for, faça echo 1 >> /sys/kernel/debug/tracing/tracing_enabled ;
  3. Reinicie os processos com instâncias de inotificação (determinadas como descrito na resposta de Petr Uzel) que você suspeita de criar muitos relógios; e
  4. Leia o arquivo /sys/kernel/debug/tracing/trace para ver quantos relógios são criados e por quais processos.

Quando estiver pronto, certifique-se de fazer o eco 0 no arquivo de ativação (e no arquivo tracing_enabled se também tiver que habilitar isso) para desativar o rastreamento, para que você não sofra o impacto de continuar rastreando.

    
por 23.01.2013 / 15:36
4

Para rastrear quais processos consomem inotify relógios (não instâncias) você pode usar o recurso ftrace dinâmico do kernel se ele estiver ativado em seu kernel.

A opção do kernel que você precisa é CONFIG_DYNAMIC_FTRACE .

Primeiro, monte o sistema de arquivos debugfs, se ainda não estiver montado.

mount -t debugfs nodev /sys/kernel/debug

Vá para o subdiretório tracing deste diretório debugfs

cd /sys/kernel/debug/tracing

Ativar rastreamento de chamadas de função

echo function > current_tracer

Filtre apenas SyS_inotify_add_watch chamadas do sistema

echo SyS_inotify_add_watch > set_ftrace_filter

Limpe o buffer do anel de rastreamento se não estiver vazio

echo > trace

Ativar rastreamento se ainda não estiver ativado

echo 1 > tracing_on

Reinicie o processo suspeito (no meu caso, foi crashplan, um aplicativo de backup)

Veja o inotify_watch sendo esgotado

wc -l trace
cat trace

Concluído

    
por 03.12.2014 / 11:01
3
find /proc/*/fd/* -type l -lname 'anon_inode:inotify' 2>/dev/null | cut -f 1-4 -d'/' |  sort | uniq -c  | sort -nr
    
por 12.09.2012 / 20:46
3

Eu me deparei com esse problema, e nenhuma dessas respostas dá a você a resposta de "quantos relógios cada processo está usando atualmente?" Os one-liners dão a você quantas instâncias estão abertas, o que é apenas parte da história, e o material de rastreamento só é útil para ver novos relógios sendo abertos.

TL; DR: Isso gerará um arquivo com uma lista de inotify instâncias abertas e o número de relógios que eles têm, junto com os pids e binários que os gerou, classificados em ordem decrescente por contagem de relógios:

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

É uma grande bagunça, então é assim que cheguei lá. Para começar, eu corri um tail em um arquivo de teste e olhei para o fd que ele abriu:

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

Então, 4 é o fd que queremos investigar. Vamos ver o que está no fdinfo para isso:

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

Parece uma entrada para o relógio na parte inferior!

Vamos tentar algo com mais relógios, desta vez com o utilitário inotifywait , apenas observando o que está em /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

Aha! Mais entradas! Então devemos ter seis coisas em /tmp então:

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

Excelente. Meu novo inotifywait tem uma entrada em sua lista fd (que é o que os outros marcadores estão contando aqui), mas seis entradas em seu arquivo fdinfo . Assim, podemos descobrir quantos relógios um dado fd para um determinado processo está usando consultando o arquivo fdinfo . Agora, para colocá-lo em conjunto com alguns dos itens acima, pegue uma lista de processos que notificam os relógios abertos e use isso para contar as entradas em cada fdinfo . Isso é semelhante ao acima, então eu vou apenas jogar o one-liner aqui:

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

Há algumas coisas grossas aqui, mas o básico é que eu uso awk para construir um caminho fdinfo da lsof output, pegando o número pid e fd, removendo o sinalizador u / r / w de o último. Então, para cada caminho fdinfo construído, eu conto o número de inotify linhas e imprimo a contagem e o pid.

Seria legal se eu tivesse os processos que esses pids representam no mesmo lugar, certo? Eu pensei assim. Então, em um momento particularmente complicado, resolvi chamar dirname duas vezes no caminho fdinfo para obter o pacote para /proc/<pid> , adicionando /exe a ele e, em seguida, executando readlink em esse para obter o nome exe do processo. Jogue isso lá também, classifique-o por número de relógios e redirecione-o para um arquivo para salvaguardar e ficamos:

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

Rodando o sem sudo para mostrar meus processos que eu lancei acima, eu recebo:

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

Perfeito! Uma lista de processos, fd's e quantos relógios estão usando, exatamente o que eu precisava.

    
por 22.02.2018 / 23:58
1

Eu modifiquei o script presente acima para mostrar a lista de processos que estão consumindo inotify recursos:

ps -p 'find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print | sed s/'^\/proc\/'/''/ | sed s/'\/fd.*$'/''/'

Acho que existe uma maneira de substituir meu sed duplo.

Sim. Use tanto
cut -f 3 -d '/'   

ou

sed -e 's/^\/proc\/\([0-9]*\)\/.*/'  

e você só vai pegar o pid.
Além disso, se você adicionar

2> /dev/null  

no achado, você se livrará de todas as linhas de erros incômodas lançadas pelo find. Então, isso funcionaria:

ps -p $(find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print 2> /dev/null | sed -e 's/^\/proc\/\([0-9]*\)\/.*//')
    
por 18.07.2013 / 14:38