14

Ubuntu Linux 14.04 で動作するアプリケーションで効率的かつ高性能な非同期 IO を動作させる方法についてのアドバイスを探しています。

私のアプリはトランザクションを処理し、ディスク/フラッシュにファイルを作成します。アプリがトランザクションを進行するにつれて、追加のブロックが作成され、ディスク/フラッシュ上のファイルに追加する必要があります。アプリは、新しいトランザクションを処理しているため、このファイルのブロックを頻繁に読み取る必要もあります。各トランザクションは、このファイルに追加する必要がある新しいブロックを作成するだけでなく、このファイルから別のブロックを読み取る必要がある場合があります。トランザクションの着信キューがあり、アプリはキューからトランザクションを処理し続けて、ディスクまたはフラッシュでの読み取りアクセスまたは書き込み完了のレイテンシを隠すのに十分な深さの IO ops パイプラインを作成できます。ディスク/フラッシュにまだ書き込まれていないブロック (前のトランザクションによって書き込みキューに入れられたブロック) の読み取りの場合、アプリは対応する書き込みが完了するまで停止します。

私には重要なパフォーマンス目標があります。アプリが IO 操作を発行するために発生する遅延を可能な限り最小限に抑える必要があります。私のアプリは、各トランザクションを処理し、ディスク/フラッシュ上のファイルへの書き込みまたはファイルからの読み取りを発行する準備が整うまでに約 10 マイクロ秒かかります。ファイルの書き込みのみが必要な場合に、アプリが各トランザクションの処理をトランザクションあたり 10 マイクロ秒にできるだけ近い速度で完了することができるように、非同期の読み取りまたは書き込みを発行するための追加の待機時間はできるだけ小さくする必要があります。

io_submit を使用して書き込みおよび読み取り要求を発行する実装を実験しています。私たちの要件に対する最善のアプローチについて、提案やフィードバックをいただければ幸いです。io_submit は、目的を達成するための最高のパフォーマンスを提供してくれるでしょうか? 各書き込み io_submit のレイテンシーと各読み取り io_submit のレイテンシーはどの程度になると予想されますか?

実験的なコード (2.3 GHz Haswell Macbook Pro、Ubuntu Linux 14.04 で実行) を使用して、出力ファイルを拡張するときの書き込み io_submit で約 50 usecs を測定しています。これは長すぎて、パフォーマンス要件に近づいていません。最小限のレイテンシーで書き込みリクエストを開始するのに役立つガイダンスがあれば、大歓迎です。

4

2 に答える 2

12

ここでは、提案された Boost.AFIOの作成者として話します。

まず、Linux KAIO (io_submit) は、O_DIRECT がオンになっていてエクステントの割り当てが不要でない限り、ほぼ常にブロックされます。O_DIRECT がオンの場合は、4Kb に揃えられた境界で 4Kb の倍数を読み書きする必要があります。そうでない場合は、デバイスに強制的に読み取りを実行させます。 -変更-書き込み。したがって、アプリケーションを O_DIRECT および 4Kb でアラインされた I/O フレンドリーに再構築しない限り、Linux KAIO を使用しても何も得られません。

次に、書き込み中に出力ファイルを拡張しないでください。エクステントの割り当てと、場合によってはメタデータのフラッシュを強制します。代わりに、ファイルの最大エクステントを適切な大きな値に割り当て、ファイルの終わりの内部アトミック カウンターを保持します。これにより、ext4 ではバッチ処理されて遅延が発生するエクステント割り当てだけに問題が軽減されます。さらに重要なのは、メタデータのフラッシュを強制しないことです。これは、ext4 の KAIO がほとんどの場合非同期になることを意味するはずですが、ジャーナルへの遅延割り当てをフラッシュするため、予期せず同期します。

第三に、私がおそらくあなたの問題にアプローチする方法は、O_DIRECT も O_SYNC も使用せずにアトミック追加 (O_APPEND) を使用することです。そのため、カーネルのページ キャッシュ内の増え続けるファイルに更新を追加します。これは非常に高速で同時実行安全です。その後、ときどき、ログ ファイル内のどのデータが古く、そのエクステントを fallocate(FALLOC_FL_PUNCH_HOLE) を使用して解放できるかをガベージ コレクションして、物理ストレージが永久に大きくならないようにします。これにより、ストレージへの書き込みを合体させる問題が、これを高速化するために多大な労力が費やされたカーネルに押し付けられます。これは、常に順方向の書き込みであるため、書き込みが書き込まれた順序にかなり近い順序で物理ストレージにヒットすることがわかります。電力損失の回復を簡単にします。

上記のすべてが多くの作業のように思われる場合、OS は、メモリ マップとしてよく知られている高度に調整された実装にまとめられた 3 つの手法をすべて提供しています。非同期入出力。64 ビット システムでは、単純にファイルを非常に大量にフォールロケートし、メモリにマップします。必要に応じて読み書きしてください。I/O パターンがカーネル ページ アルゴリズムを混乱させる可能性がある場合は、より良い動作を促進するために、あちこちで madvise() のタッチが必要になる場合があります。madvise() を使用すると、少ないほど多くなります。信頼してください。

非常に多くの人が、mmap が既に必要なすべての機能を備えていることに気付かずに、さまざまな O_DIRECT アルゴリズムを使用して mmap を複製しようとしています。Linux が動作しない場合は、はるかに予測可能なファイル I/O モデルを持つ FreeBSD を試してから、独自の I/O ソリューションを展開する領域を掘り下げることをお勧めします。これらを一日中行う人として言えば、ファイリングシステムは風変わりで奇妙な振る舞いの悪魔の穴です。終わりのないデバッグは他の人に任せましょう。

于 2016-01-03T16:56:09.317 に答える