Jamal的博客

Linux-也谈Apache和Nginx的网络模型

看这个话题之前,我们先来看下之前的文章:,https://jamal-jiang.github.io/2017/03/23/Linux-%E9%98%BB%E5%A1%9E%E9%9D%9E%E9%98%BB%E5%A1%9E%EF%BC%8C%E5%90%8C%E6%AD%A5%E5%BC%82%E6%AD%A5%E7%9A%84%E5%8C%BA%E5%88%AB/

了解一下Linux的IO模型
接下来我们看看汇总的IO模型的总结:

总结一下前一篇文章的结论:

1
2
3
4
5
1. 同步IO:导致请求进程阻塞,直到IO操作完成。
异步IO:不导致请求进程阻塞;
2. 前面的四种IO模型,唯一的区别在于等待数据的过程中是怎么处理的,实际在从内核拷贝数据到用户进程的时候都是阻塞的,所以都是同步IO,只有最后一个异步IO模型才是完全异步的。
3. 阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待;
4. 同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写。

Nginx使用了epoll poll select三种模型,这三种模式都属于IO复用模型,本质上还是同步模型。三种模型的区别在哪里呢?
select poll是主动查询机制,他们可以同时查询多个fd的状态,区别在于select有fd个数的限制,poll没有;另外他们创建的事件描述符不通,select创建读,写,异常三个集合,而poll在一个集合中设定这三种描述,由于select和poll每个循环都会检查事件的发生,而poll由于事件少,因此在性能上更高一些。
epoll是基于回调函数的,无轮询。因此当套接字较多的时候,每次select都要通过遍历所有的文件描述符来找到就绪的socket,epoll实现的回调避免了轮询。
web请求的流程:

1
2
3
4
5
6
7
8
9
10
11
1. 服务器网卡接收到请求;
2. 网卡将请求交给内核处理,拆包发现请求到80端口;
3. 内核把请求丢到用户空间的web服务器,web服务器解包发现请求的是index页面;
4. web服务器系统调用将请求发给内核;
5. 内核发现请求的是一个页面,于是调用磁盘驱动程序,连接磁盘;
6. 内核通过驱动调用磁盘取得文件;
7. 内核将取得的页面保存在自己的缓冲区然后通知用户空间web进程来取相应的页面文件;
8. web服务器通过系统调用把页面从内核拷贝到用户态缓冲区;
9. web获取到文件来响应用户,再次通过系统调用把页面发给内核;
10. 内核进程将页面封装并通过网卡发送出去
11. 当报文到达网卡的时候通过网络响应给客户端

Apache和Nginx比较: