Linuxサブディレクトリ数の制限を解決するにはどうすればよいですか?


9

ユーザープロフィール画像を保存するWebサイトがあります。各画像は、ユーザー固有のディレクトリ(Linux)に保存されます。現在、30以上の顧客ベースがあります。つまり、30以上のフォルダーがあります。しかし、私の現在のLinuxボックス(ext2 / ext3)は、32000を超えるディレクトリの作成をサポートしていません。どうすればこれを乗り越えられますか?YouTubeの男性でさえ、ビデオのサムネイルに関して同じ問題を抱えています。しかし、彼らはReiserFSに移行することでそれを解決しました。より良い解決策はありませんか?

更新:IRCで尋ねられたとき、人々はそれをext4にアップグレードすることを求めていました。これには64kの制限があり、もちろんそれを乗り越えることもできます。または、カーネルハッキングで制限を変更します。

更新:ユーザーベースをユーザーIDの範囲に基づいてフォルダに分割するのはどうですか。1つのフォルダで1-1000、他のフォルダで1000-2000を意味します。これは簡単なようです。みんな何て言うの?

正直なところ、他に方法はありませんか?


1
ファイルシステムを変更したくないのですか?これがext2 / 3の制限である場合、ファイルシステムを変更するか、現在のFSをより小さなFS(より多くの異なるマウントポイント)に分割する以外に変更はありません。
Manuel Faux、

1
マニュエル:ファイルシステムを変更する場合、彼は特定のFSをアプリケーションに結び付けています。それが結局は答えになるかもしれませんが、これはおそらくアプリケーションレベルで解決する必要がある問題でしょう。カーネルやファイルシステムをハックする必要がある場合は、特別な要件がない限り、おそらく間違ったパスをたどることになります。
カイル・ブラント

回答:


16

この制限は、ファイルシステム全体ではなく、ディレクトリごとのものなので、さらに細かく分割することで回避できます。たとえば、同じディレクトリ内のすべてのユーザーサブディレクトリを名前の最初の2文字ごとに分割するのではなく、次のようにします。

top_level_dir
|---aa
|   |---aardvark1
|   |---aardvark2
|---da
|   |---dan
|   |---david
|---do
    |---don

名前のハッシュの何らかの形式を作成し、それを分割に使用するのがさらに良いでしょう。このようにすると、最初の文字の例である「da」が非常にいっぱいになり、「zz」が完全に空になる代わりに、ディレクトリ間でより適切に分散されます。たとえば、CRCまたはMD5の名前を取得し、最初の8ビットを使用すると、次のようになります。

top_level_dir
|---00
|   |---some_username
|   |---some_username
|---01
|   |---some_username
...
|---FF
|   |---some_username

これは、たとえばハッシュ値ではなくユーザー名を使用する場合など、必要に応じてさらに深く拡張できます。

top_level_dir
|---a
|   |---a
|       |---aardvark1
|       |---aardvark2
|---d
    |---a
    |   |---dan
    |   |---david
    |---o
        |---don

このメソッドは、Ludwigの例やWebブラウザーのローカルキャッシュをコピーするために、Squidのキャッシュなどの多くの場所で使用されます。

注意すべき重要な点の1つは、ext2 / 3を使用すると、ディレクトリが直線的に検索されるため、いずれにしても32,000の制限に近づく前にパフォーマンスの問題に直面し始めることです。別のファイルシステム(ext4またはreiserなど)に移動すると、この非効率性(reiserがバイナリ分割アルゴリズムを使用してディレクトリを検索するため、長いディレクトリがより効率的に処理されるため、ext4も可能です)と、ディレクトリごとの固定制限がなくなります。


これを含むように質問の説明を更新しました:「更新:ユーザーIDの範囲に基づいてユーザーベースをフォルダーに分割する方法について。あなたは言うのですか?」
なし。

1
ユーザーがユーザー名の代わりに(またはユーザー名だけでなく)ユーザーIDで識別される場合、これはうまく機能し、ハッシュよりも効率的です。ただし、システム内の他の場所で常に名前でそれらを参照する場合は、場所全体に追加のname-> idルックアップを追加する必要があります。
David Spillett、2009

デービッド、ありがとう!別の解決策も試しました。1〜30000、30000〜60000などの範囲で4つのフォルダーをほとんど作成しませんでした。このような大きなディレクトリからファイルを取得すると、1000個のファイルがあるディレクトリよりも時間がかかると思います(以前のアプローチ)。あなたは何を言っていますか?
なし。

1
それはファイルシステムに依存します。ext2またはext3を使用している場合は、ディレクトリごとに30,000よりはるかに小さい値をお勧めします。一部のツールは約10,000の警告を発行します。ext3 / 4でディレクトリインデックスをオンにすると、次のようになります。tune2fs -O dir_index / dev / <volumename>ただし、ディレクトリ内のオブジェクトの数を少なくする(数千以下か)ことをお勧めします。 。
David Spillett、2009

@マディ、Ext2 / 3が多数のファイルを処理する方法に関する他の制限のため、このソリューションが必要です。詳細については、serverfault.com / questions / 43133 /…を参照してください。名前をbuckets-as-subdirectoriesに分割すると、最終的に遭遇する他の問題が軽減されます。これは、オブジェクトキャッシュを初めてセットアップするときにSquidが使用するのと同じ戦略であることに注意してください。
エイブリーペイン

7

あなたがext2 / ext3にバインドされている場合、私が見る唯一の可能性はあなたのデータを分割することです。データを同様のサイズの扱いやすいチャンクに分割する基準を見つけます。

それが私がやろうとしているプロフィール画像だけの場合:

  1. 画像のハッシュ(SHA1など)を使用します
  2. SHA1をファイルおよびディレクトリ名として使用します

たとえば、SQUIDキャッシュは次のように実行します。

f / 4b / 353ac7303854033

トップレベルのディレクトリは最初の16進数で、第2レベルは次の2つの16進数で、ファイル名は残りの16進数です。


2

私たちはより良い解決策を持っていることはできませんか?

あなたはより良い解決策を持っています-別のファイルシステムを使用してください、たくさんのものが利用可能で、それらの多くは異なるタスクのために最適化されています。ご指摘のとおり、ReiserFSはディレクトリ内の多数のファイルを処理するために最適化されています。

ファイルシステムの比較については、こちらご覧ください

ディレクトリ内の多くのファイルに対して本当にひどいNTFSに悩まされていないことをうれしく思います。比較的新しい(しかし明らかに安定している)ext4 FSを使いたくない場合は、代わりにJFSをお勧めします。


NTFSファイルシステムのパフォーマンスに適切なリンクがありますか?
するThorbjörnRavnアンデルセン

はい、アプリでの個人的な経験とは別に、ディレクトリに新しいファイルを作成するのに時間がかかりすぎました(それらをすべて削除するには何時間もかかりました)。また、ディレクトリ内のファイルの数を1000に制限することで、Subversionのパフォーマンスが向上しました。または、 :support.microsoft.com/kb/130694まだperfと記載されているため、これを「修正」したとは思わない。NTFSの微調整。
gbjbaanb 2009

1

プロフィール画像は小さいですか?残りのプロファイルデータと共にデータベースに配置するのはどうですか?これはあなたにとって最良の選択肢ではないかもしれませんが、検討する価値があります...

これはトピックに関する(古い)Microsoftホワイトペーパーです:To BLOB or not not to BLOB


1

私は小さなWebギャラリーをハッキングしましたが、そこでこの問題のバリエーションができました。私はキャッシュディレクトリに約30.000のイメージしか「持っていない」ので、かなり遅いことがわかりました(ext2は、覚えているように、ディレクトリインデックスにリンクリストを使用しています)。

私はこれらの線に沿って何かをすることになりました:

def key2path(key):
    hash = md5(key)
    return os.path.join(hash[0], hash[1], key)

これにより、256のディレクトリにデータが分割され、3つのレベルそれぞれの高速なディレクトリ検索が可能になります。

  • SHA-1ではなくMD5を使用することを選択しました。32ビットの12ビットを変更するとMD5が異なる出力を保証するため、ユーザー名、ディレクトリ、その他の短いものをハッシュするのに適しています。そして、それも速いです...
  • ハッシュ全体を含めないでください。ディレクトリが多すぎて、ディスクキャッシュが効果的に何度も破棄されるためです。

1
ハッシュはMD5やSHAのように暗号的に強力である必要はないので、おそらくCRCのようなより単純なハッシュを使用できますが、パフォーマンスの違いはおそらく無視できます...
sleske

0

あなたの問題に対する即座の答えではありませんが、将来の参照に注意する必要があるのは、「Epitome」と呼ばれるOpenBSDリンクプロジェクトです。

Epitomeは、シングルインスタンスストレージ、コンテンツアドレス指定可能なストレージ、重複排除サービスを提供するエンジンです。

すべてのデータは、ハッシュされたブロックとしてデータストアに格納され、一意ではないブロックを削除してスペースの使用量を削減します。また、UUIDによってデータストアにコンテンツを要求するだけでよいため、本質的にストレージメカニズムを忘れることができます。

エピトメは現在実験段階ですが、将来に注意する必要があります。


0

一般的には、多数のファイル/ディレクトリが含まれるディレクトリを作成しないようにします。主な理由は、コマンドラインでワイルドカードを展開すると、「引数が多すぎます」というエラーが発生し、これらのディレクトリを操作しようとすると非常に苦痛になるためです。

たとえば、他の人が説明しているようにサブフォルダを作成するなどして、ツリーをより深くしかしより狭くするソリューションを探します。


0

私たちにも同様の問題がありました。解決策は、前述のように、ディレクトリの階層を作成することです。

もちろん、フラットなディレクトリ構造に依存する複雑なアプリケーションがある場合、おそらく多くのパッチが必要になります。したがって、回避策があることを知っておくのは良いことです。前述の32kの制限がないシンボリックリンクを使用してください。次に、アプリを修正するための十分な時間があります...


0

タイムスタンプアプローチを使用せずに、オーバーフローオプションを用意してください。

例えば

タイムスタンプが1366587600であるとします。

最後の2桁を省略します(または、少しばかげてしまいます)。スタンプを4つのセットに分割します(ディレクトリの数が9999を超えてはなりません-別の方法で分割することもできます)。

これにより、次のようなものが残ります。

/files/1366/5876/

次に、アップロードする前にディレクトリ内の量も確認します。アップロードの数が多い場合(つまり、100秒あたり32000 +)、2番目または文字でディレクトリを反復処理します。次に例を示します。

/files/1366/5876/a/file.txt

または

/files/1366/5876/00/file.txt

次に、タイムスタンプ+文字またはフルパスコードをユーザーと一緒にdbに記録します。

パススタンプ:1366587600または13665876a(文字を使用している場合)。

これは、多数のディレクトリを作成することになりますが、ファイルリビジョンの処理に非常に役立ちます。たとえば、ユーザーが新しいプロフィール写真を使用したい場合でも、変更を元に戻したい場合に備えて、古いタイムスタンプ付きの古いバージョンのバージョンがまだ残っています(上書きされるだけではありません)。


0

親フォルダに含める(または含めることができる)サブディレクトリの最大数を決定することをお勧めします。

次に、ユーザーIDを1から開始するように変換する必要があります。

その後、次のことができます。 modulo = currentId % numberOfSubdirectories

modulonumberOfSubdirectoriesこれで、選択した数より大きくなることのないサブディレクトリ番号が含まれます。

モジュロで好きなことをしてください、例えばそれをハッシュしてください。

また、この方法では、サブディレクトリが線形​​で埋められます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.