开发者学堂课程【Linux Web 服务器 Nginx 搭建与配置:nginx 介绍及安装】学习笔记,与课程紧密联系,让用户快速学习知识.
课程地址:https://developer.aliyun.com/learning/course/579/detail/7987
nginx 介绍及安装
内容介绍
一、I/O 模型
二、Nginx 介绍
一、I/O 模型
(1)Httpd MPM
httpd MPM :
- prefork :进程模型,两级结构,一个主进程 master 负责若干个生成子进程,每个子
进程负责响应一个请求。
- worker :线程模型,三级结构,主进程 master 负责生成子进程,每个子进程负责生
成多个线程, 当用户发起请求,由每个线程响应一个请求。
- event :线程模型,三级结构,主进程 master 负责生成子进程,
一个监控线程,回收未被利用的线程,每个子进程响应多个请求。
httpd 的程序非常稳定,相对来讲在一些传统的公司用web服务的话很多都是httpd,但是对于互联网公司来讲,往往会产生一些不胜任的情况,比方说当并发量达到比较大的时候,连接数过万的时候,其性能就会急剧下降,nginx 据说可以应付达到三万以上的并发,主要取决于 IO 模型
(2)I/O 介绍
I/O:
网络 IO : 本质是 socket 读取。对网络上的数据进行传输的时候,他本质上也算是一种IO,因为在网络编程的时候,实现的socket通讯之间无非也是读和写的机制,在 Linux 之中,一切皆文件,所以你在网络中发送文件的时候是发送到 socked 文件中,通过 socked 转发到远程程序,也是用 socked 接收。
磁盘 IO :
每次IO ,都要经由两个阶段:
第一步:将数据从磁盘文件先加载至内核内存空间(缓冲区) ,等待数据准备完成,时间较长
第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短
一般情况下的通讯过程:
当服务器收到远程通信 http 的请求,希望得到一个 html 文件,那这个请求会到达网卡,nginx 线程接收收到请求。而 index 文件在物理磁盘上,nginx 是一个进程是工作在用户空间的,用户空间的进程是不能返回硬件的,发请求到kernel,所以需要通过 kernel 去访问磁盘,由 kernel 获取到 kernel 缓冲区,再复制到 nginx 缓冲区,来实现数据最终的得到获取,
如下图
(3) I/O 模型
同步/异步:关注的是消息通信机制
同步: synchronous ,调用者等待被调用者返回消息,才能继续执行
异步: asynchronous ,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态
阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态
阻塞: blocking ,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起
非阻塞: nonblocking ,指IO操作被调用后立即返回给用户一个状态值 , 无需等到IO操作彻底完成,最终的调用结果返回之前,调用者不会被挂起
I/O 模型:
阻塞型、非阻塞型、复用型、信号驱动型、异步
(4) 同步阻塞IO模型
同步阻塞IO模型是最简单的IO模型,用户线程在内核进行IO操作时被阻塞
用户线程通过系统调用 read 发起 IO 读操作,由用户空间转到内核空间。内核等到数据包到达后,然后将接收的数据拷贝到用户空间,完成 read 操作
用户需要等待read将数据读取到 buffer 后 ,才继续处理接收的数据。整个IO请求的过程中,用户线程是被阻塞的,这导致用户在发起IO请求时,不能做任何事情,对 CPU 的资源利用率不够
在实际工作中内核和用户进程那个效率高,相对影响用户体验,通常来讲,用户是访问应用程序的,不是访问内核的,内核是为应用程序提供服务的所以希望应用程序访问更快,用户感受更好,话句话说一件事是应用程序做还是内核做,如果应用程序做的事多了,自然对用户响应请求就更慢了,内核多做点减轻了应用程序的事那对用户响应请求就更快,延申出来希望内核做的事多一些,应用程序少做一些,这样应用程序就可以接收更多的用户请求。
(5) 同步非阻塞 IO 模型
同步的意思是去访问一个资源,事情做没做完不清楚,只有自己去看。所以当要得到一个资源的时候,发一个请求由内核来完成,内核系统调用recvfrom来完成,但是是否已完成并不知道,所以只能一次次的系统调用去问,非阻塞意味着进程发一个指令给内核,希望他得到一个数据,还可以干点别的事但又由于是同步,不清楚对方做好准备没有,一直问直到数据从磁盘放到内核为止,等一会将数据从内核拷贝到用户空间,才通知整个结束。
在磁盘文件复制到内核过程中,用户是并不了解的,他只有不断的轮询。
用户线程发起IO请求时立即返回。但并未读取到任何数据,用户线程需要不断地发起IO请求,直到数据到达后,才真正读取到数据,继续执行。即"轮询”机制
整个IO请求的过程中,虽然用户线程每次发起IO请求后可以立即返回,但是为了等到数据,仍需要不断地轮询、重复请求,消耗了大量的 CPU 的资源
是比较浪费 CPU 的方式,一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性
(6) I/O 多路复用模型
不用每个进程都要和内核打交道,直接找一个专门的代理select,但进程会受阻与select,发出请求到内核,等待数据从内核复制到用户空间,将数据分成了两部分,第一个阶段是用户进程阻塞在select,第二个阶段是用户进程等待数据从内核空间复制用户空间。实际上也是总阻塞状态。虽然总体性能未提高,但有select可以面对很多用户的请求。
多个连接共用一个等待机制,本模型会阻塞进程,但是进程是阻塞在 select 或者 poll 这两个系统调用上,而不是阻塞在真正的 IO 操作上
用户首先将需要进行 IO 操作添加到 select 中,继续执行做其他的工作(异步) , 同时等待 select 系统调用返回。当数据到达时, IO 被激活,select 函数返回。用户线程正式发起 read 请求,读取数据并继续执行。
从流程上来看,使用 select 函数进行 IO 请求和同步阻塞模型没有太大的区别,甚至还多了添加监视 IO ,以吸调用 select 函数的额外操作,效率更差。并且阻塞了两次,但是第一次阻塞在 select 上时, select 可以监控多个IO上是否已有IO操作准备就绪,即可达到在同一个线程内同时处理多个IO请求的目的。而不像阻塞IO那种,一次只能监控一个IO
虽然上述方式允许单线程内处理多个IO请求,但是每个IO请求的过程还是阻塞的(在select函数上阻塞) , 平均时间甚至比同步阻塞IO模型还要长。如果用户线程只是注册自己需要的IO请求,然后去做自己的事情,等到数据到来时再进行处理,则可以提高 CPU 的利用率
IO多路复用是最常使用的IO模型,但是其异步程度还不够“彻底”, 因它使用了会阻塞线程的select系统调用。因此IO多路复用只能称为异步阻塞IO模型,而非真正的异步IO
多路 I/O 复用
IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,就通知该进程
IO多路复用适用如下场合 :
当客户端处理多个描述符时( -般是交互式输入和网络套接口) , 必须使用I/O复用
当一个客户端同时处理多个套接字,多个请求时,此情况可能的但很少出现
当一个 TCP 服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到I/O复用
当一个服务器即要处理 TCP ,又要处理 UDP,一般要使用I/O复用
当一个服务器要处理多个服务或多个协议,一般要使用I/O复用