大規模なテラバイトディレクトリからディレクトリサイズをすばやく検索する方法

大規模なテラバイトディレクトリからディレクトリサイズをすばやく検索する方法

デフォルトでは、私は4つのディレクトリを持つ3TBのディスクを持っていますが、そこには何百ものディレクトリがあります。

すべてのディレクトリの相対的なサイズを見たいです。正確である必要はなく、GB単位で表示する方が良いです。

du -sh /disk/dir1/asdf を試しました。

ただし、これらのディレクトリは数百ギガバイトに達するため、上記のプロセスは10分以上かかります。

"ncdu"は良いですが、すべての作業を完了するのに時間がかかります(数時間)。

df -hはうまく機能し、高速で相対的なサイズを提供しますが、ディスクのみを表示します。 df -hの機能をエミュレートしながら深さのサイズを変更する方法はありますか?

役に立つ場合は、そのディスクでglusterfsを使用しています。そのオプションを使用して作業をスピードアップする方法はありますか?しかし、一般的なアプローチが最善です。

ベストアンサー1

df -hはうまく機能し、高速で相対的なサイズを提供しますが、ディスクのみを表示します。 df -hの機能をエミュレートしながら深さのサイズを変更する方法はありますか?

いいえ、df -hファイルシステムがどのくらいのスペースを使用しているかを尋ねます。この情報は、サブディレクトリではなくファイルシステム全体に対してのみ存在します。

役に立つ場合は、そのディスクでglusterfsを使用しています。そのオプションを使用して作業をスピードアップする方法はありますか?しかし、一般的なアプローチが最善です。

カウントは、物理(メタデータ)ストレージの接続待ち時間が最も低いマシンで実行されます。
ファイルのリストを取得するのにかかる時間が制限される可能性があり、個々のファイルのサイズについて質問することができます。私はglusterfsとその実装についてはよくわかりませんが、次のようになります。

du -s .以下を行います。各ディレクトリのディレクトリのエントリのリストを取得します(getdents64)システムコールを使用してファイルシステムを起動してファイルのリストを提供します)。次に、これらのエントリを順番に繰り返し、各ファイルのファイル統計を取得します((newfstatat)システムコールを使用して、各ファイルに関する情報を提供するためにファイルシステムを起動します)。これには、使用されるファイルサイズが含まれます。計算合計から。
会うディレクトリごとに下向きに繰り返されます。

したがって、次のディレクトリツリーがあると、通信がたくさん行われます。

.
├── b
│   ├── b
│   ├── c
│   │   ├── e
│   │   ├── g
│   │   └── h
│   ├── d
│   └── f
├── bar
├── baz
├── foo
└── foooo

情報が見つかる./bazまでサイズ情報を取得できません。./barこの情報を取得するのにほとんどの時間は、ファイルシステムが(ネットワーク経由で!)glusterfsデーモンから情報を取得するのを待つのに費やされるため、プログラムが主に行うのは、長い時間待ってから次のファイル情報を要求することです。またお待ちください。たとえ話も同じだ。コンピュータは、サーバーから送信された内容を理解したり、サイズを追加したりするなどのタスクを実行するのに少し時間を費やし、待つのに多くの時間を費やします。

glusterfsが非同期要求を実行できる場合(そして私たちはそうであると確信しています)、簡単な解決策は「ディレクトリリストのインポート」と「ファイルサイズのインポート」の側面を別々の機能単位に置き、ファイルサイズをマルチスレッドにインポートします(単純で極端な場合は、ファイルごとに1つのスレッドを作成します)。

使用できるオレデインジャーparallel

まず、find /disk/dir1/asdf -type fすべてのファイルのリストを(順次)インポートします。 (これはマルチスレッドかもしれませんが、より複雑になる可能性があり、そのディレクトリの下のディレクトリ構造がどれほど「広い」か「深い」かによって異なります。)その後、並列parallel処理を使用して各ファイルで実行し、stat -f '%s'最後に結合します。結果を確認して追加してください。

これにより、全体の待ち時間を減らすことができなくても、多くの待機が並列に発生します。

std::asyncこれはデータ収集作業を非常に簡単にするため、C ++でも良いことです。それは次のとおりです。

#include <cstdint>
#include <filesystem>
#include <future>
#include <iostream>
#include <vector>

namespace fs = std::filesystem;
using future_t = std::future<std::uintmax_t>;

int main() {
    std::vector<future_t> futures;

    for(auto const& dir_entry : fs::recursive_directory_iterator(".")) {
        if(fs::is_regular_file(dir_entry)) {
            futures.emplace_back(std::async(
                std::launch::async,
                [](auto path) {
                    return fs::file_size(path);
                },
                dir_entry
            ));
        }
    }
    std::uintmax_t total_size = 0;
    for(auto& future : futures) {
        total_size += future.get();
    }
    std::cout << "Total size " << total_size << "b\n";
}

コンパイラエクスプローラをお試しください!またはファイルにコピーし、次のようにmain.cローカルビルドを実行します。g++ -O3 -std=c++17 -lpthread -o async_size main.ccd /path/I/want/to/know/size/of; /path/of/async_size

おすすめ記事