Określ lokalizację użycia i-węzła

15

Niedawno zainstalowałem Munin na rozwojowym serwerze internetowym, aby śledzić użycie systemu. Zauważyłem, że użycie i-węzła systemu rośnie o około 7-8% dziennie, chociaż użycie dysku prawie wcale nie wzrosło. Zgaduję, że coś pisze mnóstwo małych plików, ale nie mogę znaleźć co / gdzie.

Wiem, jak znaleźć użycie miejsca na dysku, ale nie mogę znaleźć sposobu na podsumowanie użycia i-węzła.

Czy istnieje dobry sposób, aby określić użycie i-węzła według katalogu, dzięki czemu mogę zlokalizować źródło użycia?

Dave Forgac
źródło

Odpowiedzi:

15

Nie oczekuj, że to zadziała szybko ...

cd do katalogu, w którym podejrzewasz, że może istnieć podkatalog z dużą ilością i-węzłów. Jeśli ten skrypt zajmuje dużo czasu, prawdopodobnie znalazłeś, gdzie w systemie plików szukać. / var to dobry początek ...

W przeciwnym razie, jeśli przejdziesz do najwyższego katalogu w tym systemie plików i uruchomisz go i zaczekasz na zakończenie, znajdziesz katalog ze wszystkimi i-węzłami.

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

Nie martwię się o koszty sortowania. Przeprowadziłem test i posortowanie tego nieposortowanego wyjścia w stosunku do 350 000 katalogów zajęło 8 sekund. Pierwsze znalezisko zajęło. Rzeczywistym kosztem jest otwarcie wszystkich tych katalogów w pętli while. (sama pętla zajmuje 22 sekundy). (Dane testowe zostały uruchomione w podkatalogu z 350 000 katalogów, z których jeden miał milion plików, reszta zawierała od 1 do 15 katalogów).

Różni ludzie zauważyli, że ls nie jest w tym świetny, ponieważ sortuje dane wyjściowe. Próbowałem echa, ale to też nie jest świetne. Ktoś inny zauważył, że stat podaje te informacje (liczbę pozycji katalogu), ale nie jest przenośny. Okazuje się, że find -maxdepth jest naprawdę szybki w otwieraniu katalogów i zlicza pliki., Więc ... tutaj są ... punkty dla wszystkich!

Chris
źródło
2
@ Mike G: Masz 100% rację, że nie jest to najszybszy sposób na zrobienie czegoś takiego. Moim zdaniem poprawnym sposobem na zoptymalizowanie tego jest przekierowanie do stderr podczas uruchamiania i kończenia części skryptu zliczania wpisów do katalogu. W ten sposób, gdy trafisz do katalogu z milionem wpisów, powiesz „Przetwarzanie buforu katalogu / postfix / maildrop”, a następnie nie powie natychmiast „zakończono” i boom - spójrz na szpulę / postfix / maildrop i zobaczysz wiele akta.
Chris
Nie martwiłem się również kosztami sortowania, ponieważ jest to zadanie jednorazowe lub przynajmniej dość rzadkie.
Dave Forgac
7

Jeśli problemem jest jeden katalog ze zbyt dużą liczbą plików, oto proste rozwiązanie:

# 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

Ideą tego findwiersza jest to, że rozmiar katalogu jest proporcjonalny do ilości plików bezpośrednio w tym katalogu. Więc szukamy katalogów z mnóstwem plików w środku.

Jeśli nie chcesz zgadywać numeru i wolisz wymienić wszystkie podejrzane katalogi uporządkowane według „rozmiaru”, to też jest łatwe:

# Remove the "sort" command if you want incremental output
find / -xdev -size +10k -type d -printf '%s %p\n' | sort -n
Denilson Sá Maia
źródło
6

Grrr, komentarz wymaga 50 powtórzeń. Ta odpowiedź jest więc komentarzem do odpowiedzi Chris'a.

Ponieważ pytający prawdopodobnie nie przejmuje się wszystkimi katalogami, tylko najgorszymi, użycie sortowania jest prawdopodobnie bardzo kosztowną przesadą.

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

Nie jest to tak kompletne jak twoja wersja, ale to robi linie wydruku, jeśli są większe niż poprzednie maksimum, znacznie zmniejszając ilość wydrukowanego szumu i oszczędzając koszty tego rodzaju.

Wadą tego jest to, że jeśli masz 2 bardzo duże katalogi, a pierwszy ma o 1 więcej i-węzłów niż drugi, nigdy nie zobaczysz drugiego.

Bardziej kompletnym rozwiązaniem byłoby napisanie mądrzejszego skryptu perlowego, który śledzi 10 najważniejszych wartości i wypisuje je na końcu. Ale to zbyt długo, aby szybko odpowiedzieć na błąd serwera.

Ponadto, nieco bardziej inteligentne skrypty perla pozwoliłyby pominąć pętlę while - na większości platform ls sortuje wyniki, a to może być bardzo kosztowne w przypadku dużych katalogów. Sortowanie ls nie jest tutaj konieczne, ponieważ liczy się tylko liczba.

Mike G.
źródło
1
To prawda o ls - w takich sytuacjach martwię się bardziej o to, aby wyjaśnić, co robię, a nie o wydajność. Jestem prawie pewien, że możesz użyć echa $ line / * | wc -w zamiast wiersza ls $ | wc -l i unikniesz problemu sortowania ls.
Chris
Właśnie uruchomiłem test na katalogu z milionem plików i ls zajęło 22 sekundy, a echo * zajęło 12 sekund. (Dla przypomnienia, echo * w powłoce nie osiągnie limitu arg, ponieważ echo w 99% aktywnych powłok jest wbudowane)
Chris
ls -f nie posortuje wyników. Sortowanie wyników katalogów prowadzi do typowego problemu z NFS i dużymi katalogami. Jeśli czas czytania i sortowania katalogu (na serwerze) przekroczy limit czasu NFS, katalog i podkatalogi nie będą nadawać się do użytku.
mpez0
5

Możesz użyć tego małego fragmentu:

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

Wydrukuje, ile plików i katalogów znajduje się w każdym z katalogów w bieżącym folderze, z największymi przestępcami na dole. Pomoże Ci znaleźć katalogi zawierające wiele plików. ( więcej informacji )

Rory
źródło
To działało doskonale.
ptman
3

To nie jest bezpośrednia odpowiedź na twoje pytanie, ale wyszukiwanie ostatnio zmodyfikowanych plików o małym rozmiarze za pomocą find może zawęzić wyszukiwanie:

find / -mmin -10 -size -20k
Kyle Brandt
źródło
3
find /path ! -type d | sed 's,/[^/]*$,,' | uniq -c | sort -rn

ls nie znajdzie pliki, których nazwy zaczynają się od kropki. Używanie find pozwala tego uniknąć. Znajduje każdy plik w drzewie katalogów, odcina nazwę basename od końca każdej ścieżki i zlicza ile razy każda ścieżka katalogu pojawia się w wynikowym wyniku. Może być konieczne wstawienie „!” w cytatach, jeśli twoja skorupa na to narzeka.

I-węzły mogą być również wykorzystywane przez pliki, które zostały usunięte, ale są utrzymywane otwarte przez uruchomiony proces. Jeśli ten pakiet Munin zawiera jakieś stale działające programy, inną rzeczą do sprawdzenia jest to, czy przechowuje on nietypową liczbę plików.

Kenster
źródło
I-węzły mogą być również pobierane przez naprawdę głębokie katalogi, których nie znajdzie. Jest w tym wiele dziwnych przypadków brzegowych, ale najczęstszą sytuacją jest katalog pełen plików o normalnych nazwach.
Chris
3

Brute force to jeden: uruchom tripwire na całym urządzeniu, aby uzyskać linię bazową, a następnie uruchom test jakiś czas później, a katalog przestępców wystanie jak obolały kciuk.

Geoff Fritz
źródło
To zajmie prawdopodobnie miliard lat. Szybsze jest uruchomienie lsof | grep DIR i poszukaj w każdym z tych katalogów wielu nowych plików.
Chris
2
Ok, a co z tym: znajdź / | sort> /tmp/find1.txt; znajdź / | sort> /tmp/find2.txt; diff /tmp/find1.txt /tmp/find2.txt
Geoff Fritz
2

(brak możliwości komentowania naprawdę się starzeje - dotyczy to egorgry)

egorgry - ls -i drukuje i-węzeł NUMBER dla pozycji, a nie i-COUNT.

Wypróbuj go z plikiem w katalogu - prawdopodobnie zobaczysz równie wysoką liczbę, ale to nie jest liczba i-węzłów, to tylko i-węzeł #, na który wskazuje twój wpis w katalogu.

Mike G.
źródło
lol. Głosowałem za tobą. Dziękuję za wyjaśnienie. użycie i-węzła zawsze było mylące.
egorgry,
dzięki Teraz boję się przekształcić to w komentarz na twoim węźle, na wypadek, gdy stracę karmę po usunięciu tej odpowiedzi :)
Mike G.
2

Aktualizacja

Jeden linijka, która zwraca liczbę i-węzłów każdego potomka danego katalogu z największymi wpisami na dole.

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

Oryginalna odpowiedź

#!/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

Uruchom go w ten sposób (biorąc pod uwagę, że powyższy skrypt znajduje się w pliku wykonywalnym w katalogu roboczym)

./indist / | sort -n
raphinesse
źródło
1

użycie i-węzła wynosi około jednego na plik lub katalog, prawda? Tak też

find [path] -print | wc -l

policzyć w przybliżeniu, ile i-węzłów jest używanych w [ścieżka].

pjz
źródło
1

Próbowałem napisać skuteczny potok powłoki, ale stał się nieporęczny i albo powolny, albo niedokładny, np.

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

wyświetli katalogi liści (i niektóre inne) zawierające ponad 1000 plików. Oto skrypt Perla, który wykonuje to skutecznie zarówno pod względem czasu, jak i pamięci RAM. Wyjście jest jak

«Pliki w poddrzewie» «pliki bezpośrednio w katalogu» «nazwa katalogu»

dzięki czemu można go łatwo masować i filtrować za pomocą zwykłych narzędzi, np. sortuj (1) lub awk (1) jak wyżej.

#! /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);

źródło
-1
[gregm@zorak2 /]$ ls -i /home
131191 gregm

mój dom na moim laptopie używa i-węzłów 131191.

egorgry
źródło
3
ls -i drukuje i-węzeł NUMBER dla pozycji, a nie i-COUNT. Wypróbuj go z plikiem w katalogu - prawdopodobnie zobaczysz równie wysoką liczbę, ale to nie jest liczba i-węzłów, to tylko i-węzeł #, na który wskazuje twój wpis w katalogu.
egorgry,