ユーザープロフィール画像を保存するWebサイトがあります。各画像は、ユーザー固有のディレクトリ(Linux)に保存されます。現在、30以上の顧客ベースがあります。つまり、30以上のフォルダーがあります。しかし、私の現在のLinuxボックス(ext2/ext3)は、32000を超えるディレクトリの作成をサポートしていません。どうすればこれを乗り越えられますか? YouTubeの男性でさえ、ビデオのサムネイルに関して同じ問題を抱えています。しかし、彼らはReiserFSに移行することでそれを解決しました。より良い解決策はありませんか?
更新:IRCで尋ねられたとき、人々はそれをext4にアップグレードすることを求めていました。これには64kの制限があり、もちろん それを超えることもできます です。またはカーネルハッキングで制限を変更します。
更新:ユーザーベースをユーザーIDの範囲に基づいてフォルダーに分割する方法は? 1つのフォルダで1-1000、他のフォルダで1000-2000を意味します。これは簡単なようです。皆さん、どう思いますか?
正直なところ、他に方法はありませんか?
この制限は、ファイルシステム全体ではなく、ディレクトリごとのものなので、さらに細かく分割することで回避できます。たとえば、同じディレクトリ内のすべてのユーザーサブディレクトリを名前の最初の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 forインスタンス)は、この非効率性(バイナリ分割アルゴリズムを使用してディレクトリを検索するため、長いディレクトリがはるかに効率的に処理され、ext4でも実行できる)と、ディレクトリごとの固定制限が削除されます。
あなたがext2/ext3にバインドされている場合、私が見る唯一の可能性はあなたのデータを分割することです。データを同様のサイズの扱いやすいチャンクに分割する基準を見つけます。
それが私がやろうとしているプロフィール画像だけの場合:
たとえば、SQUIDキャッシュは次のように実行します。
f/4b/353ac7303854033
トップレベルのディレクトリは最初の16進数で、第2レベルは次の2つの16進数で、ファイル名は残りの16進数です。
私たちはより良い解決策を持っていることはできませんか?
あなたはより良い解決策を持っています-別のファイルシステムを使用してください、たくさんのものが利用可能であり、その多くは異なるタスクのために最適化されています。ご指摘のとおり、ReiserFSはディレクトリ内の多数のファイルを処理するために最適化されています。
ここを参照 ファイルシステムの比較。
ディレクトリ内の多数のファイルに対して本当にひどいNTFSに悩まされていないことをうれしく思います。比較的新しい(しかし明らかに安定している)ext4 FSを使いたくない場合は、代わりにJFSをお勧めします。
私は小さなWebギャラリーを一緒にハッキングしましたが、そこでこの問題のバリエーションができました。私はキャッシュディレクトリに約30.000のイメージしか「持っていない」ので、かなり遅いことがわかりました(ext2は、覚えているように、ディレクトリインデックスにリンクリストを使用しています)。
私はこれらの線に沿って何かをすることになりました:
def key2path(key):
hash = md5(key)
return os.path.join(hash[0], hash[1], key)
これにより、256のディレクトリにデータが分割され、3つのレベルそれぞれの高速なディレクトリ検索が可能になります。
プロフィール画像は小さいですか?それを残りのプロファイルデータと一緒にデータベースに入れるのはどうですか?これはあなたにとって最良のオプションではないかもしれませんが、検討する価値があります...
これはトピックに関する(古い)Microsoftホワイトペーパーです: To BLOB or not not BLOB 。
一般に、多数のファイル/ディレクトリが含まれるディレクトリを作成しないようにします。主な理由は、コマンドラインでワイルドカードを展開すると、「引数が多すぎます」というエラーが発生し、これらのディレクトリを操作しようとすると非常に苦痛になるためです。
より深く、より狭いツリーを作成するソリューションを探してください。他の人が説明したようにサブフォルダを作成することによって。
私たちにも同様の問題がありました。解決策は、前述のように、ディレクトリの階層を作成することです。
もちろん、フラットなディレクトリ構造に依存する複雑なアプリケーションがある場合、おそらく多くのパッチが必要になります。したがって、回避策があることを知っておくのは良いことです。前述の32kの制限がないシンボリックリンクを使用してください。次に、アプリを修正する時間があります...
親フォルダーに含める(または含めることができる)サブディレクトリーの最大数を決定することをお勧めします。
次に、ユーザーIDを1から開始するように変換する必要があります。
その後、次のことができます:modulo = currentId % numberOfSubdirectories
modulo
には、選択したnumberOfSubdirectories
より大きくなることのないサブディレクトリ番号が含まれるようになります。
たとえば、moduloを使って好きなことをして、ハッシュします。
また、この方法では、サブディレクトリが線形で埋められます。
あなたの問題に対する即座の答えではありませんが、将来の参照を監視するために、OpenBSDにリンクされたプロジェクト 'Epitome' があります
Epitomeは、シングルインスタンスストレージ、連想記憶、および重複排除サービスを提供するエンジンです。
すべてのデータは、ハッシュされたブロックとしてデータストアに格納され、一意ではないブロックを削除してスペースの使用量を削減します。また、UUIDによってデータストアにコンテンツを要求するだけでよいので、本質的にストレージメカニズムを忘れることができます。
エピトメは現在実験段階ですが、将来を見据えたものです。
タイムスタンプアプローチを使用せずに、オーバーフローオプションを用意してください。
タイムスタンプが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(文字を使用している場合)。
これは、多数のディレクトリになりますが、ファイルリビジョンの処理には非常に役立ちます。たとえば、ユーザーが新しいプロフィール写真を使用したい場合でも、変更を元に戻したい場合に備えて、古いタイムスタンプ付きの古いバージョンの古いバージョンがまだ残っています(上書きされるだけではありません)。