MPM全称是多道处理模块,我们都知道apache是以模块化方式设计的.那么MPM用来决定apache如何处理用户请求的.是通过一个进程处理一个请求,还是一个线程处理一个请求.当前MPM有三种可以选择的方式:
虽然有以上三种方式,但是要注意在任何时间,必须有一个,而且只能有一个MPM被使用.那么下面就介绍一下这三种处理方式的区别. prefork在这种工作模型下,apache进程分为master进程跟worker进程.web服务启动就是启动master进程,随之master进程会启动若干个worker子进程. master进程的工作就是管理worker子进程.而worker子进程的工作就是处理用户请求 .当用户发起一个请求,apache就会从空闲的子进程中选择一个处理这个用户请求. 这种处理方式有以下几点好处:
但是worker子进程的个数限制于apache配置文件中如下几个条目的限制
同时, 一般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用户方式启动 workerprefork的缺点很明显,一个worker进程处理一个请求,并发不会高.而且进程占用的资源太多.做的事情却只是处理一个请求.worker针对prefork的问题进行了改进.
这样子,worker模型的并发性高于prefork模型.并且由于线程的开销小于进程,所以worker模型占用的资源反而小于prefork. 但是worker相对于prefork存在一个问题: 非线程安全 .最典型的一个问题在于:如果你的apache使用了worker模型工作.但是php却使用非线程安全的版本,那么这两者就不能工作了.所以纵然worker有万般好,但是碰到使用非线程安全的历史代码,还是只能乖乖使用prefork模型. worker模型使用多线程响应请求,这样子存在一个问题,即一个线程崩溃就会影响整个进程.所以worker使用的是多进程+多线程的混合模型.即可以提高并发性,也可以避免一个线程崩溃导致整个整个web站点崩溃. 同prefork一样,worker中子进程跟线程数量也收到apache配置文件的控制.有如下参数
其web服务调优大抵就是根据服务器配置调节这些参数.具体参数细节可以参考 Apache文档 Eventevent模型是在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有三个著名的特性:
正是这三种编程方式促使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) |