xiao9469 发表于 2023-4-21 19:21:11

Apache运行模式MPM详解

一、理论概述
Web服务器Apache目前一共有三种稳定的MPM(Multi-Processing Module,多线程处理模块)模式。
Prefork:进程模式
Worker :线程模式
Event : 事件模式 (2.4版本开始稳定使用)
Prefork运行模式详解:
1、Prefork MPM :Prefork MPM实现了一个非线程的、预派生的Web服务器。它在Apache启动之初,就先预派生一些子进程,然后等待连接;可以减少频繁创建和销毁进程的开销,每个子进程只有一个线程,在一个时间点内,只能处理一个请求,这是一个成熟稳定,可以兼容新老模块,也不需要担心线程安全问题,但是一个进程相对占用资源,消耗大量内存,不擅长处理高并发的场景。
最重要的是将MaxRequestWorkers设置为一个足够大的数值以处理潜在的请求高峰,同时又不能太大,以致需要使用的内存超出物理内存的大小。
注:Prefork 是基于多进程的模式
优点:因为每个进程使用独立的内存空间,所以比较安全,一个进程坏了,不会影响其他进程。
缺点:占用的内存比较大。

如果在预编译的时候没有指定MPM的模式,默认使用的是Prefork模式。
# vim /etc/httpd/httpd.conf
https://img-blog.csdnimg.cn/20200929171056416.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70

如图上所示:在Apache的配置文件中,可以看出使用的是MPM的哪个模式,我的Apache在预编译的时候,使用参数让Apache三种模式都支持,但指定了使用Event模式,所以这里Event行前的#是被取消掉的!!!

2、Worker MPM:和Prefork模式相比,worker使用了多进程和多线程的混合模式,worker模式也同样会先预派生一些子进程,然后每个子进程创建一些线程,同时包括一些监听线程,每个请求过来会被分配到一个线程来服务。线程比起进程来更轻量,因为线程是通过共享父进程的内存空间,因此,内存的占用会减少一些,在高并发的场景下会比Prefork有更多可用的线程,表现会更优秀一些,另外,如果一个线程出了问题也会导致同一个进程下的线程出现问题,如果是多个线程出现问题,也只是影响Apache的一部分,而不是全部,由于用到多进程多线程,需要考虑到线程的安全了,在使用Keep-alive长连接的时候,某个线程会一直被占用,即使中间没有请求需要等待到超时才会被释放(该问题在Prefork模式下也存在)。

注:Worker MPM
优点:可以处理海量请求,而系统资源的开销小。原因:一个进程中包括多个线程,多个线程之间可以共享内存,所以占用的内存资源比较少。
缺点:不太安全,如果一个线程坏了,整个进程都要坏了,另外存在Keep-alive长连接占用资源时间过长。
   如何避免进程中某个线程坏了?一个进程中所有线程完成一定数量的请求后,自动关闭,再重新打开,就可以避免内存溢出等问题。
不管是Worker模式还是Prefork模式,Apache总是试图保持一些备用的(Spare)或者是空闲的子进程(空闲的服务线程池),用于接受客户端即将到来的请求,这样客户端就不需要再等到服务前等候子进程的产生。

3、 Event MPM :event模式是在2.4版本中才稳定发布的模式,这就是Apache最新的工作模式,他和worker模式很像,不同的是在于它解决了Keep-alive长连接的时候占用线程资源被浪费的问题,在event工作模式中,会有一些专门的线程用来管理这些Keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务器的线程,执行完毕后,又允许它释放,这增强了在高并发场景下的请求处理。
    当某个连接没有请求时,会主动关闭连接,在Worker模式下,必须要等Keep-alive超时,才可以释放。

在./configure配置编译参数的时候,可以使用 --with-mpm=prefork | worker | event 来指定编译为哪一种MPM,当然也可以用编译为三种都成 --enable-mpms-shared=all,这样在编译的时候会在modules目录下自动编译出三个MPM文件的so,然后通过修改httpd.conf配置文件更改MPM。
https://img-blog.csdnimg.cn/2020092917443519.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70


4、查看当前使用的是那种MPM
# /usr/local/apache/bin/apachectl -M | grep event    #可以查看到使用的是什么模式
mpm_event_module (shared)                        
也可以使用:/usr/local/apache/bin/apachectl -V    查看MPM ; 如下;
https://img-blog.csdnimg.cn/20200929180736417.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70

使用:/usr/local/apache/bin/httpd -M | grep event   和    /usr/local/apache/bin/httpd -V和上述是一样的效果;
总结:

RHEL6/7系统自带的apache默认采用的是Prefork进程模式,在编译apache源码时,如果不用--with-mpm显式指定某种MPM,Prefork就是缺省的MPM;
HTTP 2.4 新特性:
1)MPM支持在运行时装载
指定启用:
--enable-mpms-shared=all--with-mpm=event      ##把所有支持的MPM都编译出来,但启用默认的是event
2)支持event   2.2版本也支持,只不过是测试版本
3)异步读写
4)在每模块及每目录上指定日志级别
5)每请求配置;<If> <Elseif>
6)增强版的表达式分析器
7)毫秒级的keepalive timeout,使用ms指定为毫秒
8) 支持主机名的虚拟主机不在需要NameVirtualHost指令
9)支持使用自定义变量
新增一些模块:mod_proxy_fcgi(基于fcgi方式调用执行环境)
       mod_ratelimit (用于做速率限定)
       mod_request (对请求方法做限定)
       mod_remoteip (对远端IP做限定)
对于基于IP的访问做了修改,不在使用order,allow,deny这些机制;而是统一使用require进行调整MPM模块则直接修改主配置文件中的LoadModule指定即可。

二、优化部分
1、对Prefork模块进行设置,修改apache的httpd-mpm.conf配置
# cd /etc/httpd/extra/
# mv /etc/httpd/extra/httpd-mpm.conf ./httpd-mpm.conf.bak
# egrep -v "#|^$" ./httpd-mpm.conf.bak > ./httpd-mpm.conf
#
先将http-mpm.conf 中的注释行和空行过滤掉
https://img-blog.csdnimg.cn/20201006101029104.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70
注释:
StartServers    5         在初始化的时候打开5个进程
MinSpareServers5         最少有5个备用空闲进程
MaxSpareServers10      最多10个备用空闲进程
MaxRequestWorkers   250   Apache最大的处理并发请求是250个
MaxConnectionsPerChild   0   这个一般不用,

添加:
ServerLimit   250      该参数是最大的进程数,由于Prefork模式进程和线程是一对一的,所以最大请求并发得和最大进程数相等。

针对于Prefork中参数数值的调整,还是需要根据实际情况(服务器性能,业务需求)来进行调整:
如果做5000个并发的Web,需要多少内存?5000*2M/0.8/1024=12.2G,服务器大概需要14G——16G内存,
ServerLimit的大小,取决于你系统的资源,每个Apache进程默认大约占用2M内存,基本可以按照这个工时来计算,最大内存*80%/2M=ServerLimit      (一个进程正常是1.6-1.7M,上述使用2M作为计算的)。

根据上面的描述,修改参数如下:
https://img-blog.csdnimg.cn/20201006103204233.png
注释:MaxRequestsPerChild1000#每个子进程可以支持的请求数,累计到1000。会重启进程。存在长连接的话,一个长连接只能算一个。这可以设置为0,因为一个进程关闭,所有的线程也都关了。

额外参数:
MaxKeepAliveRequests 200      # 限制KeepAlive长链接最大处理200个请求。

目前用的MPM是Event,修改Apache配置文件,调整位Prefork:
https://img-blog.csdnimg.cn/20201006103730252.png
修改为:
https://img-blog.csdnimg.cn/20201006103747786.png

重新启动Apache之后发现,Apache预派生进程数变成5个:
https://img-blog.csdnimg.cn/20201006104057716.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70
注释:
5个预派生进程是Prefork默认的,Apache没有去读取我们修改过的http.mpm.conf文件。
https://img-blog.csdnimg.cn/20201006105233198.png
在配置文件中,将该行的注释取消掉。

重启Apache查看预派生的进程数如下:
https://img-blog.csdnimg.cn/20201006105334620.png
查看到httpd进程数52个,多的两个。一个是我们grep抓取时候的进程,还有一个是httpd的主进程。
一般对于数值的设定,够用就行。
https://img-blog.csdnimg.cn/20201006112604225.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70
如上:进程中第六列是每个进程占用我们资源大小,1536K。

# ps -aux | grep httpd | awk '{sum += $6; n++};END{print sum/n}'
1546.46
#

使用awk进行第六列自加。算出总量1546.46K。1M=1024K
比如:内存2G   20%的内存留给系统使用,最大可以处理多少Apache并发;
内存2G - 400M =1600M/1.5M = 1100并发数;然后根据实际计算,修改Prefork_module参数;

watch   命令用于动态的观察Apache的最大连接数:
watch -n 1 "pgrep httpd | wc -l"
https://img-blog.csdnimg.cn/20201006113729212.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70

使用ab来进行测压:
# yum install -y httpd-devel      #ab是httpd-devel提供的,ab是最简单的测压工具
https://img-blog.csdnimg.cn/20201006115553936.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70
https://img-blog.csdnimg.cn/20201006115527312.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70

通过ab命令测试以及配合watch可以动态查看到进程数量的变化;等请求完成之后,进程数量不断减少至52;

2、对worker模块进行设置,修改apache的httpd-mpm.conf配置
worker比prefork内存资源使用少很多,适用于高并发,缺点就是一个线程崩掉了,整个进程就崩掉了,稳定性不如prefork。
修改Apache配置文件,将Prefork注释掉,启用worder;
https://img-blog.csdnimg.cn/20201006121316173.png

重新启动Apache;
查看目前使用的MPM模块:如下
https://img-blog.csdnimg.cn/20201006121520853.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70

查看预派生进程数是不是变成worker默认的三个:如下
https://img-blog.csdnimg.cn/20201006121801713.png

修改httpd.mpm.conf配置文件:如下(生产环境最常用的)
https://img-blog.csdnimg.cn/20201006123919348.png
注释:
ServerLimit         64   最大的进程数限制
StartServers    5            最初建立的子进程
MinSpareThreads   25   最小空闲线程数
MaxSpareThreads   500   最大空闲线程数
ThreadsPerChild   150   每个进程包括150个线程数
ThreadLimit         200       一个进程下最大的线程数限制
MaxRequestWorkers   9600   表示Apache最多同时处理9600的并发请求,超过的进入队列等待;9600是64*150得到的;
此服务器配置:最多进程数:64个,最多线程数(最大并发数)64*150=9600,不可以超过64*200=12800
然后保存配置 ,重启Apache,即可生效;

案例:
如果MaxRequestsPerChild    30000这样配置会有什么结果?
结果:一但到30000次请求 , 那150个线程都关了,会出大量闪断情况。

3、Event模式,了解以下即可;
https://img-blog.csdnimg.cn/20201006130241461.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTg5NDI0NQ==,size_16,color_FFFFFF,t_70

总结:
Apache httpd 能更好的为有特殊要求的站点定制。例如,要求 更高伸缩性的站点可以选择使用线程的 MPM,即 worker 或 event; 需要可靠性或者与旧软件兼容的站点可以使用 prefork

源文地址:https://blog.csdn.net/weixin_45894245/article/details/108869963
页: [1]
查看完整版本: Apache运行模式MPM详解

创宇盾启航版免费网站防御网站加速服务