IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 大话操作系统(19)?性能?络模式:Reactor 和 Proactor -> 正文阅读

[系统运维]大话操作系统(19)?性能?络模式:Reactor 和 Proactor

演进

如果要让服务器服务多个客户端,那么最直接的?式就是为每?条连接创建线程。

其实创建进程也是可以的,原理是?样的,进程和线程的区别在于线程?较轻量级些,线程的创建和线程间切换的成本要?些,为了描述简述,后?都以线程为例。

处理完业务逻辑后,随着连接关闭后线程也同样要销毁了,但是这样不停地创建和销毁线程,不仅会带来性能开销,也会造成浪费资源,?且如果要连接?万条连接,创建?万个线程去应对也是不现实的。

要这么解决这个问题呢?我们可以使?「资源复?」的?式。

也就是不?再为每个连接创建线程,?是创建?个「线程池」,将连接分配给线程,然后?个线程可以处理多个连接的业务。

不过,这样?引来?个新的问题,线程怎样才能?效地处理多个连接的业务?

当?个连接对应?个线程时,线程?般采?「read -> 业务处理 -> send」的处理流程,如果当前连接没有数据可读,那么线程会阻塞在 read 操作上( socket 默认情况是阻塞 I/O),不过这种阻塞?式并不影响其他线程。

但是引?了线程池,那么?个线程要处理多个连接的业务,线程在处理某个连接的 read 操作时,如果遇到没有数据可读,就会发?阻塞,那么线程就没办法继续处理其他连接的业务。

要解决这?个问题,最简单的?式就是将 socket 改成?阻塞,然后线程不断地轮询调? read 操作来判断是否有数据,这种?式虽然该能够解决阻塞的问题,但是解决的?式?较粗暴,因为轮询是要消耗 CPU的,?且随着?个 线程处理的连接越多,轮询的效率就会越低。

上?的问题在于,线程并不知道当前连接是否有数据可读,从?需要每次通过 read 去试探。

那有没有办法在只有当连接上有数据的时候,线程才去发起读请求呢?答案是有的,实现这?技术的就是I/O 多路复?。

I/O 多路复?技术会??个系统调?函数来监听我们所有关?的连接,也就说可以在?个监控线程??监控很多的连接。

在这里插入图片描述
我们熟悉的 select/poll/epoll 就是内核提供给?户态的多路复?系统调?,线程可以通过?个系统调?函数从内核中获取多个事件。

select/poll/epoll 是如何获取?络事件的呢?

在获取事件时,先把我们要关?的连接传给内核,再由内核检测:

  • 如果没有事件发?,线程只需阻塞在这个系统调?,??需像前?的线程池?案那样轮训调? read操作来判断是否有数据。

  • 如果有事件发?,内核会返回产?了事件的连接,线程就会从阻塞状态返回,然后在?户态中再处理这些连接对应的业务即可。

当下开源软件能做到?络?性能的原因就是 I/O 多路复?吗?

是的,基本是基于 I/O 多路复?,?过 I/O 多路复?接?写?络程序的同学,肯定知道是?向过程的?式写代码的,这样的开发的效率不?。

于是,?佬们基于?向对象的思想,对 I/O 多路复?作了?层封装,让使?者不?考虑底层?络 API 的细节,只需要关注应?代码的编写。

?佬们还为这种模式取了个让?第?时间难以理解的名字:Reactor 模式。

这?的反应指的是「对事件反应」,也就是来了?个事件,Reactor 就有相对应的反应/响应。

事实上,Reactor 模式也叫 Dispatcher 模式,我觉得这个名字更贴合该模式的含义,即 I/O 多路复?监听事件,收到事件后,根据事件类型分配(Dispatch)给某个进程 / 线程。

Reactor 模式主要由 Reactor 和处理资源池这两个核?部分组成,它俩负责的事情如下:

  • Reactor 负责监听和分发事件,事件类型包含连接事件、读写事件;
  • 处理资源池负责处理事件,如 read -> 业务逻辑 -> send;

Reactor 模式是灵活多变的,可以应对不同的业务场景,灵活在于:

  • Reactor 的数量可以只有?个,也可以有多个;

  • 处理资源池可以是单个进程 / 线程,也可以是多个进程 /线程;

将上?的两个因素排列组设?下,理论上就可以有 4 种?案选择:

  • 单 Reactor 单进程 / 线程;
  • 单 Reactor 多进程 / 线程;
  • 多 Reactor 单进程 / 线程;
  • 多 Reactor 多进程 / 线程;

其中,「多 Reactor 单进程 / 线程」实现?案相?「单 Reactor 单进程 / 线程」?案,不仅复杂?且也没有性能优势,因此实际中并没有应?。

剩下的 3 个?案都是?较经典的,且都有应?在实际的项?中:

  • 单 Reactor 单进程 / 线程;
  • 单 Reactor 多线程 / 进程;
  • 多 Reactor 多进程 / 线程;

?案具体使?进程还是线程,要看使?的编程语?以及平台有关:

  • Java 语??般使?线程,?如 Netty;
  • C 语?使?进程和线程都可以,例如 Nginx 使?的是进程,Memcache 使?的是线程。

接下来,分别介绍这三个经典的 Reactor ?案。

Reactor

单 Reactor 单进程 / 线程

?般来说,C 语?实现的是「单 Reactor 单进程 」的?案,因为 C 语编写完的程序,运?后就是?个独?的进程,不需要在进程中再创建线程。

? Java 语?实现的是「单 Reactor 单线程 」的?案,因为 Java 程序是跑在 Java 虚拟机这个进程上?的,虚拟机中有很多线程,我们写的 Java 程序只是其中的?个线程?已。

我们来看看「单 Reactor 单进程」的?案示意图:

在这里插入图片描述
可以看到进程?有 Reactor、Acceptor、Handler 这三个对象:

  • Reactor 对象的作?是监听和分发事件;
  • Acceptor 对象的作?是获取连接;
  • Handler 对象的作?是处理业务;

对象?的 select、accept、read、send 是系统调?函数,dispatch 和 「业务处理」是需要完成的操作,其中 dispatch 是分发事件操作。

接下来,介绍下「单 Reactor 单进程」这个?案:

  • Reactor 对象通过 select (IO 多路复?接?) 监听事件,收到事件后通过 dispatch 进?分发,具体分发给 Acceptor 对象还是 Handler 对象,还要看收到的事件类型;
  • 如果是连接建?的事件,则交由 Acceptor 对象进?处理,Acceptor 对象会通过 accept ?法 获取连接,并创建?个 Handler 对象来处理后续的响应事件;
  • 如果不是连接建?事件, 则交由当前连接对应的 Handler 对象来进?响应;
  • Handler 对象通过 read -> 业务处理 -> send 的流程来完成完整的业务流程。

单 Reactor 单进程的?案因为全部?作都在同?个进程内完成,所以实现起来?较简单,不需要考虑进程间通信,也不?担?多进程竞争。

但是,这种?案存在 2 个缺点:

  • 第?个缺点,因为只有?个进程,?法充分利? 多核 CPU 的性能;
  • 第?个缺点,Handler 对象在业务处理时,整个进程是?法处理其他连接的事件的,如果业务处理耗时?较?,那么就造成响应的延迟;

所以,单 Reactor 单进程的?案不适?计算机密集型的场景,只适?于业务处理?常快速的场景。

Redis 是由 C 语?实现的,它采?的正是「单 Reactor 单进程」的?案,因为 Redis 业务处理主要是在内存中完成,操作的速度是很快的,性能瓶颈不在 CPU 上,所以 Redis 对于命令的处理是单进程的?案。

单 Reactor 多线程 / 多进程

如果要克服「单 Reactor 单线程 / 进程」?案的缺点,那么就需要引?多线程 / 多进程,这样就产?了单Reactor 多线程 / 多进程的?案。

闻其名不如看其图,先来看看「单 Reactor 多线程」?案的示意图如下:

在这里插入图片描述
详细说?下这个?案:

  • Reactor 对象通过 select (IO 多路复?接?) 监听事件,收到事件后通过 dispatch 进?分发,具体分发给 Acceptor 对象还是 Handler 对象,还要看收到的事件类型;
  • 如果是连接建?的事件,则交由 Acceptor 对象进?处理,Acceptor 对象会通过 accept ?法 获取连接,并创建?个 Handler 对象来处理后续的响应事件;
  • 如果不是连接建?事件, 则交由当前连接对应的 Handler 对象来进?响应;

上?的三个步骤和单 Reactor 单线程?案是?样的,接下来的步骤就开始不?样了:

  • Handler 对象不再负责业务处理,只负责数据的接收和发送,Handler 对象通过 read 读取到数据后,会将数据发给?线程?的 Processor 对象进?业务处理;
  • ?线程?的 Processor 对象就进?业务处理,处理完后,将结果发给主线程中的 Handler 对象,接着由 Handler 通过 send ?法将响应结果发送给 client;

单 Reator 多线程的?案优势在于能够充分利?多核 CPU 的能,那既然引?多线程,那么?然就带来了多线程竞争资源的问题。

例如,?线程完成业务处理后,要把结果传递给主线程的 Reactor 进?发送,这?涉及共享数据的竞争。

要避免多线程由于竞争共享资源?导致数据错乱的问题,就需要在操作共享资源前加上互斥锁,以保证任意时间?只有?个线程在操作共享资源,待该线程操作完释放互斥锁后,其他线程才有机会操作共享数据。

聊完单 Reactor 多线程的?案,接着来看看单 Reactor 多进程的?案。

事实上,单 Reactor 多进程相?单 Reactor 多线程实现起来很麻烦,主要因为要考虑?进程 <-> ?进程的双向通信,并且?进程还得知道?进程要将数据发送给哪个客户端。

?多线程间可以共享数据,虽然要额外考虑并发问题,但是这远?进程间通信的复杂度低得多,因此实际应?中也看不到单 Reactor 多进程的模式。

另外,「单 Reactor」的模式还有个问题,因为?个 Reactor 对象承担所有事件的监听和响应,?且只在主线程中运?,在?对瞬间?并发的场景时,容易成为性能的瓶颈的地?。

多 Reactor 多进程 / 线程

要解决「单 Reactor」的问题,就是将「单 Reactor」实现成「多 Reactor」,这样就产?了第 多Reactor 多进程 / 线程的?案。

?规矩,闻其名不如看其图。多 Reactor 多进程 / 线程?案的示意图如下(以线程为例):

在这里插入图片描述
?案详细说明如下:

  • 主线程中的 MainReactor 对象通过 select 监控连接建?事件,收到事件后通过 Acceptor 对象中的accept 获取连接,将新的连接分配给某个?线程;
  • ?线程中的 SubReactor 对象将 MainReactor 对象分配的连接加? select 继续进?监听,并创建?个Handler ?于处理连接的响应事件。
  • 如果有新的事件发?时,SubReactor 对象会调?当前连接对应的 Handler 对象来进?响应。
  • Handler 对象通过 read -> 业务处理 -> send 的流程来完成完整的业务流程。

多 Reactor 多线程的?案虽然看起来复杂的,但是实际实现时?单 Reactor 多线程的?案要简单的多,原因如下:

  • 主线程和?线程分?明确,主线程只负责接收新连接,?线程负责完成后续的业务处理。
  • 主线程和?线程的交互很简单,主线程只需要把新连接传给?线程,?线程?须返回数据,直接就可以在?线程将处理结果发送给客户端。

?名鼎鼎的两个开源软件 Netty 和 Memcache 都采?了「多 Reactor 多线程」的?案。

采?了「多 Reactor 多进程」?案的开源软件是 Nginx,不过?案与标准的多 Reactor 多进程有些差异。

Proactor

Proactor 采?了异步 I/O 技术,所以被称为异步?络模型。

现在我们再来理解 Reactor 和 Proactor 的区别,就?较清晰了。

Reactor 是?阻塞同步?络模式,感知的是就绪可读写事件。在每次感知到有事件发?(?如可读就绪事件)后,就需要应?进程主动调? read ?法来完成数据的读取,也就是要应?进程主动将socket 接收缓存中的数据读到应?进程内存中,这个过程是同步的,读取完数据后应?进程才能处理数据。

Proactor 是异步?络模式, 感知的是已完成的读写事件。在发起异步读写请求时,需要传?数据缓冲区的地址(?来存放结果数据)等信息,这样系统内核才可以?动帮我们把数据的读写?作完成,这?的读写?作全程由操作系统来做,并不需要像 Reactor 那样还需要应?进程主动发起 read/write来读写数据,操作系统完成读写?作后,就会通知应?进程直接处理数据。

因此,Reactor 可以理解为「来了事件操作系统通知应?进程,让应?进程来处理」,? Proactor 可以理解为「来了事件操作系统来处理,处理完再通知应?进程」。这?的「事件」就是有新连接、有数据可读、有数据可写的这些 I/O 事件这?的「处理」包含从驱动读取到内核以及从内核读取到?户空间。

举个实际?活中的例?,Reactor 模式就是快递员在楼下,给你打电话告诉你快递到你家?区了,你需要??下楼来拿快递。?在 Proactor 模式下,快递员直接将快递送到你家??,然后通知你。

?论是 Reactor,还是 Proactor,都是?种基于「事件分发」的?络编程模式,区别在于 Reactor 模式是基于「待完成」的 I/O 事件,? Proactor 模式则是基于「已完成」的 I/O 事件。

接下来,?起看看 Proactor 模式的示意图:

在这里插入图片描述
介绍?下 Proactor 模式的?作流程:

  • Proactor Initiator 负责创建 Proactor 和 Handler 对象,并将 Proactor 和 Handler 都通过Asynchronous Operation Processor 注册到内核;
  • Asynchronous Operation Processor 负责处理注册请求,并处理 I/O 操作;
  • Asynchronous Operation Processor 完成 I/O 操作后通知 Proactor;
  • Proactor 根据不同的事件类型回调不同的 Handler 进?业务处理;
  • Handler 完成业务处理;

可惜的是,在 Linux 下的异步 I/O 是不完善的,aio 系列函数是由 POSIX 定义的异步操作接?,不是真正的操作系统级别?持的,?是在?户空间模拟出来的异步,并且仅仅?持基于本地?件的 aio 异步操作,?络编程中的 socket 是不?持的,这也使得基于 Linux 的?性能?络程序都是使? Reactor ?案。

? Windows ?实现了?套完整的?持 socket 的异步编程接?,这套接?就是 IOCP ,是由操作系统级别实现的异步 I/O,真正意义上异步 I/O,因此在 Windows ?实现?性能?络程序可以使?效率更?的Proactor ?案。

总结

常?的 Reactor 实现?案有三种。

第?种?案单 Reactor 单进程 / 线程,不?考虑进程间通信以及数据同步的问题,因此实现起来?较简单,这种?案的缺陷在于?法充分利?多核 CPU,?且处理业务逻辑的时间不能太?,否则会延迟响应,所以不适?于计算机密集型的场景,适?于业务处理快速的场景,?如 Redis 采?的是单 Reactor 单进程的?案。

第?种?案单 Reactor 多线程,通过多线程的?式解决了?案?的缺陷,但它离?并发还差?点距离,差在只有?个 Reactor 对象来承担所有事件的监听和响应,?且只在主线程中运?,在?对瞬间?并发的场景时,容易成为性能的瓶颈的地?。

第三种?案多 Reactor 多进程 / 线程,通过多个 Reactor 来解决了?案?的缺陷,主 Reactor 只负责监听事件,响应事件的?作交给了从 Reactor,Netty 和 Memcache 都采?了「多 Reactor 多线程」的?案,Nginx 则采?了类似于 「多 Reactor 多进程」的?案。

Reactor 可以理解为「来了事件操作系统通知应?进程,让应?进程来处理」,? Proactor 可以理解为「来了事件操作系统来处理,处理完再通知应?进程」。

因此,真正的?杀器还是 Proactor,它是采?异步 I/O 实现的异步?络模型,感知的是已完成的读写事件,?不需要像 Reactor 感知到事件后,还需要调? read 来从内核中获取数据。

不过,?论是 Reactor,还是 Proactor,都是?种基于「事件分发」的?络编程模式,区别在于 Reactor模式是基于「待完成」的 I/O 事件,? Proactor 模式则是基于「已完成」的 I/O 事件。

学自小林coding,侵删

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:35:42  更:2022-03-21 21:39:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 0:46:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码