LinuxのIOモデルと関連テクノロジーの図解

ブロッキングIOモデル(ブロッキングI / O)

 

ファイル

Linuxカーネルは当初、読み取りおよび書き込みのブロック操作を提供していました。

  • クライアントが接続すると、対応するファイル記述子(0標準入力、1標準出力、2標準エラー出力;)が、fd 8などの対応するプロセス(/ proc /プロセス番号/ fd)のファイル記述子ディレクトリに生成されます。 、fd 9;
  • アプリケーションが読み取る必要がある場合、システムコールread(fd8)を介して読み取られます。データが到着していない場合、このアプリケーションのプロセスまたはスレッドはブロックして待機します。
man 2 read
概述
     #include <unistd.h>
     ssize_t read(int fd, void *buf, size_t count);
描述
     read() 从文件描述符 fd 中读取 count 字节的数据并放入从 buf 开始的缓冲区中.
     如果 count 为零,read()返回0,不执行其他任何操作. 如果 count 大于SSIZE_MAX,那么结果将不可预料.
返回值
     成功时返回读取到的字节数(为零表示读到文件描述符), 此返回值受文件剩余字节数限制.当返回值小于指定的字节数时 并不意味着错误;这可能是因为当前可读取的字节数小于指定的 字节数(比如已经接近文件结尾,或
     者正在从管道或者终端读取数 据,或者 read()被信号中断). 发生错误时返回-1,并置 errno 为相应值.在这种情况下无法得知文件偏移位置是否有变化.

問題

1000など、クライアント接続が多数ある場合、アプリケーションは1000のプロセスまたはスレッドがブロックして待機できるようにします。現時点では、パフォーマンスの問題が発生します。

  • CPUは絶えず切り替わるため、プロセスまたはスレッドのコンテキスト切り替えのオーバーヘッドが発生し、IOを読み取る実際の時間が減少するため、CPUの計算能力が浪費されます。したがって、ノンブロッキングI / Oの誕生が促進されました。

ノンブロッキングIOモデル(ノンブロッキングI / O)

 

ファイル

この時点で、Linuxカーネルは最初に読み取りと書き込みの非ブロッキング操作を提供し、SOCK_NONBLOCKフラグはソケットを介して設定できます。

  • 現時点では、アプリケーションは各ファイル記述子を処理するためのスレッドを必要としません。読み取りを読み取るために継続的にポーリングするスレッドは1つだけです。データが到着しない場合は、直接返されます。
  • データがある場合は、ビジネスロジックを処理するようにスケジュールできます。男2ソケットコピーコード
Since  Linux  2.6.27, the type argument serves a second purpose: in addition to specifying a socket type, it may include the bitwise OR of any of the following values, to modify the behavior of
       socket():

       SOCK_NONBLOCK   Set the O_NONBLOCK file status flag on the open file description (see open(2)) referred to by the new file descriptor.  Using this flag saves extra calls to fcntl(2) to  achieve
                       the same result.

ここから、ソケットLinux2.6.27カーネルが非ブロッキングモードのサポートを開始していることがわかります。

C / C ++ Linuxバックエンド開発ネットワークの基礎となる主要な知識を共有して、 学習教材を改善し、テクノロジースタックを改善します。コンテンツの知識ポイントには、Linux、Nginx、ZeroMQ、MySQL、Redis、fastdfs、MongoDB、ZK、ストリーミングメディア、オーディオ、ビデオ開発、Linuxカーネル、CDN、P2P、K8S、Docker、TCP / IP、coroutine、DPDKなど。

ビデオ学習資料をクリックしてください:C / C ++ Linuxサーバー開発/ Linuxバックグラウンドアーキテクト-学習ビデオ

 

問題

同様に、1000などのクライアント接続が多数ある場合、1000のシステムコールがトリガーされます。(1000システムコールのオーバーヘッドも非常に客観的です)

したがって、selectがあります。

IO多重化モデル(I / O多重化)-選択

 

ファイル

この時点で、Linuxカーネルは最初にselect操作を提供します。これにより、1000のシステムコールを1つのシステムコールに減らすことができ、ポーリングはカーネル空間で行われます。

  • selectシステムコールは利用可能なfdセットを返します。この時点で、アプリケーションはビジネス処理のためにデータを読み取るために利用可能なfdセットをトラバースするだけで済みます。男2選択
SYNOPSIS
       #include <sys/select.h>
       int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

DESCRIPTION
       select() allows a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). A file
       descriptor is considered ready if it is possible to perform a corresponding I/O operation (e.g., read(2), or a sufficiently small write(2)) without blocking.

       select() can monitor only file descriptors numbers that are less than FD_SETSIZE; poll(2) and epoll(7) do not have this limitation. See BUGS.

カーネルによるポーリングで複数のファイル記述子がサポートされていることがわかります。

問題

1000のシステムコールは1つのシステムコールのコストに削減されますが、1000のファイル記述子をシステムコールのオーバーヘッドで渡す必要があります。これにより、一定量のメモリオーバーヘッドも発生します。

したがって、epollがあります。

select() can monitor only file descriptors numbers that are less than FD_SETSIZE; poll(2) and epoll(7) do not have this limitation. See BUGS.

IO多重化モデル(I / O多重化)-epoll

 

ファイル

man epoll
man 2 epoll_create
man 2 epoll_ctl
man 2 epoll_wait
  • epoll:
SYNOPSIS
       #include <sys/epoll.h>

DESCRIPTION
       The  epoll  API  performs  a  similar task to poll(2): monitoring multiple file descriptors to see if I/O is possible on any of them.  The epoll API can be used either as an edge-triggered or a
       level-triggered interface and scales well to large numbers of watched file descriptors.

       The central concept of the epoll API is the epoll instance, an in-kernel data structure which, from a user-space perspective, can be considered as a container for two lists:

       • The interest list (sometimes also called the epoll set): the set of file descriptors that the process has registered an interest in monitoring.

       • The ready list: the set of file descriptors that are "ready" for I/O.  The ready list is a subset of (or, more precisely, a set of references to) the file descriptors in  the  interest  list.
         The ready list is dynamically populated by the kernel as a result of I/O activity on those file descriptors.
  • epoll_create:

カーネルはepollインスタンスのデータ構造を生成し、ファイル記述子epfdを返します。

  • epoll_ctl:

ファイル記述子fdとその監視イベントepoll_eventを登録、削除、または変更します。

SYNOPSIS
       #include <sys/epoll.h>
       int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

DESCRIPTION
       This system call is used to add, modify, or remove entries in the interest list of the epoll(7) instance referred to by the file descriptor epfd. It requests that the operation op be performed
       for the target file descriptor, fd.

       Valid values for the op argument are:
       EPOLL_CTL_ADD
              Add an entry to the interest list of the epoll file descriptor, epfd. The entry includes the file descriptor, fd, a reference to the corresponding open file description (see epoll(7)
              and open(2)), and the settings specified in event.
       EPOLL_CTL_MOD
              Change the settings associated with fd in the interest list to the new settings specified in event.
       EPOLL_CTL_DEL
          Remove (deregister) the target file descriptor fd from the interest list. The event argument is ignored and can be NULL (but see BUGS below).
  • epoll_wait:

登録されたイベントの発生をブロックし、イベントの数を返し、トリガーされた使用可能なイベントをepoll_events配列に書き込みます。

その他のIO最適化手法

man 2 mmap
man 2 sendfile
man 2 fork

mmap:

読み取りおよび書き込みシステムコールを呼び出さずに、ユーザーの仮想アドレス空間でファイルを操作するための空きアドレスを見つけることです。その最終的な目標は、ディスク上のファイルをユーザープロセスの仮想アドレス空間にマップして実現することです。ユーザープロセスファイルの直接読み取りと書き込みにより、ファイルコピーのオーバーヘッドが削減され、ユーザーアクセスの効率が向上します。

例として読んでください:

 

ファイル

  • 使用するシーン

Kafkaのデータファイルはmmapであり、ファイルに書き込まれ、ユーザースペースを経由せずにカーネルスペースに直接コピーできます。

別の例として、JavaのMappedByteBufferの最下層はLinuxのmmapです。

C / C ++ Linuxバックエンド開発ネットワークの基礎となる主要な知識を共有して、 学習教材を改善し、テクノロジースタックを改善します。コンテンツの知識ポイントには、Linux、Nginx、ZeroMQ、MySQL、Redis、fastdfs、MongoDB、ZK、ストリーミングメディア、オーディオ、ビデオ開発、Linuxカーネル、CDN、P2P、K8S、Docker、TCP / IP、coroutine、DPDKなど。

ビデオ学習資料をクリックしてください:C / C ++ Linuxサーバー開発/ Linuxバックグラウンドアーキテクト-学習ビデオ

ファイルを送信:

 

ファイル

sendfileシステムコールは、2つのファイル記述子(カーネルで完全に操作される)間でデータを直接転送するため、カーネルバッファーとユーザーバッファー間でのデータのコピーを回避します。操作効率は非常に高く、ゼロコピーと呼ばれます。

  • 使用するシーン

たとえば、Kafkaは、消費者が消費するときに、sendfile(JavaではFileChannel.transferTo)を直接呼び出して、カーネルデータがメモリまたはデータファイルから読み取られ、ネットワークカードに直接送信されることを認識します。ユーザースペース、いわゆる「ゼロコピー」を実現します。

たとえば、Tomcat、Nginx、ApacheなどのWebサーバーは、静的リソースなどを返し、すべてsendfileを使用してネットワーク経由でデータを送信します。

フォーク

man 2 fork

子プロセスを作成するには、次の3つの方法があります。

  • フォーク、呼び出し後、子プロセスは独自のpidおよびtask_struct構造を持ち、コピーは親プロセスのすべてのデータリソースに基づいて作成され、主に独自のポインターをコピーし、親プロセスの仮想メモリスペースをコピーしません。 、および親プロセスと子プロセスが同時に実行されます。変数は互いに分離されており、互いに干渉しません。

現在、Linuxはコピーオンライト(COW、コピーオンライト)テクノロジーを採用しています。オーバーヘッドを削減するために、フォークは最初は実際には2つの異なるコピーを生成しません。これは、当時、大量のデータが実際には正確であるためです。同じ。の。コピーオンライトは、実際のデータコピーを延期しています。後で書き込みが発生した場合は、親プロセスと子プロセスのデータに一貫性がないため、コピーアクションが発生し、各プロセスが独自のコピーを取得するため、システムコールのオーバーヘッドを削減できます。

NOTES
       Under  Linux,  fork()  is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique
       task structure for the child.
  • vfork、vforkシステムコールはforkとは異なり、vforkで作成された子プロセスは親プロセスとアドレス空間を共有します。つまり、子プロセスは親プロセスのアドレス空間で完全に実行されます。つまり、子プロセスです。仮想アドレス空間内のすべてのデータを変更します。親プロセスによって表示されます。そして、vforkが子プロセスを終了した後、親プロセスはブロックし、子プロセスの終了が続くのを待ちます。
  • クローンは、forkとvforkの混合使用と見なすことができます。ユーザーは、clone_flagsの設定を通じて、共有するリソースとコピーするリソースのコピーを決定します。フラグCLONE_VFORKは、子プロセスの実行時に親プロセスをブロックするか実行するかを決定します。このフラグが設定されていない場合、親プロセスと子プロセスは同時に実行されます。フラグが設定されている場合、親プロセスは子プロセスまでハングします。プロセスは終了します。
  • forkの目的を要約すると、プロセスはそれ自体のコピーを作成して、親プロセスと子プロセスがコードの異なるセクションを同時に実行できるようにする必要があります。たとえば、redisのRDB永続性は、フォークを使用して、サービスを提供し続ける親プロセスに影響を与えることなく、コピーコピーの時間が正確かつ高速であることを保証します。vforkの目的vforkで作成されたプロセスの主な目的は、最初にexec関数を使用して別のプログラムを実行することです。クローンの目的は、親プロセスと子プロセスの間で共有する必要のあるリソースと、コピーする必要のあるリソースを選択的に設定することです。

 

おすすめ

転載: blog.csdn.net/Linuxhus/article/details/114587206