操作系统之网络IO

零拷贝

传统的文件传输

图片

在传统的文件传输中,由于涉及到两次系统调用read和write,所以会产生4次上下文切换。并且存在4次数据拷贝(2次DMA拷贝和2次CPU拷贝),①第一次拷贝,把磁盘上的数据拷贝到内存的操作系统内核的缓冲区里,这个拷贝的过程是通过 DMA完成的;②第二次拷贝,把内核缓冲区的数据拷贝到用户的缓冲区里,这个拷贝到过程是由 CPU 完成的;③第三次拷贝,把刚才拷贝到用户的缓冲区里的数据,再拷贝到内核的 socket 的缓冲区里,这个过程依然还是由 CPU 搬运的;④第四次拷贝,把内核的 socket 缓冲区里的数据,拷贝到网卡的缓冲区里,这个过程又是由 DMA 搬运的。

mmap+write实现零拷贝

在传统的文件传输中,读文件需要先将文件拷贝到内核缓冲区中,然后再拷贝到用户空间中。

mmap()函数会在进程的虚拟地址空间中,寻找一段空闲的满足要求的连续虚拟地址,然后建立页表项,将该段虚拟地址映射到该文件的文件地址上,并且在第一次访问的时候会触发缺页中断,然后将文件内容从磁盘调入内存中,这样的话就可以像访问普通内存一样来访问该文件。可以发现通过mmap()系统调用,只使用一次数据拷贝,就从磁盘中将数据传入内存的用户空间中,供进程使用。同时,用户空间和内核空间中的一方对映射区域的修改,都可以立即被另一方捕捉到。

通过使用 mmap() 来代替 read(), 可以减少一次数据拷贝的过程。但是还是存在2次系统调用,4次上下文切换和3次拷贝(2次DMA拷贝和1次CPU拷贝)。

图片

sendfile实现零拷贝

通过sendfile()函数可以实现read和write两个函数的功能,将数据从源文件描述符端口拷贝到目的文件描述符端口,减少了一次系统调用。并且直接将数据从内核缓冲区拷贝到网卡,不再经过socket缓冲区了,所以只有2次拷贝,①通过 DMA 将磁盘上的数据拷贝到内核缓冲区里;②将内核缓存中的数据拷贝到网卡的缓冲区里。所以只需要2次上下文切换2次数据拷贝即可,而且2次的数据拷贝过程都是由 DMA 来完成的,不需要通过CPU。

图片

IO模型

对于一次IO访问(以read为例),数据(位于磁盘或网卡等地方)会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的空间。所以会经历两个阶段:①等待内核将数据准备好;②将数据从内核拷贝到进程的用户空间中。

①阻塞IO模型:默认情况下所有的文件操作都是阻塞的,在用户空间调用recvfrom(以套接字接口为例)读取数据时,其系统调用直到数据包到达且被复制到应用缓冲区中或者发送错误时才返回,在此期间一直会等待,进程从调用到返回这段时间内都是被阻塞;

img

②非阻塞IO:应用程序调用recvfrom读取数据时,如果该内核缓冲区没有数据的话,就会直接返回一个EWOULDBLOCK错误,不会让应用一直等待中;如果数据已经准备好了,则会将数据从内核缓冲区拷贝到用户空间中。我们在应用程序中可以循环调用recvfrom函数并判断是否出现该错误标识,直到读取到它数据要的数据为止。

img

③IO多路复用:进程通过将一个或多个fd传递给select/poll系统调用,阻塞在select操作上,select/poll帮我们侦测多个fd是否准备就绪,当有fd准备就绪时,select返回数据可读状态,应用程序再调用recvfrom读取数据。select/poll顺序扫描fd是否就绪,每次执行的时间复杂度和fd的数量成正比,且支持的fd数量受到限制,因此Linux提供了epoll系统调用,它使用事件驱动的方式代替了顺序扫描,当有fd就绪时,立即执行其回调函数,性能更高。IO多路复用的好处就是通过select或poll、epoll 来监控多个fd ,从而不必为每个fd创建一个对应的监控线程,从而创建多个线程的开销并减少了资源占用。

img

④信号驱动IO模型:首先开启套接口信号驱动IO功能,并通过系统调用sigaction为SIGIO信号绑定一个信号处理函数,此时请求即刻返回,当内核数据准备就绪时,就给对应进程发送SIGIO信号,进程接收到该信号后,会通过信号处理程序来通知应用程序调用recvfrom来读取数据。

img

⑤异步IO:应用程序告知内核启动某个操作,并让内核在整个操作完成之后通知应用程序,比如说内核已经将数据准备好并已经将其拷贝到用户空间中了。这种模型与信号驱动模型的主要区别在于,信号驱动IO只是由内核通知我们何时可以开始IO操作,而异步IO模型是由内核通知我们操作何时已经完成。

img

IO多路复用

select/poll

select 实现多路复用的方式是,将多个已连接的 Socket 都放到一个文件描述符集合,然后调用 select 函数将文件描述符集合拷贝到内核里,内核通过顺序遍历文件描述符集合的方式来检查是否有网络事件产生,当检查到有事件产生后,将此 Socket 标记为可读或可写, 接着再把整个文件描述符集合拷贝回用户态里,然后用户态还需要再通过遍历的方法找到可读或可写的 Socket,然后再对其处理。

select缺点:

  1. 单个进程能够监视的文件描述符的数量存在最大限制,通常是1024,当然可以更改数量,但由于select采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差;
  2. 需要通过遍历的方式来找到可读或可写的文件描述符,时间复杂度为O(n);
  3. 每次调用都需要会产生两次文件描述符集合的拷贝;

poll以链表形式来组织文件描述符集合,不再有单个进程文件描述符个数限制,当然还会受到系统文件描述符限制。除此之外它的实现方式和select并没有区别,所以还是会存在上述的缺点2和3。

epoll

epoll在内核里使用红黑树来管理所有待检测的文件描述符,用户程序只需要通过 epoll_ctl() 函数将需要监控的 socket加入内核中的红黑树里,这样就不需要像 select/poll 每次操作时都要拷贝整个文件描述符集合到内核,而只需要传入一个待检测的 socket,减少了内核和用户空间大量的数据拷贝。

epoll 使用事件驱动的机制,内核里维护了一个双向链表来记录就绪事件,当某个 socket 有事件发生时,通过回调函数内核会将其加入到这个就绪事件链表中,当用户调用 epoll_wait() 函数时,只会返回有事件发生的文件描述符的个数,不需要像 select/poll 那样轮询扫描整个文件描述符集合,因此与执行效率与文件描述符的个数无关,也对文件描述符的个数没有限制。

触发方式

**水平触发(LT):**当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序可以不立即处理该事件;下次调用epoll_wait时,会再次通知此事件

边缘触发(ET): 当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次通知此事件。

select/poll只支持水平触发,epoll支持水平触发和边缘触发,但是默认为水平触发。

Reactor模型

单Reactor单线程模型

使用一个线程来完成客户端的所有请求,Reactor通过IO多路复用接口监听事件,收到事件后通过dispatch进行分发,根据事件类型将其分发给Acceptor 来建立连接或者当前连接对应的Handler来完成业务请求。

缺点:

  • 只有一个线程,无法充分利用多核CPU的优势,当客户端数量很多时,即使CPU的负载达到100%,也无法满足高并发下海量消息的编解码、读取和发送;
  • 如果一个业务请求的耗时特别长,就会导致后续请求阻塞;
  • 一旦这个线程出现问题,则会导致整个通信模块不可用,不能接收和处理消息;

所以该模型不适用于计算密集型场景,只适用于业务处理非常快的场景(如Redis)。

图片

单Reactor多线程模型

该模型专门有一个线程(Acceptor线程)用于处理客户端的TCP连接请求,然后其它的业务请求交由一个线程池来负责。

  • Reactor通过IO多路复用接口监听事件,收到事件后通过dispatch进行分发,根据事件类型将其分发给Acceptor 来建立连接或者当前连接对应的Handler来完成业务请求;
  • Handler 对象不再负责业务处理,只负责数据的接收和发送,Handler 对象通过 read 读取到数据后,会将数据发给子线程里的 Processor 对象进行业务处理;
  • 子线程里的 Processor 对象就进行业务处理,处理完后,将结果发给主线程中的 Handler 对象,接着由 Handler 通过 send 方法将响应结果发送给 client;

在一些场景下,一个线程负责监听和处理所有的客户端连接可能会存在性能问题。

图片

主从Reactor多线程模型

用于接收客户端连接的不再是一个单独的线程,而是一个独立的线程池。Acceptor接收到客户端的TCP连接请求并处理完成后,将新建的Socket注册到IO线程池的某个线程上,此后由它来负责该连接后续的读写和编解码工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值