当前位置: > Linux服务器 > apache >

Apache--MPMs && Nginx事件驱动

时间:2016-12-22 13:21来源:linux.it.net.cn 作者:IT

MPM全称是多道处理模块,我们都知道apache是以模块化方式设计的.那么MPM用来决定apache如何处理用户请求的.是通过一个进程处理一个请求,还是一个线程处理一个请求.当前MPM有三种可以选择的方式:

  • prefork

  • worker

  • event

虽然有以上三种方式,但是要注意在任何时间,必须有一个,而且只能有一个MPM被使用.那么下面就介绍一下这三种处理方式的区别.

prefork

在这种工作模型下,apache进程分为master进程跟worker进程.web服务启动就是启动master进程,随之master进程会启动若干个worker子进程. master进程的工作就是管理worker子进程.而worker子进程的工作就是处理用户请求 .当用户发起一个请求,apache就会从空闲的子进程中选择一个处理这个用户请求.

这种处理方式有以下几点好处:

  • 用户不用等到其他进程处理完毕.因为只要有空闲子进程在就可以处理新的请求

  • 如果一个worker子进程崩溃了,不会影响其他worker进程处理请求.

但是worker子进程的个数限制于apache配置文件中如下几个条目的限制

  • MinSpareServers 最少空闲worker进程.

  • MaxSpareServers 最多空闲worker进程,超过这个数,就会有一些空闲worker进程被kill

  • MaxRequestWorkers 同一时刻可以处理的请求数,即并发量

  • MaxConnectionsPerChild 每一个worker子进程一生中可以处理的请求,超过这个数之后就会被master进程kill

同时, 一般master进程使用root用户启动,这样方便master进程监听80端口,以及管理进程.而余下的worker子进程则是以apache配置文件中 User 指令指定的用户启动.这样子是为了减少worker子进程的权限.保证安全.

root@ff1221aa94a9:~# ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   4448   676 ?        Ss   09:33   0:00 /bin/sh -c supervisord -n
root         5  0.0  0.8  60556 17172 ?        S    09:33   0:02 /usr/bin/python /usr/bin/supervisord -n
root        31  0.0  0.1  61384  3160 ?        Ss   09:33   0:00 /usr/sbin/sshd
root        32  0.0  0.8 200164 16384 ?        Ss   09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      33  0.0  0.4 200300  8392 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      34  0.0  0.3 200300  7512 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      35  0.0  0.3 200300  7512 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      36  0.0  0.3 200300  7512 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start
daemon      37  0.0  0.3 200300  7512 ?        S    09:33   0:00 /usr/local/apache/bin/httpd -k start

执行ps可以看出只有一个master进程以root用户方式启动

worker

prefork的缺点很明显,一个worker进程处理一个请求,并发不会高.而且进程占用的资源太多.做的事情却只是处理一个请求.worker针对prefork的问题进行了改进.

  • 仍然有一个master父进程启动若干个子进程

  • 每个子进程启动若干个线程

  • 每个线程处理每个请求

这样子,worker模型的并发性高于prefork模型.并且由于线程的开销小于进程,所以worker模型占用的资源反而小于prefork.

但是worker相对于prefork存在一个问题: 非线程安全 .最典型的一个问题在于:如果你的apache使用了worker模型工作.但是php却使用非线程安全的版本,那么这两者就不能工作了.所以纵然worker有万般好,但是碰到使用非线程安全的历史代码,还是只能乖乖使用prefork模型.

worker模型使用多线程响应请求,这样子存在一个问题,即一个线程崩溃就会影响整个进程.所以worker使用的是多进程+多线程的混合模型.即可以提高并发性,也可以避免一个线程崩溃导致整个整个web站点崩溃.

同prefork一样,worker中子进程跟线程数量也收到apache配置文件的控制.有如下参数

  • MinSpareThreads 最少空闲线程

  • ThreadsPerChild 每个子进程可以创建的线程数量

  • MaxClients 同时可以处理的请求数

  • .....

其web服务调优大抵就是根据服务器配置调节这些参数.具体参数细节可以参考 Apache文档

Event

event模型是在apache2.2之后当做试验特性引入的,在apache2.4之后才正式支持.event模型是为了解决长连接(keep-alive)问题而生的.使用worker模型,一个线程对应一个请求,当一个请求为长连接的时候,线程就会保持当长连接状态,等待客户端的下一个请求.这样子当前线程就不能处理其他客户端请求了.

event模型跟worker模型很像,也是多个进程+多个线程的混合模式,但是event模型下每个进程会有一个单独的线程来管理这些keep-alive类型的线程.当新的请求过来的时候,管理线程会把请求交给其他的空闲线程处理.这样子就避免了每个线程都被keep-alive阻塞.

但是event模型并不是所有情况都通用,在https协议下会退化成worker模型.具体原因可以看 官方文档 .

Nginx

讲到Apache,不得不提起现在Nginx.相比于Apache.Nginx于2004年正式发布.而Apache在1995就已经出现了.当时的web环境还只是简单的展示静态页面,而且并发量远没有现在这么高.所以当时Apache的prefork模型也可以很好的承担web服务需求.加之其稳定性好,没有什么理由不用它.

当时后来互联网渐渐变大,网站的并发量变大,Apache就出现了一个 C10K 的问题.即一个物理服务器达到并发量1W的时候apache就会承受不了.后来2004年Nginx很好的解决了C10K问题.Nginx为何能优于apache解决C10K问题,我们还是得从其处理请求模型说起.

Nginx有三个著名的特性:

  • 事件驱动编程

  • 异步

  • 非IO阻塞

正是这三种编程方式促使Nginx可以有如此高的并发量.下面来分析下Nginx到底是如何工作的.

同样,Nginx的进程也分为master进程跟worker子进程.(其实还有两个cache有关的进程, 这里略过).在启动nginx之后,master进程就会随即创建 一定数量 的worker子进程,并且之后worker子进程数量保持不变.并且这些 worker子进程都是单线程的 .当一个请求到来时,worker进程中某一个空闲进程就会去处理这个请求.乍一看到这里nginx的工作模式跟apache没有什么区别.关键就在于nginx如何处理用户请求.

worker子进程开始处理请求.这个请求可能是访问某个网站的静态页面.而html页面都是保存在硬盘上的.站在操作系统角度来看,nginx是没有办法直接读取硬盘上的文件,必须由nginx告诉操作系统需要读取哪个文件,然后又操作系统去读取这个文件,读取完毕操作系统再交给nginx.也就是说,在操作系统读取文件的时候,nginx是空闲的.如果是apache,那这个时候apache的worker进程/线程就阻塞在这里等待操作系统把文件读取好再交个自己,这种就称之为 IO阻塞 .

但是nginx不一样, nginx的worker进程在这个时候就会注册一个事件,相当于告诉操作系统:你文件读好了跟我说一下,我先去处理其他事情.然后这个worker就可以去处理新的用户请求了.这里nginx的worker进程并没有由于操作系统读取文件而阻塞等待,这种即称之为 非IO阻塞

当操作系统读取好文件之后,就会通知ngixn:我文件帮你读取好了,你过来拿走."操作系统读取好文件"这个事件被触发了,于是Nginx就跑回去把文件拿走,然后返回响应.这种由于某个事件出现触发Nginx执行操作的方式就称为 事件驱动编程 .

我们回顾上面过程,一个用户请求读取文件,nginx把读取文件这个事情通知操作系统之后就去处理下一个用户请求,直到操作系统读取好文件之后再返回响应.这种一个请求还没有处理完毕就去处理下一个请求的编程方式即 异步编程

正是由于nginx这种工作模型,使得nginx在保持一定量的worker进程下,也可以得到相当大的并发量.这点正是nginx优于apache的地方.同样,nginx的这种请求处理模型在处理长连接的时候也可以使用.

Use Both

那么是不是说Nginx一定就优于Apache.Apache就药丸了呢.也不是.一定要记住,一个后来者的出现, 没有在它的前辈所擅长的领域打败它,那么后来者是不可能完全取代前者.很有可能的情况是两者并存.nginx本身并不能处理php,python等脚本语言,只能把这些动态请求通过CGI转发给其他程序处理.所以现在通常的架构是前台Ngixn负责处理静态文件诸如js,css,image文件.而碰到请求php等动态内容.就 在后端多个apache服务器中选择一个比较空闲的服务器 ,把这请求转发给这个服务器处理.等apache处理好之后把返回交给nginx.nginx再返回给用户.这是目前典型的一种设计方案.上面的流程中nginx负责两个功能: 反向代理,负载均衡 .这也是nginx所擅长的两个功能.而apache丰富的模块可以很好的满足一个站点的各种需求.并且经过了20+年的考验,Apache的稳定性也是可以保证的.



(责任编辑:IT)
------分隔线----------------------------