何百万ものテキストファイルをLinuxファイルシステムに保存し、任意のコレクションをZipアップしてサービスとして提供できるようにしたいと考えています。キー/値データベースのような他のソリューションを試しましたが、同時実行性と並列処理の要件により、ネイティブファイルシステムを使用するのが最適です。
最も簡単な方法は、すべてのファイルをフォルダーに保存することです。
$ ls text_files/
1.txt
2.txt
3.txt
which EXT4ファイルシステムで可能である必要があります 。これは、フォルダ内のファイル数に制限はありません。
2つのFSプロセスは次のようになります。
私の質問は、フォルダーに最大1000万のファイルを保存すると、上記の操作のパフォーマンス、または一般的なシステムパフォーマンスに、ファイルを格納するサブフォルダーのツリーを作成する場合とは異なる影響があるのでしょうか。
ls
コマンド、またはシェルによるTAB補完またはワイルドカード展開でさえ、通常は結果を英数字順に表示します。これには、ディレクトリリスト全体を読み取ってソートする必要があります。 1つのディレクトリに1千万のファイルがある場合、この並べ替え操作には無視できない時間がかかります。
あなたがTAB補完の衝動に抵抗できれば完全に圧縮するファイルの名前を書きます。問題はないはずです。
ワイルドカードのもう1つの問題は、ワイルドカードの拡張であり、最大長のコマンドラインに収まらないファイル名が生成される可能性があります。一般的なコマンドラインの最大長はほとんどの状況で十分ですが、1つのディレクトリにある何百万ものファイルについて話しているとき、これはもはや安全な仮定ではありません。ワイルドカード展開でコマンドラインの最大長を超えると、ほとんどのシェルはコマンドライン全体を実行せずに失敗します。
これは、find
コマンドを使用してワイルドカード操作を行うことで解決できます。
find <directory> -name '<wildcard expression>' -exec <command> {} \+
または可能な限り同様の構文。 find ... -exec ... \+
は、コマンドラインの最大長を自動的に考慮に入れ、最大数のファイル名を各コマンドラインに合わせながら、必要な回数だけコマンドを実行します。
これは非常に意見ベースの質問/回答に近いですが、私は私の意見でいくつかの事実を提供しようとします。
mv * /somewhere/else
)は、ワイルドカードを正常に展開できなかったり、結果が大きすぎて使用できない場合があります。ls
は、少数のファイルよりも非常に多数のファイルを列挙するのに時間がかかります。1つの推奨事項は、ファイル名を2つ、3つ、または4つの文字チャンクに分割し、それらをサブディレクトリとして使用することです。たとえば、somefilename.txt
はsom/efi/somefilename.txt
として格納されます。数値名を使用している場合は、左から右ではなく右から左に分割して、より均等な分布になるようにします。たとえば、12345.txt
は345/12/12345.txt
として格納されます。
Zip -j zipfile.Zip path1/file1 path2/file2 ...
と同等のものを使用して、Zipファイルに中間サブディレクトリパスを含めないようにすることができます。
Webサーバーからこれらのファイルを提供している場合(それが関連するかどうかは完全にはわかりません)、Apache2の書き換えルールで仮想ディレクトリを優先してこの構造を非表示にするのは簡単です。 Nginxについても同様です。
映画、テレビ、ビデオゲームのデータベースを扱うウェブサイトを運営しています。これらのそれぞれについて、テレビごとに複数の画像があり、番組ごとに数十枚の画像が含まれています(エピソードのスナップショットなど)。
たくさんの画像ファイルが存在することになります。 250,000以上の範囲のどこか。これらはすべて、アクセス時間が妥当なマウントされたブロックストレージデバイスに格納されます。
画像を保存する最初の試みは、/mnt/images/UUID.jpg
として単一のフォルダーにありました
私は以下の課題に遭遇しました。
ls
は、リモートターミナル経由でハングします。プロセスはゾンビになり、CTRL+C
はそれを壊しません。ls
コマンドを実行すると出力バッファーがすぐにいっぱいになり、CTRL+C
は無限スクロールを停止しません。パスを作成するために、作成時間を使用してファイルをサブフォルダーに保存する必要がありました。 /mnt/images/YYYY/MM/DD/UUID.jpg
など。これにより、上記のすべての問題が解決され、日付をターゲットとするZipファイルを作成できるようになりました。
あなたが持っているファイルの唯一の識別子が数値であり、これらの番号が順番に実行される傾向がある場合。 100000
、10000
、1000
でグループ化しないでください。
たとえば、384295.txt
という名前のファイルがある場合、パスは次のようになります。
/mnt/file/300000/80000/4000/295.txt
あなたが知っているなら、あなたは数百万に達するでしょう。 1,000,000には0
接頭辞を使用
/mnt/file/000000/300000/80000/4000/295.txt
まず、 'ls'が 'ls -U'で並べ替えられないようにします。おそらく〜/ bashrcを更新して、 'alias ls = "ls -U"'または類似のものにします。
大きなファイルセットの場合は、次のようにして試すことができます。
テストファイルのセットを作成する
多くのファイル名が問題を引き起こすかどうかを確認します
xargs parmeter-batchingおよびZipにファイルを追加する(デフォルト)動作を使用して、問題を回避します。
これはうまくいきました:
# create ~ 100k files
seq 1 99999 | sed "s/\(.*\)/a_somewhat_long_filename_as_a_prefix_to_exercise_Zip_parameter_processing_\1.txt/" | xargs touch
# see if Zip can handle such a list of names
Zip -q /tmp/bar.Zip ./*
bash: /usr/bin/Zip: Argument list too long
# use xargs to batch sets of filenames to Zip
find . -type f | xargs Zip -q /tmp/foo.Zip
l /tmp/foo.Zip
28692 -rw-r--r-- 1 jmullee jmullee 29377592 2017-12-16 20:12 /tmp/foo.Zip
Webスクレイプからテキストファイルを書き込みます(フォルダー内のファイル数の影響を受けません)。
新しいファイルを作成するには、ディレクトリファイルをスキャンして、新しいディレクトリエントリに十分な空きスペースを探す必要があります。新しいディレクトリエントリを保存するのに十分な大きさのスペースが見つからない場合は、ディレクトリファイルの最後に配置されます。ディレクトリ内のファイル数が増えると、ディレクトリをスキャンする時間も長くなります。
ディレクトリファイルがシステムキャッシュに残っている限り、これによるパフォーマンスヒットは悪くありませんが、データが解放された場合、ディスクからディレクトリファイル(通常は非常に断片化されている)を読み取ると、かなりの時間がかかる可能性があります。 SSDはこれを改善しますが、何百万ものファイルを含むディレクトリの場合、パフォーマンスに大きな影響が出る可能性があります。
ファイル名のリストで指定された、選択したファイルを圧縮します。
これはまた、数百万のファイルがあるディレクトリで追加の時間が必要になる可能性があります。ハッシュされたディレクトリエントリを持つファイルシステム(EXT4など)では、この違いはごくわずかです。
フォルダに最大1000万個のファイルを保存すると、上記の操作のパフォーマンス、または一般的なシステムパフォーマンスに、ファイルを格納するサブフォルダのツリーを作成する場合とは異なる影響がありますか?
サブフォルダのツリーには、上記のパフォーマンス上の欠点はありません。さらに、基盤となるファイルシステムがハッシュされたファイル名を持たないように変更された場合でも、ツリー手法は引き続き適切に機能します。