*** 作系统(二)网络系统

 *** 作系统(二)网络系统,第1张

*** 作系统(二)网络系统

目录

拷贝

DMA

传统文件传输

实现零拷贝

mmap + write

sendfile(Linux 2.1)

sendfile(Linux 2.4) 

I/O

过程

同步

理解

阻塞 I/O

阻塞 I/O

信号驱动式 I/O 

异步

理解

异步 I/O

例子:钓鱼 

I/O 多路复用 

出现原因及特点

select/poll

过程

缺点 

epoll 

特点 

过程

事件触发模式 

边缘触发(edge-triggered,ET)

水平触发(level-triggered,LT) 

Reactor

基础 

核心架构

模式优点 

适用场景 

单 Reactor 单线程

架构

优点

缺点

应用实例 

单 Reactor 多线程

架构

Handler 收到结果才返回,为什么不阻塞? 

优点

缺点

主从 Reactor 多线程 

架构

优点

缺点

应用实例 

Proactor

基础 

核心架构

模式缺点

适用场景 

与 Reactor 区别 


零拷贝 DMA 传统文件传输 实现零拷贝 mmap + write

sendfile(Linux 2.1)

sendfile(Linux 2.4) 

I/O 过程

第一步:将网络中的数据拷贝到内核缓冲区

第二步:将内核缓冲区数据拷贝到应用进程的缓冲区

同步 理解

拷贝 *** 作不是全部由内核来完成;第二步需要阻塞等待 

阻塞 I/O

第一步:阻塞等待数据拷贝完成第二步:阻塞等待数据拷贝完成 


整体都是阻塞的;会一直阻塞等待读/写,无法执行其他 *** 作

非阻塞 I/O

第一步:循环进行系统调用,查看数据是否拷贝完成;无论是否有数据,调用都不会阻塞,立即返回;会耗费大量 CPU 资源第二步:阻塞等待数据拷贝完成 


小过程不阻塞,但其实整体来看是阻塞的;可检测状态,无数据可读/写则执行其他 *** 作

信号驱动式 I/O 

第一步:完全不阻塞;数据拷贝完成,内核会通知用户进程第二步:阻塞等待数据拷贝完成 


只有第二步阻塞

异步 理解

拷贝 *** 作全部由内核来完成 

异步 I/O

第一步:完全不阻塞第二步:完全不阻塞;数据拷贝完成,内核会通知用户进程

整个过程都不阻塞,内核完成所有 *** 作,通知用户进程

例子:钓鱼 

拷贝数据到内核:鱼上钩

拷贝数据到用户态:将鱼放入桶中


阻塞 I/O:上钩之前,一直盯着;上钩之后,将入桶


非阻塞 I/O:上钩之前,不需要一直盯着,时不时看看有没有动静;鱼上钩之后,将鱼入桶


信号驱动式 I/O:鱼竿上绑,上钩之前,可以一直不管;上钩之后,会响,然后将入桶


异步 I/O:智能鱼竿,上钩之后,自动入桶;整个过程都不用管,入桶后通知你

I/O 多路复用  出现原因及特点

传统的 socket 模型,一个线程/进程只能处理一个 I/O 请求;无数据读/写,会一直阻塞,无法执行其他 *** 作;要想处理多个 I/O 请求,则需要开多个线程/进程,对资源造成浪费

I/O 多路复用,一个线程中可以处理多个 I/O 请求可设置超时时间,来决定是否一直阻塞等待系统调用(并非读写数据)

select/poll 过程

已连接的 socket 都放到一个文件描述符集合(在用户态)select 函数将集合拷贝到内核(第一次拷贝)遍历集合,将产生事件的 socket 标记为可读/可写(第一次遍历 O(n))将集合拷贝回用户态(第二次拷贝)用户态遍历集合,对可读/可写的 socket 进行处理(第二次遍历 O(n))拷贝 2 次,遍历 2 次


select:使用固定长度的 BitsMap,所支持文件描述符个数有限

poll:使用链表,突破文件描述符个数限制

缺点 

随着并发数上升,拷贝与遍历的开销越来越大 检测效率低(可能整个集合都未发生事件)

epoll  特点 

① 内核中使用红黑树来跟踪待检测的文件描述符;每次只需要传入一个待检测的 socket,因为存储结构在内核中,不需要再从用户态中将整个集合拷贝;增删查均为 O(logn)


② 使用事件驱动机制,当 socket 有事件发生,通过回调函数内核将其加入就绪队列,不需要再遍历整个集合;内核维护一个链表记录就绪事件


③ 只返回有事件发生的文件描述符

过程

需要监控的 socket 通过 epoll_ctl()  加入内核红黑树socket 事件发生,加入事件就绪链表用户调用 epoll_wait() 内核将事件就绪链表内描述符,拷贝到用户态

事件触发模式  边缘触发(edge-triggered,ET)

只有第一次满足条件才触发事件;如 socket 中数据从 0 到有,只触发这一次读事件,下一次 0 到有则会再次触发

对该文件描述符的 *** 作必须一次性执行完,最好结合非阻塞 I/O(返回的事件并不一定可读写,非阻塞 I/O 可以检测状态)系统调用次数更少,效率更高epoll 支持

水平触发(level-triggered,LT) 

只要满足条件就会一直触发事件;如 socket 中只要有数据,就会一直触发读事件

没必要一次性执行完可以继续检测该文件描述符状态select/poll/epoll 支持


优点

减少内核和用户态大量拷贝和内存分配极大提高了检测效率  

Reactor 基础  核心架构

I/O 多路复用 + 线程池 

I/O 多路复用监听事件收到事件,Dispatch 根据事件类型,分发给某个线程 

模式优点 

实现相对简单,可最大程度避免多线程同步以及交换的开销整体是同步的,但不会因为单个同步时间而阻塞 可扩展性强,增加 Reactor 实例很方便,以此充分利用 CPU 资源可复用性高,与事件具体处理逻辑无关

适用场景 

同时接受多个服务请求,并依次同步处理 

单 Reactor 单线程 架构

    Reactor 对象 通过 Select 监听客户端请求事件,收到事件后通过 Dispatch 分发为连接事件,则建立新连接并加入监听队列,为连接分配 Handler 做后续业务 *** 作不为连接事件,则分发调用连接对应的 Handler 来响应
优点

模型简单没有多线程竞争问题,都在一个线程内完成

缺点

性能问题:不能发挥多核 CPU 的性能优势;在单线程中处理所有事件的监听和响应;处理某个连接的业务时,无法处理其他连接的事件,容易造成性能瓶颈可靠性问题:线程意外终止或者进入死循环,会造成整个系统通信模块不可用,造成结点故障

应用实例 

客户数量有限,并且业务处理速度极快 -> redis

单 Reactor 多线程 架构

    Reactor 对象 通过 Select 监听客户端请求事件,收到事件后通过 Dispatch 分发为连接事件,则建立新连接并加入监听队列,为连接分配 Handler 做后续业务 *** 作不为连接事件,则分发调用连接对应的 HandlerHandler 只负责响应,不负责业务处理Handler read 数据后,业务交给 Worker 线程池中线程处理;收到业务处理结果后,通过 send 响应客户端
Handler 收到结果才返回,为什么不阻塞? 

Reactor 采用非阻塞 I/O非阻塞 I/O 无数据可读/可写时,不会一直等待(read/send),可以执行其他 *** 作单 Reactor 单线程阻塞,是因为所有复杂耗时的业务都在一个线程中处理将会引起阻塞的业务处理交给其他线程处理,避免了阻塞

优点

充分利用多核 CPU 性能优势

缺点

多线数据共享和访问比较复杂单 Reactor 处理所有事件的监听和响应,在单线程中,容易出现性能瓶颈

主从 Reactor 多线程  架构

    Main Reactor 只监听连接事件;建立新连接后,将连接分发给 Slave Reactor;后续所有业务处理事件,就由 Slave Reactor 独立管理Slave Reactor 将新连接加入监听队列,为连接分配 Handler 做后续业务 *** 作Handler 只负责响应,不负责业务处理Handler read 数据后,业务交给 Worker 线程池中线程处理;收到业务处理结果后,通过 send 响应客户端单个 Main Reactor 可以对应多个 Slave Reactor
优点

主从职责明确:主 Reactor 只负责接收新连接;从 Reactor 只负责处理业务主从数据交互简单:主 Reactor 只需把新连接分发给从 Reactor(之后无需再管);从 Reactor 无需返回数据,可自行返回

缺点

编程复杂度高

应用实例 

nginx(主进程只负责初始化 socket,其他 *** 作都交给从进程)memcachednetty 主从模型

Proactor 基础  核心架构

Proactor Initiator 创建 Handler、Proactor,并通过 Asynchronous Operation Processor 注册到内核Asynchronous Operation Processor 异步处理注册请求和 I/O *** 作;I/O *** 作完成,通知 Proactor Processor 通过事件类型回调不同 Handler 执行业务 *** 作

模式缺点

编程复杂性 *** 作系统支持,Windows下通过IOCP实现了真正的异步 I/O,Linux2.6 才引入 

适用场景 

同时接受多个服务请求,并同时处理 

与 Reactor 区别 

Reactor:来了事件,通知应用进程处理(非阻塞 I/O,基于待完成 I/O 事件)Proactor:来了事件, *** 作系统来处理,完成后通知应用进程 (异步 I/O,基于已完成 I/O 事件)

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5715602.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存