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复用
(7) 信号驱动 IO 模型
具有更多的异步特性,就是调用者不需要主动问被调用者,比如当磁盘文件读取到内核当中时,数据还未得到,但进程仍可继续执行,或者响应其他用户的请求,直到磁盘文件读取到内核当中后,将数据从内核拷贝到用户空间中,但这个过程中需要等待,换句话说就是有一部分实现了异步,一部分仍是同步,意味着信号驱动IO模型将数据分成了一半阻塞不阻塞状态,效率提高了不少,因为将磁盘文件拷贝到内核空间上是最费时间的,而信号驱动IO模型可以将这时间自由分配。
- 信号驱动 IO : signal-driven I/O
- 用户进程可以通过 sigaction系统调用注册一个信号处理程序,然后主程序可以继续向下执行,当有IO操作准备就绪时,由内核通知触发一个 SIGIO信号处理程序执行,然后将用户进程所需要的数据从内核空间拷贝到用户空间
- 此模型的优势在于等待数据报到达期间进程不被阻塞。用户主程序可以继续执行,只要等待来自信号处理函数的通知
- 该模型并不常用
(8)异步 IO 模型
当用户发请求,内核得到请求从磁盘复制到内核,从内核复制到用户空间,用户程序一直在执行,没有堵塞,一直由内核复制数据,递交给应用程序。所以对于进程来讲很轻松,内核做的事更多一点,当然进程做的事越少,他的负担越小,就可以同时做更多的事。
(9)五种 I/O 模型
同步IO模型一直在阻塞,同步非阻塞模型不是完全非阻塞,只是前面的阶段磁盘拷贝到内核不阻塞,但又因为是同步的还是什么都干不了,因为不清楚做没做完,所以一直消耗资源在轮询。IO复用模型都是阻塞的,只不过在前面阶段阻塞在代理select上面,只是换个地方阻塞。而信号驱动模型,前面阶段不阻塞,可以做一些事情。异步IO模型是最理想的,不阻塞。如图越往左越阻塞,越往右越不阻塞。
(10)I/O 模型的具体实现
主要实现方式有以下几种:
- Select : Linux 实现对应, I/O复用模型, BSD4.2 最早实现
- Poll : Linux 实现,对应I/O复用模型, System V unix 最早实现
- Epoll : Linux 实现,对应I/O复用模型,具有信号驱动I/O模型的某些特性
- Kqueue : FreeBSD 实现,对应I/O复用模型,具有信号驱动I/O模型某些特性
- /dev/poll : SUN的 Solaris 实现,对应I/O复用模型,具有信号驱动I/O模型的某些特性
- Iocp Windows 实现 ,对应第5种(异步I/O )模型
(11)select/poll/epoll 区别
epoll :在Linux 2.6内核中提出的 select 和 poll 的增强版本
- 支持水平触发 LT和边缘触发 ET ,最大的特点在于边缘触发,它只告诉进程哪些 fd刚刚变为就需态,并且只会通知一次
- 使用"事件”的就绪通知方式,通过 epoll_ ctl 注册 fd ,一旦该 fd 就绪,内核就会采用类似 callback 的回调机制来激活该 fd , epoll_ wait 便可以收到通知
优点:
- 没有最大并发连接的限制:能打开的 FD 的上限远大于1024(1G的内存能监听约10万个端口)
- 效率提升:非轮询的方式,不会随着 FD 数目的增加而效率下降;只有活跃可用的FD 才会调用callback函数,即 epoll 最大的优点就在于它只管理“活跃"的连接,而跟连接总数无关
- 内存拷贝,利用mmap(Memory Mapping)加速与内核空间的消息传递;即epoll 使用 mmap 减少复制开销
注:mmap 为内存映射
内存映射:
用 nginx 访问磁盘文件,一般情况要发指令给内核,内核跑到磁盘读取数据,数据在磁盘上存放是文件数组方式组织的,要先从磁盘找节点表inode,通过目录一层层找到文件 data,相对效率不高。
所以可以在磁盘划一块空间就是这个文件,然后把这个文件映射到内存空间,假设磁盘是16M,则内存也是16M,让两块区间一个字节一个字节对应,将来要访问文件时就可以直接访问内存里的这块空间提高了效率,如下图,
二、Nginx 介绍
- Nginx:engineX,2002年,开源,商业版
- NGINX是免费,开源,高性能的 HTTP 和反向代理服务器,邮件代理服务器,通用 TCP/UDP 代理服务器
- 解决 C10K 问题( 10K Connections )
- 官网: http://nginx.org
- 二次开发版:
Tengine, OpenResty (章亦春)