Determina a localização do uso do inode

15

Eu instalei recentemente o Munin em um servidor web de desenvolvimento para acompanhar o uso do sistema. Eu notei que o uso do inode do sistema está subindo cerca de 7-8% por dia, mesmo que o uso do disco tenha aumentado pouco. Eu estou supondo que algo está escrevendo uma tonelada de arquivos minúsculos, mas não consigo encontrar o que / onde.

Eu sei como encontrar o uso do espaço em disco, mas não consigo encontrar uma maneira de resumir o uso do inode.

Existe uma boa maneira de determinar o uso do inode por diretório para que eu possa localizar a fonte do uso?

    
por Dave Forgac 10.07.2009 / 15:31

12 respostas

15

Não espere que isso seja executado rapidamente ...

cd para um diretório onde você suspeita que pode haver um subdiretório com muitos inodes. Se esse script levar muito tempo, você provavelmente encontrará o que procurar no sistema de arquivos. / var é um bom começo ...

Caso contrário, se você mudar para o diretório principal nesse sistema de arquivos e rodar isto e esperar que ele termine, você encontrará o diretório com todos os inodes.

find . -type d | 
while 
  read line  
do 
  echo "$( find "$line" -maxdepth 1 | wc -l) $line"  
done | 
sort -rn | less

Não estou preocupado com o custo da classificação. Fiz um teste e classifiquei a saída não classificada de 350.000 diretórios em 8 segundos. A descoberta inicial levou. O custo real é abrir todos esses diretórios no loop while. (o próprio loop leva 22 segundos). (Os dados do teste foram executados em um subdiretório com 350.000 diretórios, um dos quais tinha um milhão de arquivos, o restante tinha entre 1 e 15 diretórios).

Várias pessoas apontaram que não é ótimo, porque classifica a saída. Eu tentei eco, mas isso também não é ótimo. Alguém havia apontado que o stat fornece essa informação (número de entradas de diretório), mas não é portátil. Acontece que encontrar -maxdepth é realmente rápido em abrir diretórios e contar arquivos. Então ... aqui está .. pontos para todos!

    
por 10.07.2009 / 15:36
7

Se o problema for um diretório com muitos arquivos, veja uma solução simples:

# Let's find which partition is out of inodes:
$ df -hi
Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda3               2.4M    2.4M       0  100% /
...

# Okay, now we know the mount point with no free inodes,
# let's find a directory with too many files:
$ find / -xdev -size +100k -type d

A ideia por trás da linha find é que o tamanho de um diretório é proporcional à quantidade de arquivos diretamente dentro desse diretório. Então, aqui nós procuramos por diretórios com vários arquivos dentro dele.

Se você não quiser adivinhar um número e preferir listar todos os diretórios suspeitos ordenados por "tamanho", também é fácil:

# Remove the "sort" command if you want incremental output
find / -xdev -size +10k -type d -printf '%s %p\n' | sort -n
    
por 10.11.2010 / 17:24
6

Grrr, comentar requer 50 repetições. Portanto, esta resposta é na verdade um comentário sobre a resposta de Chris.

Como o questionador provavelmente não se importa com todos os diretórios, apenas os piores, então, usar classificação provavelmente é um exagero muito caro.

find . -type d | 
while 
  read line  
do 
  echo "$(ls "$line" | wc -l) $line"  
done | 
perl -a -ne'next unless $F[0]>=$max; print; $max=$F[0]'  | less

Isso não é tão completo quanto a sua versão, mas o que isso faz é imprimir linhas se elas forem maiores que o máximo anterior, reduzindo muito a quantidade de ruído impresso e economizando o gasto do tipo.

A desvantagem disso é se você tem 2 diretórios muito grandes, e o primeiro acontece ter mais 1 inode do que o segundo, você nunca verá o segundo.

Uma solução mais completa seria escrever um script perl mais inteligente que rastreie os 10 principais valores vistos e os imprima no final. Mas isso é muito longo para uma rápida resposta de falha de servidor.

Além disso, alguns scripts de perl mais inteligentes permitem que você ignore o loop while - na maioria das plataformas, ls classifica os resultados e isso também pode ser muito caro para diretórios grandes. O tipo ls não é necessário aqui, já que tudo o que nos interessa é a contagem.

    
por 10.07.2009 / 16:18
5

Você pode usar este pequeno snippet:

find | cut -d/ -f2 | uniq -c | sort -n

Ele irá imprimir quantos arquivos e diretórios estão em cada um dos diretórios na pasta atual, com os maiores ofensores na parte inferior. Isso ajudará você a encontrar diretórios com muitos arquivos. ( mais informações )

    
por 11.02.2010 / 12:03
3

Esta não é uma resposta direta à sua pergunta, mas a pesquisa de arquivos modificados recentemente com um tamanho pequeno usando a localização pode restringir sua pesquisa:

find / -mmin -10 -size -20k
    
por 10.07.2009 / 15:36
3
find /path ! -type d | sed 's,/[^/]*$,,' | uniq -c | sort -rn

ls não encontrará arquivos cujos nomes iniciem com um ponto. Usar o find evita isso. Isso localiza todos os arquivos na árvore de diretórios, retira o nome da base do final de cada caminho e conta o número de vezes que cada caminho de diretório aparece na saída resultante. Você pode ter que colocar o "!" entre aspas, se a sua shell reclamar.

Os inodes também podem ser usados por arquivos que foram excluídos, mas que estão sendo mantidos abertos por um processo em execução. Se este pacote Munin incluir quaisquer programas em execução constante, outra coisa a verificar é se está abrindo um número incomum de arquivos.

    
por 10.07.2009 / 21:11
3

Eu usaria a força bruta aqui: execute o tripwire em todo o dispositivo para obter uma linha de base, depois execute um teste algum tempo depois e o diretório ofensivo ficará destacado como um polegar dolorido.

    
por 10.07.2009 / 22:10
2

(não poder comentar está realmente ficando velho - isso é para egorgry)

egorgry - ls -i imprime o inode NUMBER para uma entrada, não o inode COUNT.

Experimente com um arquivo em seu diretório - você (provavelmente) verá um número igualmente alto, mas não é a contagem de inodes, é apenas o inode # em que aponta sua entrada de diretório.

    
por 10.07.2009 / 17:02
2

Atualizar

Um forro que retorna a contagem de inode de cada filho de determinado diretório com as maiores entradas na parte inferior.

find . -mindepth 1 -printf "%p/%i\n" \
  | awk -F/ '{print $2"/"$NF}' | sort -u \
  | cut -d/ -f1 | uniq -c | sort -n

Resposta original

#!/bin/bash
# Show inode distribution for given directory

dirs=$(find $1 -mindepth 1 -maxdepth 1 -type d)

for dir in $dirs
do
    inode_count=$(find $dir -printf "%i\n" 2> /dev/null | sort -u | wc -l)
    echo "$inode_count $dir"
done

Execute-o assim (dado que o script acima reside em um arquivo executável em seu diretório de trabalho)

./indist / | sort -n
    
por 14.09.2012 / 16:50
1

O uso de inode é aproximadamente um por arquivo ou diretório, certo? Então faça

find [path] -print | wc -l

para contar aproximadamente quantos inodes são usados sob [caminho].

    
por 10.07.2009 / 15:36
1

Eu tentei escrever um pipeline de shell eficiente, mas tornou-se pesado e lento ou impreciso, por exemplo,

find . -depth -printf '%h\n' | uniq -c | awk '$1>1000'

listará os diretórios folha (e alguns outros) com mais de 1.000 arquivos neles. Então, aqui está um script Perl para fazê-lo com eficiência tanto no tempo quanto na memória RAM. Saída é como

«arquivos-em-sub-árvore» «arquivos diretamente no diretório» «nome-do-diretório»

para que você possa massagear e filtrar facilmente usando ferramentas normais, por exemplo, sort (1) ou awk (1) como acima.

#! /usr/bin/perl -w
# Written by Kjetil Torgrim Homme <[email protected]>

use strict;
use File::Find;

my %counted;
my %total;

sub count {
    ++$counted{$File::Find::dir};
}

sub exeunt {
    my $dir = $File::Find::dir;

    # Don't report leaf directories with no files
    return unless $counted{$dir}; 

    my $parent = $dir;
    $parent =~ s!/[^/]*$!!;

    $total{$dir} += $counted{$dir};
    $total{$parent} += $total{$dir} if $parent ne $dir;
    printf("%8d %8d %s\n", $total{$dir}, $counted{$dir}, $dir);
    delete $counted{$dir};
    delete $total{$dir};
}

die "Usage: $0 [DIRECTORY...]\n" if (@ARGV && $ARGV[0] =~ /^-/);
push(@ARGV, ".") unless @ARGV;

finddepth({ wanted => \&count, postprocess => \&exeunt}, @ARGV);
    
por 22.07.2010 / 14:40
-1
[gregm@zorak2 /]$ ls -i /home
131191 gregm

minha casa no meu laptop está usando 131191 inodes.

    
por 10.07.2009 / 16:50