Inode Kullanım Konumunu Belirleme


15

Son zamanlarda Munin'i sistem kullanımını takip etmek için bir geliştirme web sunucusuna kurdum. Disk kullanımı neredeyse hiç artmamasına rağmen, sistemin inode kullanımının günde yaklaşık% 7-8 oranında arttığını fark ettim. Sanırım bir şey bir sürü küçük dosya yazıyor ama ne / nerede bulamıyorum.

Disk alanı kullanımını nasıl bulacağımı biliyorum ama inode kullanımını özetlemenin bir yolunu bulamıyorum.

Kullanımın kaynağını bulabilmek için dizine göre inode kullanımını belirlemenin iyi bir yolu var mı?

Yanıtlar:


15

Bunun hızlı çalışmasını beklemeyin ...

cd, çok sayıda inode içeren bir alt dizin olduğundan şüphelendiğiniz bir dizine. Bu komut dosyası çok zaman alıyorsa, büyük olasılıkla dosya sisteminde nereye bakacağınızı bulmuşsunuzdur. / var iyi bir başlangıç ​​...

Aksi takdirde, o dosya sistemindeki en üst dizine geçip bunu çalıştırır ve bitmesini beklerseniz, tüm inode'ları içeren dizini bulacaksınız.

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

Sıralama maliyeti konusunda endişelenmiyorum. Ben bir test yaptım ve 350.000 dizin karşı 8 ay sürdü sıralanmamış çıktı üzerinden sıralama. İlk bulgu aldı. Gerçek maliyet while döngüsünde tüm bu dizinleri açmaktır. (döngünün kendisi 22 saniye sürer). (Test verileri 350.000 dizinli bir alt dizinde çalıştırıldı, bunlardan birinde milyon dosya vardı, geri kalanında 1-15 dizin vardı).

Çeşitli insanlar, ls'nin o kadar iyi olmadığını, çıktıyı sıraladığını belirtti. Yankıyı denedim, ama bu da harika değil. Birisi stat'in bu bilgiyi verdiğini (dizin girişi sayısı) fakat taşınabilir olmadığını belirtti. Görünen o ki -maxdepth'i bulmak gerçekten hızlıdır.


2
@mike G: Bu tür şeyleri yapmanın en hızlı yolu olmadığında% 100 haklısın. Aklımda, bunu optimize etmenin doğru yolu, komut dosyasının "dizin girişlerini say" bölümünü başlatırken ve bitirirken stderr'e yönlendirmektir. Bu şekilde, bir milyon girişli bir dizine bastığınızda "dizin biriktirme / postfix / maildrop işleniyor" der ve sonra hemen "bitmiş" ve patlama demez - spool / postfix / maildrop'a bakın ve bir sürü göreceksiniz Dosyalar.
chris

Ayrıca, bir kerelik veya en azından oldukça nadir bir görev olduğu için sıralama maliyetinden endişe etmiyordum.
Dave Forgac

7

Sorun çok fazla dosya içeren bir dizindeyse, basit bir çözüm:

# 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

findÇizginin arkasındaki fikir , bir dizinin boyutunun doğrudan o dizinin içindeki dosya miktarıyla orantılı olmasıdır. Burada, içinde tonlarca dosya bulunan dizinleri arıyoruz.

Bir sayıyı tahmin etmek istemiyorsanız ve "boyut" a göre sıralanan tüm şüpheli dizinleri listelemeyi tercih ediyorsanız, bu da kolaydır:

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

6

Grrr, yorum yapmak 50 tekrar gerektirir. Yani bu cevap aslında chris'in cevabı hakkında bir yorum.

Sorgulayan muhtemelen tüm dizinleri umursamadığı için, sadece en kötü olanları, o zaman sıralama kullanmak muhtemelen çok pahalı bir aşırı doludur.

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

Bu, sürümünüz kadar eksiksiz değildir, ancak bunun bir önceki maksimum değerden daha büyük olması durumunda baskı çizgileri yazdırılması, yazdırılan gürültü miktarını büyük ölçüde azaltması ve sıralama masrafını azaltmasıdır.

Bunun dezavantajı, 2 çok büyük dizininiz varsa ve ilki 2'den 1 inode daha varsa, asla 2'yi göremezsiniz.

Daha eksiksiz bir çözüm, görülen en iyi 10 değeri takip eden ve sonunda çıktısı basan daha akıllı bir perl betiği yazmak olacaktır. Ancak bu hızlı bir sunucu hatası cevabı için çok uzun.

Ayrıca, bazı daha akıllı perl komut dosyaları while döngüsünü atlamanıza izin verir - çoğu platformda, sonuçları sıralar ve bu da büyük dizinler için çok pahalı olabilir. Burada ls sıralama gerekli değildir, çünkü tek umurumuz budur.


1
Ls hakkında doğru - bu gibi durumlarda performans hakkında o kadar çok değil ne yaptığımı net olmak hakkında daha fazla endişeleniyorum. Echo $ line / * | ls $ hattı yerine wc -w | wc -l ve ls sıralama sorunu kaçının.
chris

Bir milyon dosya içeren bir dizinde bir test yaptım ve ls 22 saniye ve echo * 12 saniye sürdü. (Kayıt için, kabuktaki echo * arg limitine çarpmayacaktır çünkü aktif kullanımdaki kabukların% 99'undaki eko yerleşiktir)
chris

ls -f sonuçları sıralamaz. Dizin sonuçlarının sıralanması, NFS ve büyük dizinlerde yaygın bir soruna yol açar. Dizini okuma ve sıralama süresi (sunucuda) NFS zaman aşımını aşarsa, dizin ve alt dizinler kullanılamaz.
mpez0

5

Bu küçük pasajı kullanabilirsiniz:

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

Geçerli klasördeki dizinlerin her birinde kaç dosya ve dizin olduğunu, en büyük suçlular altta olacak şekilde yazdıracaktır. Çok sayıda dosya içeren dizinleri bulmanıza yardımcı olacaktır. ( daha fazla bilgi )


Bu harika çalıştı.
ptman

3

Bu, sorunuzun doğrudan bir yanıtı değildir, ancak find kullanarak küçük boyutlu son değiştirilen dosyaları aramak, aramanızı daraltabilir:

find / -mmin -10 -size -20k

3
find /path ! -type d | sed 's,/[^/]*$,,' | uniq -c | sort -rn

ls isimleri bir süre ile başlayan dosyaları bulamaz. Kullanılması find bu kaçınır. Bu, dizin ağacındaki her dosyayı bulur, her yolun sonundan temel adı atlar ve her bir dizin yolunun sonuçta elde edilen çıktıda kaç kez göründüğünü sayar. "!" Kabuğunuzdan şikayet ederse tırnak içinde.

Düğümler, silinmiş ancak çalışan bir işlem tarafından açık tutulan dosyalar tarafından da kullanılabilir. Bu Munin paketi sürekli çalışan programlar içeriyorsa, kontrol edilmesi gereken başka bir şey, olağandışı sayıda dosyayı açık tutup tutmayacağıdır.


İnodlar, bulamayacakları gerçekten derin dizinler tarafından da alınabilir. Bu konuda bazı garip kenar durumlar var, ancak en yaygın durum normal adlara sahip dosyalarla dolu bir dizindir.
chris

3

Ben bunu kaba bir kuvvet olurdu: bir taban çizgisi için tüm cihaz üzerinde tripwire çalıştırın, sonra bir süre sonra bir kontrol çalıştırın ve rahatsız edici dizin boğaz başparmak gibi yapışacaktır.


Bu muhtemelen bir milyar yıl alacaktı. Yapılacak daha hızlı bir şey lsof çalıştırmaktır | grep DIR ve birçok yeni dosya için bu dizinlerin her birine bakın.
chris

2
Tamam, bu nasıl: find / | sort> /tmp/find1.txt; bul / | sort> /tmp/find2.txt; diff /tmp/find1.txt /tmp/find2.txt
Geoff Fritz

2

(yorum yapamamak gerçekten yaşlanıyor - bu egorgry için)

egorgry - ls -i bir giriş için inode NUMBER değerini yazdırır, inode COUNT değerine yazdırmaz.

Dizininizdeki bir dosyayla deneyin - (muhtemelen) eşit derecede yüksek bir sayı göreceksiniz, ancak bu düğüm sayısı değil, sadece dizin girişinizin işaret ettiği inode #.


lol. Sana bir oy verdim. Açıklama için teşekkürler. inode kullanımı her zaman kafa karıştırıcı olmuştur.
egorgry

teşekkürler Şimdi ben bu cevabı sildiğimde karma kaybetmek durumunda, düğüm üzerinde bir yorum dönüştürmek için korkuyorum :)
Mike G.

2

Güncelleme

En büyük girişleri en altta olan belirli bir dizinin her alt öğesinin inode sayısını döndüren bir astar.

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

Orijinal Yanıt

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

Bu şekilde çalıştırın (yukarıdaki komut dosyasının çalışma dizininizdeki yürütülebilir bir dosyada bulunduğu göz önüne alındığında)

./indist / | sort -n

1

inode kullanımı dosya veya dizin başına yaklaşık birdir, değil mi? Öyleyse yap

find [path] -print | wc -l

[yol] altında yaklaşık kaç inot kullanıldığını saymak için.


1

Etkili bir kabuk boru hattı yazmaya çalıştım, ancak uygunsuz ve yavaş ya da yanlış oldu, örneğin,

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

yaprak dizinlerini (ve bazılarını) içinde 1000'den fazla dosyayla listeler. İşte, hem zaman hem de RAM'de verimli bir şekilde yapmak için bir Perl betiği. Çıktı gibi

«Alt ağaçtaki dosyalar» «doğrudan dizindeki dosyalar» «dizin adı»

böylece normal araçları kullanarak kolayca masaj yapabilir ve filtreleyebilirsiniz, örneğin, yukarıdaki gibi sıralayın (1) veya awk (1).

#! /usr/bin/perl -w
# Written by Kjetil Torgrim Homme <kjetil.homme@redpill-linpro.com>

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);

-1
[gregm@zorak2 /]$ ls -i /home
131191 gregm

dizüstü bilgisayarımdaki evim 131191 inode kullanıyor.


3
ls -i bir giriş için inode NUMBER değerini yazdırır, inode COUNT değerine yazdırmaz. Dizininizdeki bir dosyayla deneyin - (muhtemelen) eşit derecede yüksek bir sayı göreceksiniz, ancak bu düğüm sayısı değil, sadece dizin girişinizin işaret ettiği inode #.
egorgry
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.