确定Inode用法的位置


15

我最近在开发Web服务器上安装了Munin,以跟踪系统使用情况。我注意到,即使磁盘使用量几乎没有增加,系统的inode每天仍会上升约7-8%。我猜有些东西正在写大量的小文件,但我找不到什么/在哪里。

我知道如何查找磁盘空间使用情况,但似乎找不到一种汇总inode使用情况的方法。

是否有按目录确定索引节点使用情况的好方法,以便我可以找到使用情况的来源?

Answers:


15

不要指望它能快速运行...

cd到您怀疑其中可能存在一个包含许多inode的子目录的目录。如果此脚本花费大量时间,您可能已经找到了文件系统中的位置。/ var是一个好的开始...

否则,如果您转到该文件系统中的顶层目录并运行它并等待其完成,则将找到包含所有inode的目录。

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

我不担心排序的成本。我进行了测试,然后对850,000个目录的未排序输出进行了排序。最初的发现花了。真正的代价是在while循环中打开所有这些目录。(循环本身需要22秒)。(测试数据在包含350,000个目录的子目录上运行,其中一个目录具有一百万个文件,其余目录具有1至15个目录)。

各种各样的人指出ls并不是很好,因为它对输出进行排序。我曾尝试过echo,但这也不是很好。有人指出,stat提供了此信息(目录条目数),但它不是可移植的。事实证明,find -maxdepth在打开目录并计数.file时确实非常快,所以...在这里,这是每个人的要点!


2
@mike G:对于这不是最快的方法,您是100%正确的。在我看来,优化此方法的正确方法是在开始和结束脚本的“计数目录项”部分时重定向到stderr。这样,当您命中具有一百万个条目的目录时,它会说“正在处理目录spool / postfix / maildrop”,而不是立即说“已完成”和繁荣-查看spool / postfix / maildrop,您会看到很多文件。
克里斯,2009年

我也不担心排序的成本,因为这是一次性的任务,或者至少是非常少见的任务。
戴夫·福加克

7

如果问题是一个目录中包含太多文件,那么这是一个简单的解决方案:

# 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代表。因此,此答案实际上是对克里斯答案的评论。

由于发问者可能并不关心所有目录,仅关心最差的目录,因此使用sort可能是非常昂贵的过度杀伤力。

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个非常大的目录,而第一个恰好比第二个多1个inode,则您将永远看不到第二个。

一个更完整的解决方案是编写一个更智能的perl脚本,该脚本跟踪所看到的前10个值,并在最后输出这些值。但这对于快速的服务器故障答案来说太长了。

另外,一些中度更聪明的perl脚本可以让您跳过while循环-在大多数平台上,ls对结果进行排序,这对于大型目录也可能非常昂贵。ls排序在这里不是必需的,因为我们只关心计数。


1
关于ls的说法是正确的-在这种情况下,我更担心的是清楚自己在做什么,而不是对性能有太多关注。我很确定您可以使用echo $ line / * | wc -w代替ls $ line | wc -l可以避免ls排序问题。
克里斯,2009年

我只是在具有一百万个文件的目录上进行了测试,ls花费了22秒,echo *花费了12秒。(根据记录,shell中的echo *不会达到arg限制,因为在主动使用的99%外壳中的echo是内置的)
chris

ls -f不会对结果进行排序。目录结果的排序导致NFS和大型目录的常见问题。如果读取和排序目录(在服务器上)的时间超过NFS超时,则目录和子目录将不可用。
mpez0'2

5

您可以使用以下小片段:

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

它将打印出当前文件夹中每个目录中有多少个文件和目录,违例数最大的位于底部。这将帮助您查找包含大量文件的目录。(更多信息


这非常出色。
ptman


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

ls将找不到名称以句点开头的文件。使用find可以避免这种情况。这将在目录树中找到每个文件,在每个路径的末尾标明基本名称,并计算每个目录路径出现在结果输出中的次数。您可能需要输入“!” 如果您的shell抱怨,请用引号引起来。

索引节点还可以被已删除但正在运行的进程保持打开状态的文件用尽。如果此Munin软件包包含任何正在运行的程序,则要检查的另一件事是它是否正在打开异常数量的文件。


索引节点也可以由真正的较深目录获取,这将找不到。在这种情况下有很多奇怪的情况,但是最常见的情况是目录中充满了具有正常名称的文件。
克里斯,2009年

3

我会蛮力地这样做:在整个设备上运行tripwire作为基准,然后过一会儿再执行一次检查,令人讨厌的目录将像拇指酸痛地伸出来。


这可能需要十亿年。更快的方法是运行lsof | grep DIR,然后在每个目录中查找许多新文件。
克里斯·克里斯(

2
好的,如何处理:查找/ | 排序> /tmp/find1.txt; 查找/ | 排序> /tmp/find2.txt; diff /tmp/find1.txt /tmp/find2.txt
Geoff Fritz,2009年

2

(无法发表评论的年龄实际上已经变老了-这是出于egorgry)

egorgry-ls -i输出条目的索引节点号,而不是索引索引号。

尝试使用目录中的文件-您(可能)会看到一个同样高的数字,但这不是索引节点的数量,它只是目录条目指向的索引节点。


大声笑。我投票赞成你。感谢您的解释。索引节点的用法一直令人困惑。
egorgry

谢谢,现在我担心将其转换为您节点上的评论,以防万一删除此答案时我失去业力:)
Mike G.

2

更新资料

一种衬里,返回给定目录中每个子项的索引节点计数,其最大条目位于底部。

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

每个文件或目录的inode用法大约是一个,对吗?也是

find [path] -print | wc -l

计算大约在[path]下使用了多少个inode。


1

我试图编写一个有效的shell管道,但是它变得笨拙,缓慢或不准确,例如,

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

将列出其中包含1000多个文件的叶目录(和其他一些目录)。因此,这是一个Perl脚本,可以在时间和RAM上高效地完成此任务。输出就像

«子树中的文件»«目录中的文件直接»«目录名»

因此,您可以使用常规工具(例如上述的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索引节点。


3
ls -i输出条目的索引节点号,而不是索引索引号。尝试使用目录中的文件-您(可能)会看到一个同样高的数字,但这不是索引节点的数量,它只是目录条目指向的索引节点。
egorgry
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.