Tentukan Lokasi Penggunaan Inode

15

Saya baru-baru ini menginstal Munin pada server web pengembangan untuk melacak penggunaan sistem. Saya telah memperkirakan bahwa penggunaan inode sistem meningkat sekitar 7-8% per hari meskipun penggunaan disk hampir tidak meningkat sama sekali. Saya menduga ada sesuatu yang menulis satu ton file kecil tapi saya tidak dapat menemukan apa / di mana.

Saya tahu cara menemukan penggunaan ruang disk, tetapi sepertinya saya tidak bisa menemukan cara untuk meringkas penggunaan inode.

Apakah ada cara yang baik untuk menentukan penggunaan inode berdasarkan direktori sehingga saya dapat menemukan sumber penggunaannya?

Dave Forgac
sumber

Jawaban:

15

Jangan berharap ini berjalan cepat ...

cd ke direktori tempat Anda mencurigai ada subdirektori dengan banyak inode. Jika skrip ini membutuhkan banyak waktu, Anda mungkin akan menemukan di mana dalam filesystem yang akan dicari. / var adalah awal yang baik ...

Jika tidak, jika Anda mengubah ke direktori teratas dalam sistem file itu dan menjalankannya dan menunggu sampai selesai, Anda akan menemukan direktori dengan semua inode.

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

Saya tidak khawatir tentang biaya penyortiran. Saya menjalankan tes dan memilah-milah output yang tidak disortir itu terhadap 350.000 direktori membutuhkan waktu 8 detik. Temuan awal mengambil. Biaya sebenarnya adalah membuka semua direktori ini di loop sementara. (loop itu sendiri membutuhkan waktu 22 detik). (Data uji dijalankan pada subdirektori dengan 350.000 direktori, salah satunya memiliki sejuta file, sisanya memiliki antara 1 dan 15 direktori).

Berbagai orang telah menunjukkan bahwa itu tidak hebat karena itu memilah output. Saya sudah mencoba gema, tetapi itu juga tidak bagus. Orang lain telah menunjukkan bahwa stat memberikan info ini (jumlah entri direktori) tetapi tidak portabel. Ternyata find -maxdepth sangat cepat dalam membuka direktori dan menghitung .file, jadi ... ini dia .. poin untuk semua orang!

chris
sumber
2
@ Mike G: Anda 100% benar tentang ini bukan cara tercepat untuk melakukan hal semacam ini. Dalam pikiran saya, cara yang benar untuk mengoptimalkan ini adalah dengan mengarahkan ulang ke stderr ketika memulai dan menyelesaikan bagian "hitung entri direktori" dari skrip. Dengan begitu, ketika Anda menekan direktori dengan sejuta entri itu akan mengatakan "memproses direktori spool / postfix / maildrop" dan kemudian tidak mengatakan langsung "selesai" dan boom - lihat di spool / postfix / maildrop dan Anda akan melihat banyak file.
chris
Saya juga tidak khawatir tentang biaya penyortiran karena ini adalah tugas satu kali atau setidaknya cukup jarang.
Dave Forgac
7

Jika masalahnya adalah satu direktori dengan terlalu banyak file, berikut ini adalah solusi sederhana:

# 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

Gagasan di balik findgaris adalah bahwa ukuran direktori sebanding dengan jumlah file langsung di dalam direktori itu. Jadi, di sini kita mencari direktori dengan banyak file di dalamnya.

Jika Anda tidak ingin menebak nomor, dan lebih memilih untuk mencantumkan semua direktori yang dicurigai diurutkan berdasarkan "ukuran", itu juga mudah:

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

Grrr, berkomentar membutuhkan 50 rep. Jadi jawaban ini sebenarnya adalah komentar atas jawaban chris.

Karena si penanya mungkin tidak peduli dengan semua direktori, hanya yang terburuk, maka menggunakan sortir kemungkinan besar sangat mahal.

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

Ini tidak selengkap versi Anda, tetapi yang dilakukan adalah mencetak baris jika lebih besar dari maksimum sebelumnya, sangat mengurangi jumlah kebisingan yang tercetak, dan menghemat biaya semacam itu.

Kelemahan dari ini adalah jika Anda memiliki 2 direktori yang sangat besar, dan yang pertama memiliki 1 lebih banyak inode daripada yang ke-2, Anda tidak akan pernah melihat yang ke-2.

Solusi yang lebih lengkap adalah dengan menulis skrip perl yang lebih cerdas yang melacak 10 nilai teratas yang terlihat, dan mencetaknya di akhir. Tapi itu terlalu lama untuk jawaban serverfault yang cepat.

Juga, beberapa skrip perl yang lebih pintar akan membuat Anda melewatkan loop while - pada sebagian besar platform, seperti hasil, dan itu juga bisa sangat mahal untuk direktori besar. Jenis ini tidak diperlukan di sini, karena yang kita pedulikan hanyalah hitungan.

Mike G.
sumber
1
Benar tentang ls - dalam situasi seperti ini saya lebih khawatir tentang hal itu menjadi jelas apa yang saya lakukan dan tidak begitu banyak tentang kinerja. Saya cukup yakin Anda dapat menggunakan echo $ line / * | wc -w di tempat ls $ line | wc -l dan Anda menghindari masalah penyortiran ls.
chris
Saya baru saja menjalankan tes pada direktori dengan sejuta file dan butuh waktu 22 detik dan gema * butuh 12 detik. (Sebagai catatan, gema * di shell tidak akan mencapai batas arg karena gema di 99% dari shell yang digunakan aktif adalah built-in)
chris
Jika tidak akan mengurutkan hasilnya. Penyortiran hasil direktori mengarah ke masalah umum dengan NFS dan direktori besar. Jika waktu untuk membaca dan mengurutkan direktori (di server) melebihi batas waktu NFS, direktori dan subdirektori tidak dapat digunakan.
mpez0
5

Anda dapat menggunakan potongan kecil ini:

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

Ini akan mencetak berapa banyak file dan direktori di masing-masing direktori di folder saat ini, dengan pelanggar terbesar di bagian bawah. Ini akan membantu Anda menemukan direktori yang memiliki banyak file. ( info lebih lanjut )

Rory
sumber
Ini bekerja dengan sangat baik.
ptman
3

Ini bukan jawaban langsung untuk pertanyaan Anda, tetapi mencari file yang baru dimodifikasi dengan ukuran kecil menggunakan find mungkin mempersempit pencarian Anda:

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

Ia tidak akan menemukan file yang namanya dimulai dengan titik. Menggunakan find menghindari ini. Ini menemukan setiap file di pohon direktori, memotong nama samaran dari akhir setiap jalur, dan menghitung berapa kali setiap jalur direktori muncul di hasil yang dihasilkan. Anda mungkin harus meletakkan "!" dalam kutipan jika shell Anda mengeluhkannya.

Inode juga dapat digunakan oleh file yang telah dihapus tetapi ditahan terbuka oleh proses yang sedang berjalan. Jika paket Munin ini termasuk program yang terus berjalan, hal lain yang perlu diperiksa adalah apakah paket itu dibuka dengan jumlah file yang tidak biasa.

Kenster
sumber
Inode juga dapat diambil oleh direktori yang sangat dalam, yang tidak akan ditemukan. Ada beberapa kasus tepi aneh dalam hal ini, tetapi situasi yang paling umum adalah direktori yang penuh dengan file dengan nama normal.
chris
3

Saya akan memaksa yang satu ini: jalankan tripwire pada seluruh perangkat untuk baseline, kemudian jalankan pemeriksaan beberapa waktu kemudian dan direktori yang menyinggung akan menonjol seperti jempol sakit.

Geoff Fritz
sumber
Itu mungkin akan membutuhkan satu miliar tahun. Hal yang lebih cepat untuk dilakukan adalah menjalankan lsof | grep DIR dan lihat di masing-masing direktori untuk banyak file baru.
chris
2
Oke, bagaimana dengan ini: find / | sort> /tmp/find1.txt; temukan / | sort> /tmp/find2.txt; diff /tmp/find1.txt /tmp/find2.txt
Geoff Fritz
2

(Tidak bisa berkomentar benar-benar menjadi tua - ini untuk egorgry)

egorgry - ls -i mencetak inode NUMBER untuk sebuah entri, bukan COUNT inode.

Cobalah dengan file di direktori Anda - Anda (mungkin) akan melihat angka yang sama-sama tinggi, tetapi itu bukan jumlah inode, itu hanya inode yang # titik masuk direktori Anda.

Mike G.
sumber
lol. Saya memilih Anda satu. Terima kasih untuk penjelasannya. penggunaan inode selalu membingungkan.
egorgry
berkat Sekarang aku takut untuk mengubahnya menjadi komentar pada node Anda, dalam kasus saya kehilangan karma ketika saya menghapus jawaban ini :)
Mike G.
2

Memperbarui

Satu liner yang mengembalikan jumlah inode setiap anak dari direktori yang diberikan dengan entri terbesar di bagian bawah.

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

Jawaban Asli

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

Jalankan seperti ini (mengingat bahwa skrip di atas berada di file yang dapat dieksekusi di direktori kerja Anda)

./indist / | sort -n
raphinesse
sumber
1

penggunaan inode kira-kira satu per file atau direktori, kan? Begitu juga

find [path] -print | wc -l

untuk menghitung kira-kira berapa banyak inode yang digunakan di bawah [path].

pjz
sumber
1

Saya mencoba menulis pipa shell yang efisien, tetapi menjadi sulit dan lambat atau tidak akurat, misalnya,

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

akan mendaftar direktori leaf (dan beberapa lainnya) dengan lebih dari 1000 file di dalamnya. Jadi, inilah skrip Perl untuk melakukannya secara efisien dalam waktu dan RAM. Outputnya seperti

«Files-in-subtree» «files-direct-in-directory» «direktori-nama»

sehingga Anda dapat memijat dan memfilternya dengan mudah menggunakan alat normal, misalnya, urutkan (1) atau awk (1) seperti di atas.

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

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

rumah saya di laptop saya menggunakan 131191 inode.

egorgry
sumber
3
ls -i mencetak inode NUMBER untuk sebuah entri, bukan COUNT inode. Cobalah dengan file di direktori Anda - Anda (mungkin) akan melihat angka yang sama-sama tinggi, tetapi itu bukan jumlah inode, itu hanya inode yang # titik masuk direktori Anda.
egorgry