インタビューの質問:Linuxのゼロコピー技術を理解する方法は?

この記事では、Linuxのゼロコピー技術について説明します。クラウドコンピューティングは、多くの技術を統合する巨大な技術テーマです。Linuxは比較的基本的な技術です。したがって、Linuxをよく学ぶことは、クラウドコンピューティングの研究に大いに役立ちます。この記事では、Linuxでのいくつかの一般的なゼロコピーテクノロジーを利用して要約します。

ゼロコピーが必要な理由

従来のLinuxシステムの標準I / Oインターフェイス(読み取り、書き込み)は、データコピーに基づいています。つまり、データはcopy_to_userまたはcopy_from_userです。これの利点は、中間キャッシュメカニズムによってディスクI / O操作が削減されることです。不利な点も明らかです。大量のデータをコピーし、ユーザーモードとカーネルモードを頻繁に切り替えると、多くのCPUリソースが消費され、データ送信のパフォーマンスに深刻な影響を及ぼします。データによると、Linuxカーネルプロトコルスタックでは、コピーには時間がかかりますデータパケットの処理フロー全体の57.1%を占めています。

ゼロコピーとは

ゼロコピーはこの問題の解決策であり、コピー操作を可能な限り回避することでCPUへの負荷を軽減します。Linuxでの一般的なゼロコピーテクノロジーは、2つのカテゴリに分類できます。1つは特定のシナリオで不要なコピーを削除すること、もう1つはコピープロセス全体を最適化することです。この観点から、ゼロコピーは実際には「0」コピーを達成しません。それはより多くのアイデアであり、多くのゼロコピーテクノロジーはこのアイデアに基づいて最適化されています。

 

ゼロコピーのいくつかの方法

元のデータのコピー操作

紹介する前に、Linuxの元のデータコピー操作を見てみましょう。次の図に示すように、アプリケーションがディスクファイルからコンテンツを読み取り、ネットワーク経由で送信する必要がある場合は、次のようになります。

while((n = read(diskfd, buf, BUF_SIZE)) > 0)
write(sockfd, buf , n);

次に、プロセス全体を実行する必要があります。

  • 1)読み取りは、DMAおよびその他の方法を介してディスクファイルからカーネルによって開かれたバッファにデータをコピーします。
  • 2)データがカーネルバッファからユーザーモードバッファにコピーされます。
  • 3)書き込みコピーデータをユーザーモードバッファからカーネルプロトコルスタックによって開かれたソケットバッファに書き込みます。
  • 4)データはDMAを介してソケットバッファからネットワークカードにコピーされ、送信されます。

プロセス全体で少なくとも4つのデータコピーが発生し、そのうち2つはDMAとハードウェア通信によって完了し、CPUは直接参加していなかったことがわかります。これらの2回を削除しても、CPUデータコピー操作は2回残っています。 。

方法1:ユーザーモードでのダイレクトI / O

この方法では、ユーザーモードで実行されているアプリケーションまたはライブラリ関数がハードウェアデバイスに直接アクセスでき、データはカーネルを介して直接送信されます。カーネルは、データ送信プロセス全体で必要な仮想ストレージ構成作業以外には参加しません。方法はカーネルを直接バイパスでき、パフォーマンスを大幅に向上させます。

欠陥:

  • 1)この方法は、カーネルバッファ処理を必要としないアプリケーションにのみ適用できます。これらのアプリケーションは通常、データベース管理システムなどのセルフキャッシュアプ​​リケーションと呼ばれる独自のデータキャッシュメカニズムをプロセスアドレス空間に持っています。
  • 2)この方法はディスクI / Oを直接操作します。CPUとディスクI / Oの実行時間のギャップにより、リソースが浪費されます。この問題を解決するには、非同期I / Oと組み合わせる必要があります。

方法2:mmap

この方法では、読み取りの代わりにmmapを使用すると、次のように1つのコピー操作を減らすことができます。

buf = mmap(diskfd, len);
write(sockfd, buf, len);

アプリケーションプログラムはmmapを呼び出し、ディスクファイル内のデータはDMAを介してカーネルバッファにコピーされます。その後、オペレーティングシステムはこのバッファをアプリケーションプログラムと共有するため、ユーザースペースにコピーする必要はありません。アプリケーションはwriteを呼び出し、オペレーティングシステムはデータをカーネルバッファからソケットバッファに直接コピーし、最後にDMAを介してネットワークカードにコピーして送信します。

640?wx_fmt = png&tp = webp&wxfrom = 5&wx_lazy = 1&wx_co = 1upload.4e448015.gifアップロード中...再アップロードがキャンセルされました


欠陥:

  • 1)mmapはトラップを非表示にします。ファイルをmmapするときに、ファイルが別のプロセスによってインターセプトされた場合、不正なアドレスへのアクセスにより、書き込みシステムコールはSIGBUSシグナルによって終了します。SIGBUSはデフォルトでプロセスを強制終了し、コアダンプ。サーバーはこの方法で終了します。損失は小さくない場合があります。

この問題を解決するには、通常、ファイルリースロックが使用されます。最初にファイルのリースロックを申請します。他のプロセスがファイルを切り捨てる場合、カーネルはリアルタイムのRT_SIGNAL_LEASEシグナルを送信して、現在のプロセスにプロセスを通知します。はファイルを破棄しようとしているので、書き込みSIGBUSによって強制終了される前に、ファイルは中断され、書き込まれたバイト数を返し、errnoを成功に設定します。

通常は、mmapの前にロックし、操作後にロックを解除します。

方法3:sendfile

Linux 2.1カーネルから、Linuxはsendfileを導入しました。これにより、コピーを1つ減らすこともできます。

#include<sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

sendfileは、カーネルモードでのみ発生し、ユーザーモードに参加しないデータ転送インターフェイスであり、ユーザーモードのデータコピーを自然に回避します。in_fdとout_fdの間のデータ転送を指定します。その中で、in_fdが指すファイルはmmap可能である必要があり、out_fdはソケットを指す必要があることを指定します。つまり、データはファイルからソケットにのみ転送できます。逆もまた同様です。Sendfileには、mmap中にファイルが傍受されるという状況はなく、独自の例外処理メカニズムがあります。

欠陥:

  • 1)ユーザーモード処理を必要としないアプリケーションにのみ適用できます。

方法4:DMA支援sendfile

通常のsendfileにもカーネルモードのコピー操作がありますが、このコピーも削除できますか?

答えは、このDMA支援のsendfileです。

ハードウェアの助けを借りて、このメソッドはカーネルバッファーからソケットバッファーにデータをコピーしませんが、バッファー記述子をコピーします。完了後、DMAエンジンはカーネルバッファーからデータを直接コピーします。プロトコルエンジンに移動して、最後のコピー。

欠陥:

  • 1)3.4の欠陥に加えて、ハードウェアとドライバーのサポートも必要です。
  • 2)ファイルからソケットへのデータのコピーにのみ適用されます。

方法5:スプライス

Spliceは、sendfileの使用範囲の制限を取り除き、任意の2つのファイル記述子間でデータを転送するために使用できます。

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <fcntl.h>
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);

ただし、スプライスにも制限があります。Linuxパイプバッファメカニズムを使用するため、2つのファイル記述子パラメータの少なくとも1つはパイプデバイスである必要があります。

スプライスは、事前定義されたウォーターマークを介して書き込み要求をブロックするフロー制御メカニズムを提供します。実験によると、この方法を使用して1つのディスクから別のディスクにデータを転送すると、スループットが30%〜70%向上します。CPUの責任も半分になります。 。

欠陥:

  • 1)同じことがユーザーモード処理を必要としないプログラムにのみ適用されます
  • 2)送信記述子の少なくとも1つはパイプデバイスです。

方法6:コピーオンライト

場合によっては、カーネルバッファが複数のプロセスで共有されることがあります。プロセスがこの共有領域に書き込み操作を実行させたい場合、書き込みはロック操作を提供しないため、共有領域のデータに損傷を与えます。Copy-オンライトは、データを保護するためにLinuxによって導入されました。

コピーオンライトとは、複数のプロセスが同じデータを共有している場合、プロセスの1つがこのデータを変更する必要がある場合、そのデータを独自のプロセスアドレス空間にコピーする必要があることを意味します。これは他のプロセスのデータブロック操作には影響しません。各プロセスを変更する必要がある場合にのみコピーされるため、コピーオンライトと呼ばれます。この方法により、システムのオーバーヘッドをある程度削減できます。プロセスがアクセスされたデータを変更しない場合は、コピーする必要はありません。

欠陥:

  • 1)MMUのサポートが必要です。MMUはプロセスアドレス空間のどのページが読み取り専用であるかを知る必要があります。これらのページにデータを書き込む必要がある場合、例外がオペレーティングシステムカーネルに送信され、カーネルは新しいものを割り当てます。需要を書き込むためのストレージスペース。

方法7:バッファ共有

従来のI / Oインターフェイスはすべてデータコピーに基づいているため、この方法はI / O操作を完全に書き換えます。コピーを回避するには、元のインターフェイスセットを削除して書き換えます。したがって、この方法はより包括的なゼロコピーテクノロジです。現在、より成熟したソリューションは、Solarisに最初に実装されたfbuf(Fast Buffer)です。

Fbufの考え方は、各プロセスがバッファープールを維持することです。このバッファープールは、プログラムアドレス空間とカーネルアドレス空間に同時にマップできます。カーネルとユーザーはこのバッファープールを共有するため、コピーを回避できます。

欠陥:

  • 1)共有バッファプールの管理には、アプリケーション、ネットワークソフトウェア、およびデバイスドライバ間の緊密な協力が必要です。
  • 2)APIの書き換えはまだ実験段階です。

高性能ネットワークI / Oフレームワーク-ネットマップ

共有メモリのアイデアに基づいて、Netmapは生データパケットを送受信するための高性能フレームワークです。LuigiRizzoなどによって開発されました。カーネルモジュールとユーザーモードライブラリ関数が含まれています。目標は、既存のオペレーティングシステムソフトウェアを変更したり、特別なハードウェアサポートを使用したりすることなく、ユーザーモードとネットワークカード間でデータパケットを高性能に送信することです。

Netmapフレームワークでは、カーネルにデータパケットプールがあります。送信リング/受信リングのデータパケットを動的に適用する必要はありません。データがネットワークカードに到着すると、データが到着すると、データパケットはから直接取得されます。データパケットプール、次にデータがこのデータパケットに入れられ、次にデータパケットの記述子が受信リングに入れられます。カーネル内のパケットプールは、mmapテクノロジーを介してユーザースペースにマップされます。ユーザーモードプログラムは、最終的にnetmap_ifを介して受信および送信リングnetmap_ringを取得し、データパケットを取得および送信します。

おすすめ

転載: blog.csdn.net/baidu_39322753/article/details/104491598