NIOからReactorへの多重化(下記)

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して12日目です。クリックしてイベントの詳細をご覧ください

しかし、Longcheng Feiがそこにいるようにし、HumaにYinMountainsに乗るように教えないでください。

1はじめに

NIOとブロッキングの理解は前の記事で説明されており、多重化とReactorの概念はこの記事でも継続されます。

2マルチプレクサ

nioがブロッキングの問題を解決したとしても、無効なポーリングはCPUをアイドル状態にし、リソースを浪費します。IO多重化技術を使用すると、カーネルはデータを準備するときにアプリケーションプロセスにデータを取得するよう通知し、この問題を解決します。Linuxオペレーティングシステムでは、さまざまな動作モードに応じて、select / poll/epollの3つのマルチプレクサに分割されます。すべてのソケットはカーネルカーネルによって監視されます。データの準備ができると、システムコールが開始されます。つまり、システムコールは、カーネルからユーザープロセスにデータをコピーします。

I / O多重化の機能は、プロセスがメカニズムを介して複数のファイル記述子を同時に待機できることです。これらのファイル記述子(ソケット記述子)のいずれかが読み取り可能状態になり、select()関数が返されます。 。複数の接続要求を同時に処理できることが最大の利点です。

2.1関数選択操作

selectは、オペレーティングシステムによって提供されるシステムコール関数であり、これを介してファイル記述子の配列をオペレーティングシステムに送信できます。オペレーティングシステムはそれをトラバースして、読み取りと書き込みが可能なファイル記述子を決定し、次のように通知します。操作は次のようになります。

方法を選択selectは、オペレーティングシステムによって提供される呼び出し関数であり、これを介してfdsのグループをオペレーティングシステムに渡すことができ、オペレーティングシステムはfdsをトラバースし、準備されたファイル記述子の数をユーザースレッドに返し、ユーザースレッドはトラバースします。 fdsを1つずつ確認して、どのfdがすでに準備完了状態にあるかを確認してから、処理に進みます。

selectの特徴は次のとおりです。

  • 1 用户需要将监听的 fd list 传入到操作系统内核中,内核来完成遍历操作并将解决返回,这样在高并发场景数组的复制操作下会过多的消耗资源。select 的这一操作仅解决了系统的上下文切换的开销,遍历数组是依旧存在的。select 返回结果是就绪的 fd 个数,用户线程还需要判断哪个 fd 处于就绪状态。

  • 2 select 可以传入一组 socket 然后等待内核的处理结果,但是其 list 大小只有 1024 个,每次调用 select 都需要将 fd 数组从用户态复制到内核态,其开销比较大。调用 select 后返回的是就绪 fd 数量,还需要用户再次遍历。

2.2 epoll 操作

针对 select 的缺点,poll 为了增加单次监听 socket 的个数,采用了链表的结构,放弃了数组的结构,但是其核心需要遍历的缺点依然没有解决。针对 select 和 poll 的缺点,epoll 应运而生,其核心主要包括三个方法:

# 在内核开辟一个区域用来存放需要监听的fd
epoll_create
# 向内核中添加、修改、删除需要监控的fd
epoll_ctl
# 返回已经就绪的fd
epoll_wait
复制代码

epoll 示意图如下所示: epoll方法

总结核心内容如下所述:

  • 1.内核中存储了一份文件描述符 fd 的集合,无需用户每次都从用户态传入,只需要告诉内核修改的部分就可以。
  • 2.内核中不再通过轮询的方式找到就绪的文件描述符 fd,而是通过异步 IO 事件进行唤醒,这里涉及到数据的操作模式。
  • 3.内核会将有 IO 事件发生的文件描述符 fd 返回给用户,用户不需要自己进行遍历。
2.2.1 epoll 内部的数据结构

epoll 创建了一个空间用来存储监听的 fd,这些监听的 fd 是按照红黑树的数据结构进行组织,eventpoll 中是 rbr 指向该红黑树,而已经准备好的数据则使用双向链表的结构进行存储,存放在 eventpoll 通过 rdllist 指向该链表。

2.2.2 epoll 的数据操作模式

epoll 的数据操作有两种模式:水平模式 LT(level trigger)和边缘模式 ET(edge trigger)。LT 是 epoll 的默认操作模式,两者的区别在于当触发 epoll_wait 函数时,是否会清空 rdllist。

  • 1 LT 模式: epoll_wait 函数检测到有事件发生时需要通知应用程序,但是应用程序不一定及时进行处理,当 epoll_wait 函数再次检测到该事件的时还会通知应用程序,直到事件被处理。可以理解为 mq 发送消息的 at least once 模型。

  • 2 ET 模式:epoll_wait 函数检测到事件发生只会通知应用程序一次,后续 epoll_wait 函数将不再监控该事件。因此 ET 模式降低了同一个事件被 epoll 触发的次数,效率比 LT 模式高。可以理解为 mq 发送消息的 exactly once 模型。

3 IO 线程模型

前文是从内核的角度来分析数据收发的模型,在本节中将从用户空间的角度来看数据的收发情况。通过 IO 多路复用就可以监听 IO 事件,通过 dispatch 不断分发事件就像一个反应堆一样,看起来像不断的产生 IO 事件,因此我们称这种模式为 Reactor 模型。Reactor 就是利用 NIO 对 IO 线程进行不同的分工:

  • 1 前文中提到的 IO 多路复用器,进行 IO 事件的注册和监听。
  • 2 将监听到的就绪 IO 事件通过 dispatch 分发到具体的处理事件 handler 进行 IO 事件处理。

Single Reactorは、接続イベント、読み取りおよび書き込みイベントを含むすべてのイベントをリッスンするepollオブジェクトが1つしかないことを意味します。準備ができたソケットを取得するためにepoll_waitを実行するスレッドは1つだけであり、ソケットに対する後続の操作もこのスレッドによって処理されます。新しい接続が着信すると、接続イベントがトリガーされます。これはアクセプターによって処理され、IOイベントがある場合は、ハンドラーによって処理されます。アクセプターの主なタスクはハンドラーを構築することです。クライアントに関連するSocketChannelを取得した後、対応するハンドラーにバインドされます。対応するSocketChannelがイベントの読み取りと書き込みを行った後、処理できます。ハンドラーには、デコード、計算、エンコード操作が含まれます。次の図に、シングルリアクターのシングルスレッドモデルを示します。

シングルスレッドはマルチコアCPUの利点を十分に発揮できないため、あまり使用されないため、シングルリアクターマルチスレッドモデルがあります。ビジネスロジック、つまりIO読み取り/書き込みまたはシングルを処理する場合スレッド、デコード、計算、エンコードの各操作はスレッドプールによって処理され、そのモデルを次の図に示します。

マスタースレーブマルチスレッドReactorは、タスクをさらに分割します。マスターReactorは、接続を処理するためのソケットイベントの監視を主に担当します。接続が確立されると、ソケットチャネルがスレーブsubReactorに登録されます。subReactorは独自のセレクターを維持し、データの読み取りおよび書き込み操作が完了した後、データ処理は処理のためにワーカースレッドに渡されます。このモデルでは、各モジュールの作業がより具体的になり、結合度が低くなり、パフォーマンスと安定性も大幅に向上し、サポートされる同時クライアントの数は数百万に達する可能性があります。nettyでは、具体的なモデルの実装は次のとおりです。

// 配置单Reactor单线程
EventLoopGroup eventGroup = new NioEventLoopGroup(1);
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(eventGroup);
//配置单Reactor多线程
EventLoopGroup eventGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(eventGroup);
//配置主从Reactor多线程
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup);
复制代码

4まとめ

この記事では、主にNIOノンブロッキングの概念の理解、カーネルに基づく多重化のいくつかのモデルの理解、そして最後にIOスレッドモデルの内容を含む、IO関連の操作について説明します。

おすすめ

転載: juejin.im/post/7085540586379280392