Nginx实践总结简介篇
一:简介
nginx [engine x]是Igor Sysoev编写的一个HTTP和反向代理服务器,另外它也可以作为邮件代理服务器。它已经在众多流量很大的俄罗斯网站上使用了很长时间,这些网站包括Yandex、Mail.Ru、VKontakte,以及Rambler。据Netcraft统计,在2012年8月份,世界上最繁忙的网站中有11.48%使用Nginx作为其服务器或者代理服务器。部分成功案例请见:Netflix,Wordpress.com,FastMail.FM。(摘自官方文档)
二:为什么Nginx这么多人使用?
在设计的最初阶段,nginx的主要着眼点就是其高性能以及对物理计算资源的高密度利用,因此其采用了不同的架构模型。受启发于多种操作系统设计中基于“事件”的高级处理机制,nginx采用了模块化、事件驱动、异步、单线程及非阻塞的架构,并大量采用了多路复用及事件通知机制。在nginx中,连接请求由为数不多的几个仅包含一个线程的进程worker以高效的回环(run-loop)机制进行处理,而每个worker可以并行处理数千个的并发连接及请求。维持10000个非活动的HTTP keep-alive 连接用掉了2.5MB内存因此Nginx因为其高并发低消耗的特点,并且还支持缓存反向代理加速和负载均衡等,得到了广泛的使用。
三:Nginx为什么这么快?
说到Nginx为什么这么快,消耗这么低,很多人都可以说上几点,什么支持epoll模型啊,什么支持缓存啊,等等。但是究其本质很少有人弄清究竟为什么使用了epoll模型就很快,为什么支持事件驱动,为什么支持非阻塞的架构就快。下面我从几个方面的探究Nginx为如此快
I/O模型好:
1. 阻塞I/O模型
进程调用recvfrom系统调用的时候,就会一直等待数据从内核空间拷贝至用户空间结束,在此过程中进程一直处于阻塞状态,直到数据处理完成。这种模型下一个进程处理一个连接,稳定,但是效率低下。
注:这里简单介绍网络中的数据传输机制,当网络中有数据达到本地机器的时候,先是到达网卡缓冲区,接着网卡会通知内核接受数据,内核会去网卡缓冲区拷贝数据至内核的缓冲区,这个阶段是非常快的,等数据准备好了,内核就会将数据从内核缓冲区拷贝至用户空间进行处理,至此数据处理完成。
2.非阻塞I/O模型
进程调用recvfrom系统调用来接收数据后便一段时间就去询问下内核是否有数据到来,此时CPU处于忙等状态,直到数据准备就绪,进程便转为阻塞状态进行数据的拷贝。这种模型下,如果没有数据胡总数据不可读便立即通知进程,防止进程被阻塞,最大的好处便是一个进程可以同时处理多个I/O请求。但是需要不断的询问I/O状态是CPU处于忙碌状态。
3.I/O复用模型
进程调用select系统调用等待数据准备就绪,等数据准备好了内核就会改变相应的标志位表示数据可读,进程会不断去扫描文件描述符查看是否有数据准备就绪,I/O复用模型可以帮我们很快获得数据是否就绪,这让进程可以同时接受多个I/O请求,并且高效的活动哪些请求数据已经准备就绪,数据准备就绪后进程任然需要阻塞的等待数据拷贝完成。
相比于非阻塞I/O模型,I/O复用模型可以更高效的得知哪些请求数据就绪,
4.信号驱动I/O模型
进程将请求接入后建立SIGIO的信号处理程序后,进程便可以继续运行,等待数据报准备好后就立即通知进程数据准备好了等待进行数据的拷贝,这种SIGIN信号通知方式效率很高在2.4内核下这种通知方式应该应该是性能做好的I/O多路就绪通知方法,但是基于SIGIO的通知是一次性的,也就死只通知一次,这种通知方法我们称之为边缘触发,和select模型不一样的是,select是水平触发,进程每次去读取数据就绪位直到数据全部拷贝完成后。SIGIO虽然性能很好,但是也存在一些问题,事件过期和事件丢失等问题,换句话就是说不稳定,容易产生请求丢失。
5.异步I/O模型
进程在整个过程中都是异步的,讲请求接入后,进程可以继续接入其他请求,数据拷贝完成后,内核会通知进程,进程就会继续处理后续的报文封装等后续操作,性能特别好。
看到了上面五种I/O模型好,我想大家应该清楚了,Nginx是属于那种I/O模型了,Apache是属于select模型,但是早起select模型最大支持1024个请求,所以poll模型对select模型进行了改进,让其可以支持更多的并发连接数。然后Nginx支持epoll模型,epoll模型并不是真正的异步I/O模型,epoll模型只是一种基于事件驱动的I/O复用模型,Nginx在好像在RHEL6.0后才开始支持真正的异步IO叫做AIO。可以在编译的时候加上--with-aio。epoll模型算是2.6内核下性能最好的I/O多路就绪通知方法了。
这里我还是引用网上的一则故事来解释下epoll模型:
比如你去逛街,逛着逛着有点饿了,这时你看到商场里小吃城,就去一个小吃店买了一碗面条,
交了钱,可面条做起来需要时间,你也不知道什么时候做好,没办法,只好坐在那等。这就是阻塞型IO
如果你不甘心在这坐着等想去逛逛街,于是你一边跑出去玩,一段时间你又跑回来看看面条有没有做好,虽然最后吃到面条了但是自己累死了这就是非阻塞型IO,假如你不止买了面条还买了饺子,粥,等,这些东西都需要时间来做,如果你轮流不停你看各个小吃店有没有做好,那就痛苦不堪了,于是引入了I/O复用(又称多路I/O就绪通知),小吃城管理处给大厅安装了一块电子屏幕,以后所有小吃店的食物做好后,都会显示在屏幕上,这样你就可以同时逛逛附件的商店,在不远处也可以看到大屏幕.(这个救赎select/poll模型),虽然有了电子屏幕,但是显示的内容是所有餐品的状态,包括正在制作的和已经做好的,这显然给你造成阅读上的麻烦,并且一旦你走的比较远了,就还得花时间走到小吃城去看电子屏幕,于是小吃城这次采用了手机短信通知的方法,你只需要到小吃城注册后便可以在就餐点就绪时及时收到短信通知,这就是类似于epoll机制
直接I/O:
通常对于磁盘文件的访问显示从磁盘读取数据至内核缓冲区,再从内核缓冲区读取数据至用户空间,如多下次访问的时候在内核缓冲区中存在则不需要读取磁盘,提高了访问的速度,然后Nginx本身提供了丰富的缓存机制,所以可以使用直接I/O不使用内核缓冲减少CPU和内存的开销
支持sendfile机制:
sendfile,sendfile64:
通常对于一个web访问请求,首先请求报文达到网卡的缓冲区,接着从网卡缓冲区送到内核缓冲区最后送到用户空间,接着会去从磁盘读取所需文件,从磁盘读取文件至内核缓冲区再拷贝至用户空间,如果是静态文件,用户空间不需要处理则又拷贝至内核空间再拷贝至网卡发送缓冲区进行发送,一个小小的访问请求需要多次用户空间和内核空间的上下文切换,非常耗费资源,从磁盘读取数据至内核区如果数据不需要处理的话可以不送往用户空间,直接发送至网卡发送缓冲区的机制就叫做seddfile机制,这需要在内核空间提供一个khttp内核级web服务器,用于封装http报文进行发送.目的在于减少用户空间和内核空间的上下文切换.
最后我们从服务器并发策略的角度来分析下Nginx为何如此快:
一个进程处理一个连接:
Apache的prefork模型,这种策略使得对于进程的创建和撤销开销非常大,但是进程直接的独立性又是的这种策略更加稳定,但是并发程度不高,开销大.
一个线程处理一个连接:
这个也就是Apache的work模型,这种模型下,线程的创建和撤销对于资源的消耗是很少的.并且进程内部的多个线程可以共享内存空间,共享一些打开的文件描述符等,并且维持一个长连接的话线程的开销明显小于进程,但是随着线程数增多,线程之间会产生资源竞争。加大CPU开销,同时,线程模型也不够稳定,一个线程奔溃了影响到整个进程。linux本身对线程的支持也不是原生的。并且同样存在上下文的切换频繁。
一个线程处理多个连接:
减少了上下文切换的次数,减少了系统开销,这也是Nginx采用的并发策略。再配合Nginx的CPU绑定,就要更一步的减少了上下文切换的次数。
优良的并发策略,正在的异步I/O模型,sendfile 直接I/O等优良的技术。促使Nginx成为了目前比较主流的web服务器,多用于反向代理。Apache因为其丰富的模块和优良的稳定性市场占用率仍然位居第一。Apache2.4中也同样引入了epoll机制。但是还没做到AIO。
四:Nginx安装脚步
#Nginx安装 #!/bin/bash useradd -s /sbin/nologin -M www yum groupinstall "Dvelopment Tools" -y yum install openssl-devel pcre-devel -y wget http://nginx.org/download/nginx-1.4.5.tar.gz tar zxvf nginx-1.4.5.tar.gz cd nginx-1.4.5 ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module --with-pcre --with-http_realip_module make && make install