iノードの使用場所を決定する


15

最近、システムの使用状況を追跡するために、Muninを開発用Webサーバーにインストールしました。ディスク使用量はほとんど増加していませんが、システムのiノード使用量は1日あたり約7〜8%増加していることに気付きました。私は何かがたくさんの小さなファイルを書いていると推測していますが、何/どこを見つけることができません。

ディスク領域の使用量を見つける方法は知っていますが、iノードの使用量を要約する方法を見つけることができないようです。

ディレクトリごとにiノードの使用状況を判断する良い方法はありますか?

回答:


15

これがすぐに実行されることを期待しないでください...

多数のiノードがあるサブディレクトリがあると思われるディレクトリにcdします。このスクリプトに膨大な時間がかかる場合、ファイルシステム内のどこを探すべきかを見つけた可能性があります。/ varは良いスタートです...

それ以外の場合、そのファイルシステムの最上位ディレクトリに移動してこれを実行し、終了するのを待つと、すべてのiノードを含むディレクトリが見つかります。

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

ソートのコストは心配していません。私はテストを実行し、350,000のディレクトリに対してソートされていない出力をソートするのに8秒かかりました。最初の発見はかかりました。実際のコストは、whileループでこれらすべてのディレクトリを開くことです。(ループ自体は22秒かかります)。(テストデータは350,000個のディレクトリを持つサブディレクトリで実行され、そのうちの1つは100万個のファイルを持ち、残りは1〜15個のディレクトリを持ちました)。

lsは出力をソートするので、lsはそれほど優れていないと多くの人が指摘していました。私はエコーを試みましたが、それも素晴らしいことではありません。他の誰かが、statはこの情報(ディレクトリエントリの数)を提供するが、移植性がないことを指摘していました。find -maxdepthはディレクトリを開くのに非常に高速で、.filesをカウントするため、...ここにあります。


2
@mike G:これがこの種のことをする最速の方法ではないということは100%正しい。私の考えでは、これを最適化する正しい方法は、スクリプトの「ディレクトリエントリのカウント」部分を開始および終了するときにstderrにリダイレクトすることです。そのようにすると、100万エントリのディレクトリにアクセスすると、「spool / postfix / maildropを処理中」と表示され、すぐに「終了」とブームとは表示されません。spool/ postfix / maildropを見ると、ファイル。
クリス

また、これは1回限りのタスクまたは少なくともかなりまれなタスクなので、ソートのコストについては心配していませんでした。
デイブForgac 09

7

問題が1つのディレクトリのファイル数が多すぎる場合、簡単な解決策を次に示します。

# 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ラインの背後にある考え方は、ディレクトリのサイズがそのディレクトリ内のファイルの量に直接比例するということです。そのため、ここでは大量のファイルが含まれるディレクトリを探します。

数字を推測したくなく、「サイズ」で順序付けられたすべての疑わしいディレクトリを一覧表示したい場合は、それも簡単です。

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

6

Grrr、コメントするには50担当者が必要です。したがって、この答えは実際にはクリスの答えに対するコメントです。

質問者はおそらくすべてのディレクトリを気にするわけではなく、最悪のディレクトリだけを気にするので、ソートの使用はおそらく非常に高価なやり過ぎです。

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

これはあなたのバージョンほど完全ではありませんが、これは行が前の最大値よりも大きい場合に行を印刷し、印刷されるノイズの量を大幅に削減し、並べ替えの費用を節約します。

これの欠点は、2つの非常に大きなディレクトリがあり、最初のディレクトリに2番目のディレクトリより1つ多いiノードがある場合、2番目のディレクトリが表示されないことです。

より完全な解決策は、上位10個の値を追跡し、最後にそれらを出力する、よりスマートなperlスクリプトを作成することです。しかし、サーバーフォールトの簡単な答えには長すぎます。

また、いくつかのよりスマートなperlスクリプトを使用すると、whileループをスキップできます。ほとんどのプラットフォームで、lsは結果をソートします。これは、大きなディレクトリでは非常に高価になる可能性があります。ここで重要なのはカウントだけなので、lsソートはここでは必要ありません。


1
lsについては本当です-このような状況では、パフォーマンスについてそれほどではなく、自分がやっていることを明確にすることをもっと心配します。echo $ line / *を使用できると確信しています。ls $ lineの代わりにwc -w | wc -lを使用すると、lsソートの問題を回避できます。
クリス

100万のファイルがあるディレクトリでテストを実行したところ、lsは22秒かかり、echo *は12秒かかりました。(レコードの場合、アクティブな使用中のシェルの99%のエコーは組み込みであるため、シェルのecho *は引数の制限に達しません)
クリス

ls -fは結果をソートしません。ディレクトリの結果を並べ替えると、NFSおよび大きなディレクトリで一般的な問題が発生します。(サーバー上の)ディレクトリの読み取りとソートの時間がNFSタイムアウトを超えると、ディレクトリとサブディレクトリは使用できなくなります。
mpez0

5

この小さなスニペットを使用できます:

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

現在のフォルダ内の各ディレクトリにあるファイルとディレクトリの数を出力します。最大の違反者は一番下にあります。たくさんのファイルがあるディレクトリを見つけるのに役立ちます。(詳細


これは見事に機能しました。
ptman

3

これはあなたの質問に対する直接的な答えではありませんが、findを使用してサイズが小さい最近変更されたファイルを検索すると、検索が絞り込まれます。

find / -mmin -10 -size -20k

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

lsは、名前がピリオドで始まるファイルを検出しません。findを使用すると、これ回避できます。これにより、ディレクトリツリー内のすべてのファイルが検索され、各パスの末尾からベース名が削除され、結果の出力に各ディレクトリパスが表示される回数がカウントされます。「!」を付ける必要があるかもしれません シェルが文句を言う場合は引用符で囲みます。

iノードは、削除されたが実行中のプロセスによって開かれているファイルによって使い果たされることもあります。このMuninパッケージに常時実行されるプログラムが含まれている場合、チェックすべきもう1つのことは、異常な数のファイルを開いているかどうかです。


iノードは、本当に深いディレクトリによって取得されることもありますが、これは見つかりません。これには多くの奇妙なエッジケースがありますが、最も一般的な状況は、通常の名前のファイルでいっぱいのディレクトリです。
クリス

3

私はこれをブルートフォースします。ベースラインのためにデバイス全体でtripwireを実行し、しばらくしてからチェックを実行すると、問題のディレクトリがひどい親指のように突き出ます。


それにはおそらく10億年かかるでしょう。より簡単なことは、lsofを実行することです。grep DIRを実行し、これらの各ディレクトリを調べて、多数の新しいファイルを探します。
クリス

2
OK、これはどうですか:find / | sort> /tmp/find1.txt; 見つける/ | sort> /tmp/find2.txt; diff /tmp/find1.txt /tmp/find2.txt
ジェフフリッツ

2

(コメントできないことは本当に古くなっています-これはエゴリー用です)

egorgry-ls -iは、iノードCOUNTではなく、エントリのiノードNUMBERを出力します。

ディレクトリ内のファイルで試してみてください-(おそらく)同様に高い数が表示されますが、iノードの数ではなく、ディレクトリエントリが指す#iノードだけです。


笑。投票しました。説明してくれてありがとう。iノードの使用は常に混乱を招きます。
エゴリー2009

おかげで、この回答を削除したときにカルマを失った場合に備えて、これをあなたのノードのコメントに変換するのが怖いです:)
マイクG.

2

更新

指定されたディレクトリの各子のiノードカウントを返す1つのライナー。一番下に最大のエントリがあります。

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

元の回答

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

このように実行します(上記のスクリプトが作業ディレクトリの実行可能ファイルに存在する場合)

./indist / | sort -n

1

iノードの使用量は、ファイルまたはディレクトリごとに約1つです。そうする

find [path] -print | wc -l

[path]で使用されているおおよそのiノード数を数えます。


1

効率的なシェルパイプラインを記述しようとしましたが、扱いにくくなり、低速または不正確になりました。たとえば、

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

1000以上のファイルが含まれるリーフディレクトリ(および他のいくつか)をリストします。そのため、時間とRAMの両方で効率的に実行するPerlスクリプトを次に示します。出力は

«サブツリー内のファイル»«ディレクトリ内のファイル直接»«ディレクトリ名»

したがって、通常のツール、たとえば上記のsort(1)または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

私のラップトップ上の私の家は131191のiノードを使用しています。


3
ls -iは、iノードCOUNTではなく、エントリのiノードNUMBERを出力します。ディレクトリ内のファイルで試してみてください-(おそらく)同様に高い数が表示されますが、iノードの数ではなく、ディレクトリエントリが指す#iノードだけです。
エゴリー2009
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.