以前は非常に大きかった小さなディレクトリで「ls」がなぜそんなに時間がかかりますか?この問題をどのように解決しますか?

以前は非常に大きかった小さなディレクトリで「ls」がなぜそんなに時間がかかりますか?この問題をどのように解決しますか?

私はArch Linuxを実行しており、ext4ファイルシステムを使用しています。

ls今は実際には小さいですが、以前は非常に大きかったディレクトリで実行するとしばらく停止します。しかし、次回実行するとほぼ瞬時に実行されます。

私はこれを試みます:

strace ls

しかし、正直なところ、出力をデバッグする方法がわかりません。 100行を超えても必要に応じて投稿できます。

そしていいえ、エイリアスを使用しません。

$ type ls
ls is hashed (/usr/bin/ls)

$ df .
Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/sda9      209460908 60427980 138323220  31% /home

答え1

かつて、大きなディレクトリにはまだ多くのブロックがディレクトリエントリ(=ディレクトリ内のファイルとサブディレクトリの名前とinode番号)に割り当てられている可能性がありますが、そのブロックの大部分は削除されたとマークされています。

新しいディレクトリが作成されると、ディレクトリエントリに最小限のスペースしか割り当てられません。追加のファイルが追加されると、必要に応じてディレクトリエントリを保持するために新しいブロックが割り当てられます。ただし、ファイルが削除されると、ファイルext4システムはすぐに再び必要になる可能性があると仮定して、現在必要でないディレクトリエントリと利用可能なディレクトリメタデータブロックをマージしません。

e2fsck -C0 -f -D /dev/sda9追加のディレクトリメタデータブロックを取得し、既存のディレクトリエントリをより小さなスペースにマージするには、ファイルシステムをマウント解除し、そのシステムのディレクトリを最適化するために実行する必要があります。

これは/homeファイルシステムなので、すべての一般ユーザーアカウントがログアウトされていることを確認してから、ルート(通常はテキストコンソール)としてローカルにログインしてこれを実行できます。umount /homeこの状況でファイルシステムが使用中であると報告された場合は、fuser -m /dev/sda9マウント解除を妨げるプロセスを識別できます/home。以前のユーザーセッションの残りの部分では直接終了できますが、サービスに属している場合は制御された方法で停止できます。

このタイプの主なメンテナンスを実行するもう1つの一般的な方法は、/homeシステムをシングルユーザー/緊急モードで起動することです。使用されているディストリビューションでは、systemd起動オプションがsystemd.unit=emergency.targetその役割を果たす必要があります。

他の人が述べたように、より簡単な解決策があります。ディレクトリのタイムスタンプが保存されるかどうかは重要ではありません。、問題ディレクトリは、そのディレクトリを含むファイルシステムのルートではありません。 「肥大した」ディレクトリの横に新しいディレクトリを作成し、すべてのファイルを新しいディレクトリに移動し、古いディレクトリを削除し、新しいディレクトリの名前を同じに変更します。名前は昔のようです。たとえば、/directory/A問題がある場合:

mkdir /directory/B
mv /directory/A/* /directory/B/      # regular files and sub-directories
mv /directory/A/.??* /directory/B/   # hidden files/dirs too
rmdir /directory/A
mv /directory/B /directory/A

もちろん、ディレクトリがどのサービスで使用されている場合は、そのサービスを最初に停止するのが最善です。

答え2

好奇心でこれを再現しましょう:

$ mkdir test
$ cd test
$ time ls   # Check initial speed of ls
real    0m0,002s
$ stat .    # Check initial size of directory
  File: .
  Size: 4096        Blocks: 8          IO Block: 4096   directory
  ...
$ seq 1 1000000 | xargs touch    # Create lot of files
$ echo 3 | sudo tee /proc/sys/vm/drop_caches   # Clear cache
$ time ls > /dev/null
real    0m1.588s
$ stat .                        # Check size of directory when files are there
  File: .
  Size: 22925312    Blocks: 44776      IO Block: 4096   directory

さて、今私たちは大きなディレクトリを持っています。このファイルを削除し、何が起こるのか見てみましょう。

$ ls | xargs rm   # To avoid too long argument list
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
$ time ls > /dev/null
real    0m1.242s
$ stat .
 File: .
 Size: 22925312     Blocks: 44776      IO Block: 4096   directory

はいls。 TelcoMの回答でも指摘したように、ディレクトリの割り当てサイズが実際に大きく、速度が遅くなります。

問題が単一のディレクトリの場合は、ルートアクセスまたはルートアクセスを必要としないより簡単なソリューションがあります。新しいディレクトリを作成し、残りのファイルをそのディレクトリに移動して、肥大化したファイルを削除します。

関連情報