文章目录
- I/O模型相关概念
- 网络I/O模型
- 阻塞型I/O模型
- 非阻塞型I/O模型
- 多路复用I/O型
- 信号驱动式I/O型
- 异步I/O模型
- apache和nginx的区别,什么时候选择apache,什么时候选择nginx
文章相关连接如下:
- 如果想更多了解nginx,请点击:企业高性能web服务器之nginx篇
- 如果想更多了解web服务工作模型,请点击:重大发现!看Apache与nginx工作模型,享web服务幸福人生
I/O模型相关概念
同步/异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状态的通知。
- 同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事情是否处理完成
- 异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态
阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态
- 阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
- 非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。
网络I/O模型
阻塞型、非阻塞型、复用型、信号驱动型、异步
阻塞型I/O模型
阻塞型 I/O 模型(blocking IO)流程图
- 阻塞IO模型是最简单的I/O模型,用户线程在内核进行IO操作时被阻塞
- 用户线程通过系统调用read发起I/O读操作,由用户空间转到内核空间。内核等到数据包到达后,然后将接收的数据拷贝到用户空间,完成read操作
- 用户需要等待read将数据读取到buffer后,才继续处理接收的数据。整个I/O请求的过程中,用户线程是被阻塞的,这导致用户在发起IO请求时,不能做任何事情,对CPU的资源利用率不够
优点:程序简单,在阻塞等待数据期间进程/线程挂起,基本不会占用 CPU 资源
缺点:每个连接需要独立的进程/线程单独处理,当并发请求量大时为了维护程序,内存、线程切换开销较apache 的preforck使用的是这种模式。
非阻塞型I/O模型
在设置连接为非阻塞时,当应用进程系统调用 recvfrom 没有数据返回时,内核会立即返回一个 EWOULDBLOCK 错误,而不会一直阻塞到数据准备好。如上图在第四次调用时有一个数据报准备好了,所以这时数据会被复制到 应用进程缓冲区 ,于是 recvfrom 成功返回数据
- 当一个应用进程这样循环调用 recvfrom 时,称之为轮询 polling 。这么做往往会耗费大量CPU时间,实际使用很少
多路复用I/O型
- 上面的模型中,每一个文件描述符对应的IO是由一个线程监控和处理
- 多路复用IO指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自的IO,即复用同一个线程
- 一个线程之所以能实现同时处理多个IO,是因为这个线程调用了内核中的SELECT,POLL或EPOLL等系统调用,从而实现多路复用IO
基本原理:select/poll/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。
优点
- 可以基于一个阻塞对象,同时在多个描述符上等待就绪,而不是使用多个线程(每个文件描述符一个线程),这样可以大大节省系统资源
缺点
- 当连接数较少时效率相比多线程+阻塞 I/O 模型效率较低,可能延迟更大,因为单个连接处理需要 2 次系统调用,占用时间会有增加
适用场景:
- 当客户端处理多个描述符时(一般是交互式输入和网络套接口),必须使用I/O复用
- 当一个客户端同时处理多个套接字时,此情况可能的但很少出现
- 当一个服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到I/O复用
- 当一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用
- 当一个服务器要处理多个服务或多个协议,一般要使用I/O复用
信号驱动式I/O型
信号驱动I/O的意思就是进程现在不用傻等着,也不用去轮询。而是让内核在数据就绪时,发送信号通知进程
优势:
- 等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处理函数的通知。
- 在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O,并安装一个信号处理函数,进程继续运行并不阻塞
- 在信号驱动式 I/O 模型中,应用程序使用套接口进行信号驱动 I/O,并安装一个信号处理函数,进程继续运行并不阻塞
- 线程并没有在等待数据时被阻塞,内核直接返回调用接收信号,不影响进程继续处理其他请求因此可以提高资源的利用率
缺点:
- 信号 I/O 在大量 IO 操作时可能会因为信号队列溢出导致没法通知
- 异步阻塞:程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核收到进程
请求后 - 进行的IO如果不能立即返回,就由内核等待结果,直到IO完成后内核再通知进程。
异步I/O模型
优点:
- 异步 I/O 能够充分利用 DMA 特性,让 I/O 操作与计算重叠
缺点:
- 要实现真正的异步 I/O,操作系统需要做大量的工作。目前 Windows 下通过 IOCP 实现了真正的异步 I/O,在 Linux 系统下,Linux 2.6才引入
- 目前 AIO 并不完善,因此在 Linux 下实现高并发网络编程时以 IO 复用模型模式+多线程任务的架构基本可以满足需求
异步非阻塞:
- 程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现
较大的同时并实现较高的IO复用,因此异步非阻塞使用最多的一种通信方式。
apache和nginx的区别,什么时候选择apache,什么时候选择nginx
- 两者最核心的区别在于apache是同步多进程模型,一个连接对应一个进程,而nginx是异步的,多个连接(万级别)可以对应一个进程。
- 需要性能的web服务,用nginx。如果不需要性能只求稳定,更考虑apache,apache的各种功能模块实现比nginx好,例如ssl的模块就比nginx好,可配置项多。
- epoll(freebsd上是kqueue)网络IO模型是nginx处理性能高的根本理由,但并不是所有的情况下都是epoll大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache的select模型或许比epoll更高性能。
- 这只是根据网络IO模型的原理作的一个假设,真正的应用还是需要实测。更为通用的方案是,前端nginx抗并发,后端apache集群,配合起来会更好。