Linux クライアントから大きなディレクトリにアクセスする際のファイル共有のパフォーマンスを最適化する
この記事では、多数のファイルを含むディレクトリの操作に関する推奨事項を示します。 通常は、ファイルを複数のディレクトリに分散させて、1 つのディレクトリ内のファイルの数を減らすのが良い方法です。 ただし、状況によっては大きなディレクトリを回避できないことがあります。 Linux クライアントにマウントされている Azure ファイル共有で大きなディレクトリを操作する場合は、次の推奨事項を検討してください。
適用対象
ファイル共有の種類 | SMB | NFS |
---|---|---|
Standard ファイル共有 (GPv2)、LRS/ZRS |
![]() |
![]() |
Standard ファイル共有 (GPv2)、GRS/GZRS |
![]() |
![]() |
Premium ファイル共有 (FileStorage)、LRS/ZRS |
![]() |
![]() |
推奨されるマウント オプション
次のマウント オプションは列挙に固有のものであり、大きなディレクトリを操作するときの待ち時間を短縮できます。
actimeo
actimeo
を指定すると、acregmin
、acregmax
、acdirmin
、acdirmax
のせべてに同じ値が設定されます。
actimeo
を指定していない場合、クライアントではこれらの各オプションで既定値が使用されます。
大きなディレクトリを操作するときは、actimeo
を 30 から 60 秒に設定することをお勧めします。 この範囲の値を設定すると、属性はクライアントの属性キャッシュ内で長時間有効なままになり、ネットワーク経由でフェッチするのではなく、キャッシュからファイルの属性を取得する操作を使用できます。 これにより、操作がまだ実行されている間にキャッシュされた属性の有効期限が切れる状況での待ち時間を短縮できます。
次のグラフは、1 つのディレクトリに 100 万個のファイルがあるワークロードについて、既定のマウントと actimeo
の値を 30 に設定した場合とで、さまざまな操作の完了までにかかる合計時間を比べたものです。 このテストでは、一部の操作で完了までの合計時間が最大 77% 短縮されました。 すべての操作は、別名ではない ls で行われました。
nconnect
Nconnect
は、NFS ファイル共有用のクライアント側のマウント オプションであり、クライアントと NFSv4.1 用 Azure Premium Files サービスの間で、複数の TCP 接続を使用できます。 待ち時間を短縮し、パフォーマンスを向上させるための最適な設定である nconnect=4
をお勧めします。
Nconnect
は、複数のスレッドからの非同期または同期 I/O を使用するワークロードに特に役立ちます。
詳細情報。
ハッシュ バケットの数を増やす
列挙を行うシステムに存在する RAM の総量は、NFS や SMB など、ファイルシステム プロトコルの内部動作に影響を与えます。 ユーザーのメモリ使用量が多くない場合でも、利用できるメモリの量はシステムの inode ハッシュ バケットの数に影響を与え、それによって大きなディレクトリの列挙のパフォーマンスが影響を受けたり改善したりします。 システムの inode ハッシュ バケットの数を変更して、大きな列挙ワークロードの間に発生する可能性のあるハッシュ競合を減らすことができます。
これを行うには、ブート中に有効になって inode ハッシュ バケットの数を増やすカーネル コマンドを追加指定して、ブート構成の設定を変更する必要があります。 以下の手順に従ってください。
テキスト エディタで、
/etc/default/grub
ファイルを編集します。sudo vim /etc/default/grub
/etc/default/grub
ファイルに次のテキストを追加します。 このコマンドは、inode ハッシュ テーブル サイズとして 128 MB を別に設定し、システム メモリの消費量を最大 128 MB 増やします。GRUB_CMDLINE_LINUX="ihash_entries=16777216"
GRUB_CMDLINE_LINUX
がすでに存在する場合は、次のようにスペースで区切ってihash_entries=16777216
を追加します。GRUB_CMDLINE_LINUX="<previous commands> ihash_entries=16777216"
変更を適用するには、以下を実行します。
sudo update-grub2
システムを再起動します。
sudo reboot
変更が有効になっていることを確認するには、システムが再起動してから、カーネル コマンドライン コマンドを確認します。
cat /proc/cmdline
ihash_entries
が表示される場合、システムによって設定が適用されていて、列挙のパフォーマンスが指数関数的に向上するはずです。dmesg 出力を確認して、カーネル コマンドラインが適用されたかどうかを確認することもできます。
dmesg | grep "Inode-cache hash table" Inode-cache hash table entries: 16777216 (order: 15, 134217728 bytes, linear)
コマンドと操作
コマンドと操作を指定する方法も、パフォーマンスに影響する可能性があります。
ls
コマンドを使って大きなディレクトリ内のすべてのファイルを一覧表示する場合がよい例です。
Note
再帰的な ls
、find
、du
などの一部の操作では、ファイル名とファイル属性の両方が必要であるため、(エントリを取得するための) ディレクトリの列挙と (属性を取得するための) 各エントリに対する stat が組み合わされます。 このようなコマンドを実行する可能性が高いマウント ポイントでは、actimeo に高い値を使うことをお勧めします。
別名ではない ls を使用する
一部の Linux ディストリビューションでは、シェルによって ls
コマンドに ls --color=auto
などの既定のオプションが自動的に設定されます。 これにより、ネットワーク上での ls
の動作が変更され、ls
の実行に追加される操作が増えます。 パフォーマンスの低下を避けるため、別名ではない ls を使うことをお勧めします。 次の 3 つの方法のいずれかでこれを行うことができます。
unalias ls
コマンドを使って別名を削除します。 これは、現在のセッションに対する一時的な解決策にすぎません。永続的に変更するには、ユーザーの
bashrc/bash_aliases
ファイルでls
の別名を編集できます。 Ubuntu では、~/.bashrc
を編集して、ls
の別名を削除します。ls
を呼び出す代わりに、ls
のバイナリを直接呼び出すことができます (例:/usr/bin/ls
)。 これにより、別名に含まれる可能性のあるオプションを使わずに、ls
を使用できます。 バイナリの場所は、which ls
コマンドを実行して調べることができます。
ls が出力を並べ替えないようにする
ls
を他のコマンドと共に使う場合、ls
からファイルが返される順序が重要でないときは、ls
による出力の並べ替えを無効にして、パフォーマンスを向上させることができます。 出力を並べ替えると、オーバーヘッドが大幅に増加します。
ls -l | wc -l
を実行してファイルの合計数を取得する代わりに、ls
で -f
または -U
オプションを使うと、出力の並べ替えが行われません。 違いは、-f
では非表示ファイルも表示され、-U
では表示されないということです。
たとえば、Ubuntu で ls
のバイナリを直接呼び出す場合は、/usr/bin/ls -1f | wc -l
または /usr/bin/ls -1U | wc -l
を実行します。
次のグラフは、別名ではなく並べ替えを行わない ls
と、並べ替えを行う ls
で、結果の出力にかかる時間を比較したものです。
ファイルのコピーとバックアップの操作
ファイル共有から別の場所にデータをコピーまたはバックアップする場合は、パフォーマンスを最適化するため、アクティブな I/O があるライブ ファイル共有ではなく、共有スナップショットをソースとして使用することをお勧めします。 バックアップ アプリケーションでは、スナップショットに対してコマンドを直接実行する必要があります。 詳細については、「Azure Files で共有スナップショットを使用する」を参照してください。
アプリケーション レベルでの推奨事項
大きなディレクトリを使用するアプリケーションを開発する際は、次の推奨事項に従ってください。
ファイル属性をスキップします。 ファイル名のみが必要で、ファイルの種類や最終変更時刻などのファイル属性が必要ないアプリケーションの場合は、
getdents64
などのシステム呼び出しを、適切なバッファー サイズを使って複数回呼び出すことができます。 このようにすると、指定したディレクトリ内のファイルの種類を含まないエントリが取得され、必要のない余計な操作を行わずに済むので、操作が高速になります。stat 呼び出しをインターリーブします。 アプリケーションで属性とファイル名が必要な場合は、
getdents64
でファイルの終わりまですべてのエントリを取得した後、返されたすべてのエントリに対して statx を実行するのではなく、stat の呼び出しとgetdents64
をインターリーブすることをお勧めします。 stat の呼び出しをインターリーブすると、クライアントはファイルとその属性の両方を一度に要求するよう指示され、サーバーへの呼び出しの数が減ります。 高いactimeo
の値と組み合わせると、パフォーマンスが大幅に向上します。 たとえば、[ getdents64, getdents64, ... , getdents64, statx (entry1), ... , statx(n) ]
の代わりに、[ getdents64, (statx, statx, ... , statx), getdents64, (statx, statx, ... , statx), ... ]
のように、各getdents64
の後に statx の呼び出しを配置します:。I/O の深さを増やします。 可能であれば、
nconnect
を 0 以外の値 (1 より大きい値) に構成して複数のスレッドに操作を分散させるか、非同期 I/O を使うことをお勧めします。 これにより、操作を非同期に行うことができ、ファイル共有への複数のコンカレント接続からの利点が得られます。キャッシュを強制的に使います。 1 つのクライアントのみがマウントしているファイル共有でファイル属性のクエリを実行するアプリケーションの場合は、
AT_STATX_DONT_SYNC
フラグを指定して statx システム呼び出しを使います。 このフラグを使うと、キャッシュされた属性がキャッシュから取得され、サーバーと同期されないので、最新のデータを取得するための余分なネットワーク ラウンド トリップがなくなります。