httpd 服务器的三大引擎 prefork、worker、event分析

简介:

概述:

     httpd 2.2之前(2.2也包含在内),不支持动态切换MPM。且在编译时候,只能指定使用哪种MPM。如果,提供了 prefork、worker、event ,要改变MPM,只能在启动httpd服务器程序的时候,指定使用:

1
2
3
   /usr/sbin/httpd
   /usr/sbin/httpd .event
   /usr/sbin/httpd .worker

中的那一个二进制程序。

     httpd 2.4就支持动态切换MPM,在配置文件中使用【LoadModule】指令就可以实现MPM的切换了。条件:我们编译httpd时,要把:prefork、worker、event都编译成模块。

一、httpd服务器工作在 prefork 模型是一个进程服务响应一个用户请求

 启动httpd服务

1
2
3
[root@stu13 httpd-2.4] # ./bin/apachectl start
[root@stu13 httpd-2.4] # pstree | grep httpd
      |-httpd---5*[httpd]

查看httpd服务器工作的MPM是什么?

1
2
[root@stu13 httpd-2.4] # ./bin/httpd -M | grep mpm
  mpm_prefork_module (shared)

说明:

    从【pstree】命令的显示结果,可以看到启动httpd服务器时就启动5个httpd服务进程用来准备接收web请求。

    当然这5个进程都是由会话领导进程(该进程的所有者是root管理员)fork()而来。主进程管理子进程,如:回收子进程、创建子进程等。而响应用户访问请求的则是子进程。

    当用户向httpd服务器,发起访问资源连接请求的时候,

httpd服务器会根据<IfModule mpm_prefork_module>指令定义的参数维护进程池中的进程。

当用户向httpd服务器发起连接请求的时候,httpd的主进程就会从进程池中派一个子进程来负责响应用户的请求,如果该服务器的并发请求量为100的话,一下子就使用完,进程池中空闲进程数(我们定义了进程池中最小空闲进程数为5),90个用户的连接请求只好等待。这时主进程fork()出子进程,然后才能响应处于等待90个用户的连接请求。虽然是一个进程负责响应一个用户的请求,当该进程完成了用户的请求之后,会话领导进程并不会马上kill掉该进程。而是使用了重用的机制。意思是在进程的生命周期内它响应完负责的用户请求后,还可以响应后续的用户请求。这是为了减少消耗在创建进程上面的时间。实现快速地响应用户请求的一种机制。假如过了一会,我们的httpd服务器已经处理完这100个并发用户的请求了。根据后续用户的并发用户数目有三种情况:

(1)、后续的并发用户数小于10的话:

     领导会话进程,为了响应这100个并发请求的用户,而fork()出的子进程,除了用来响应后面的

     用户连接请求的进程之外,其它空闲进程统统被kill掉。只保留一定数目的空闲进程。如最小空      闲进程数为:5( MinSpareServers          5)、最大空闲进程数为:10(MaxSpareServers         10)

(2)、后续的并发用户数大于10而小于150的话:

     响应100个并发用户连接请求的进程都得到了重用,但由于在处理过程中进程要不断申请和释放      内存,次数(处理用户的请求次数)多了就会造成一些内存垃圾,就会影响系统的稳定性且影响了

     系统的有效利用,所以会话进程的生命周期是有限的,会话管理进程要kill掉一些进程。而在进

     程的生命周期内,能够处理的用户请求数量是可以

     设置的。httpd 2.2 版本和httpd 2.4版本的设置如下:

1
2
      httpd 2.2     MaxRequestsPerChild    4000
      httpd 2.4     MaxConnectionsPerChild   0

 所以,领导进程fork()子进程是难免的。意思是说:消耗在创建进程和销毁进程中的时间是难免的。

     如果,我们的服务器性能很好的话,可以增加进程可以处理的用户请求的数量,但是可能会影响

     系统的稳定,产生一些内存垃圾。但是减少了fork()进程和kill进程的时间。在一定的程序上,

     提高了响应用户连接请求的速度。

     如果,不调整进程的生命周期内可以处理多少个用户的连接请求数的话,就要花费大量的时间

     (如果我们的服务器比较繁忙的话)fork()进程,kill进程.会在一定程度上影响响应用户请求的

     速度的。

(3)、后续的并发用户请求数大于150的话;

     有可能会出现,有可能会出现连接请求超时的情况。如果我们的接收连接的缓存不够大的话,

     有些用户的请求连接都无法接收下来。不管服务器是否能够处理,都应该把请求接收下来再说。我们可以调大该缓存:

1
2
3
4
5
6
      [root@stu13 ~] # cat /proc/sys/net/ipv4/tcp_mem
      46368   61824   92736
      [root@stu13 ~] # cat /proc/sys/net/ipv4/tcp_rmem
      4096    87380   1978368
      [root@stu13 ~] # cat /proc/sys/net/ipv4/tcp_wmem
      4096    16384   1978368

 当然,如果服务器的性能很好的话,我们可以调大处理的并发用户数量,httpd 2.2 与 httpd 2.4中定义如下:

1
2
     httpd 2.2     MaxClients             300  
     httpd 2.4     MaxRequestWorkers      150

    但是,如果调大了并发用户数(服务器的性能条件下),虽然一次性可以处理的用户请求数增加了,但是在服务器上进程的切换的次数也增加了。因为进程的切换是浪费CPU时间周期的。所以,我们要为服务器定做一个黄金比例。既能处理更多的用户并发请求,浪费在进程间切换的时间又很合理。

prefork模型的配置如下:

1
2
3
4
5
6
7
<IfModule mpm_prefork_module>
     StartServers             5      服务器启动时就fork()出5个进程,等待用户连接请求
     MinSpareServers          5      服务器在等待客户端连接请求的最小空闲进程数。
     MaxSpareServers         10      服务器在等待客户端连接请求的最大空闲进程数。
     MaxRequestWorkers      150      允许最大的用户并发请求数。
     MaxConnectionsPerChild   0      在进程的生命周期内,它可以服务多少个请求。
< /IfModule >

httpd服务器刚启动没有接收客户端连接请求时候,所占据常驻物理内存大小为

1
2
3
4
5
6
7
8
9
10
11
[root@stu13 ~]. /test/test .sh
Date: 2014 /08/10_16 :30:05
user     pid     vsz      rss       comm
root     19506   5252     2196     httpd
daemon   19507   5252     1684     httpd
daemon   19508   5252     1684     httpd
daemon   19509   5252     1684     httpd
daemon   19510   5252     1684     httpd
daemon   19511   5252     1684     httpd
--------------------total_Rss---------------------
10616

说明:

    httpd服务器所有进程占据的常驻物理内存集约为:10M.


2、对该httpd进行压力测试,并发用户数为:100,共发起3000个请求。暂停2秒。共测试40次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[root@stu13 httpd-2.4] # declare -i num=40
[root@stu13 httpd-2.4] # while [ "$num" -gt 0 ]; do ab -c 100 -n 3000 http://192.168.60.99/index.html; sleep 2 ; let num--; done
.....
Date: 2014 /08/10_16 :33:02
user     pid     vsz      rss       comm
root     19506   5252     2216     httpd
daemon   19509   5384     2264     httpd
daemon   20311   5384     2244     httpd
daemon   20459   5384     2244     httpd
daemon   20519   5384     2244     httpd
daemon   20555   5384     2244     httpd
daemon   20615   5384     2244     httpd
daemon   20856   5384     2244     httpd
daemon   20944   5384     2244     httpd
daemon   21036   5384     2244     httpd
daemon   21089   5384     2244     httpd
--------------------total_Rss---------------------
24676
 
Date: 2014 /08/10_16 :33:03
user     pid     vsz      rss       comm
root     19506   5252     2216     httpd
daemon   19509   5384     2264     httpd
daemon   20311   5384     2244     httpd
daemon   20459   5384     2244     httpd
daemon   20519   5384     2244     httpd
daemon   20555   5384     2244     httpd
daemon   20615   5384     2244     httpd
daemon   20856   5384     2244     httpd
daemon   20944   5384     2244     httpd
daemon   21036   5384     2244     httpd
daemon   21089   5384     2244     httpd
--------------------total_Rss---------------------
24676

说明:

   进行压力测试后,httpd服务器常驻内存集大小为:24675,约为:24M.

prefork模式,使用一个进程服务一个用户请求。由于进程打开的资源是独享,如果,用户访问的资源相同也要打开多次的。但是,比较稳定的。

   由于prefork模型的,服务用户请求的会话进程要不断创建、销毁。也就是进程号PID不断发生变化,所以很难做到把会话进程绑定在CPU上(使用进程号做绑定)。如果我们的服务器,有多颗CUP的话,可以使用指定的CPU处理中断请求。

    prefork 工作模式,负责监听/响应的是主进程(属主为root的httpd会话领导进程)是基于 select/poll 实现网络IO利复的。这样服务器就可以实现并发了。但由于 select/poll本身的局限性,理论上并发能力上限为:1024。

二、worker 工作模型是

    一个线程服务一个用户的连接请求。线程比进程更轻量级,创建和消耗的速度比进程的创建和消耗要快得多。线程之间还可以共享资源,如:打开的文件描述符等。这样如果:两个客户端请求的是同一个文件,就不需要从磁盘上加载两次了,速度要比基于进程的响应速度快。但线程的管理要比进程复杂得多。线程之间很多资源是共享的,所以它没有prefork模型,一个进程服务一个服务请求那么安全稳定。况且,linux不是真线程的操作系统,worker 与 prefork 这两种模型,在linux上的表现几乎都一样。通常使用prefork模型。windows 是真线程的操作系统,它对线程的支持就很好。

 启动httpd服务器

1
2
3
[root@stu13 httpd-2.4] # ./bin/apachectl start
[root@stu13 httpd-2.4] # pstree | grep httpd
      |-httpd---2*[httpd---26*[{httpd}]]

查看当前httpd服务器使用的MPM是什么?

1
2
[root@stu13 httpd-2.4] # ./bin/httpd -M | grep mpm
  mpm_worker_module (shared)

说明:

    从【pstree】的显示结果可以看出,httpd服务器刚起动就创建了2个子进程,且这2个子进程又创建了25个线程用来等待服务客户端的连接请求的。刚启动httpd服务器时(没有接收客户端连接请求),

worker 的模型如下:分析评估应用,可以调节下述的参数来调节httpd服务器的并发能力的。

1
2
3
4
5
6
7
8
9
10
<IfModule mpm_worker_module>
     StartServers             2         服务器刚启动的时候就启动两个进程,这两个进程共生
                                         成25个线程用来等待客户端的连接请求的。
     MinSpareThreads         25         最少保持25个线程处于空闲状态
     MaxSpareThreads         75         最多保持75个纯程处于空闲状态
     ThreadsPerChild         25         每个进程最多允许生成25个线程
     MaxRequestWorkers      150         并发数为150
     MaxConnectionsPerChild   0         在线程的生命周期内,
                                         线程允许服务的客户端连接的个数。
< /IfModule >

1、httpd服务器刚启动没有接收客户端连接请求时候,所占据常驻物理内存大小为

1
2
3
4
5
6
7
8
[root@stu13 ~]. /test/test .sh
Date: 2014 /08/10_16 :40:34
user     pid     vsz      rss       comm
root     23955   5428     2372     httpd
daemon   23956   283160   2092     httpd
daemon   23957   283160   2096     httpd
--------------------total_Rss---------------------
6560

2、对该httpd进行压力测试,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@stu13 httpd-2.4] # declare -i num=40
[root@stu13 httpd-2.4] # while [ "$num" -gt 0 ]; do ab -c 100 -n 3000 http://192.168.60.99/index.html; sleep 2 ; let num--; done
.....
Date: 2014 /08/10_16 :59:37
user     pid     vsz      rss       comm
root     28920   5428     2384     httpd
daemon   28921   285476   3740     httpd
daemon   28922   285476   3752     httpd
daemon   29110   285476   3720     httpd
daemon   30774   285476   3712     httpd
--------------------total_Rss---------------------
17308
 
Date: 2014 /08/10_16 :59:38
user     pid     vsz      rss       comm
root     28920   5428     2384     httpd
daemon   28921   285476   3740     httpd
daemon   28922   285476   3752     httpd
daemon   29110   285476   3720     httpd
--------------------total_Rss---------------------
13596

说明:

    因为,线程池中定义了,每个进程最多可以生成25个线程, 假如:此时,httpd服务器共有4个进程,每个进程都产生了25个线程,4个进程都满负荷运转了,

    但是,还是有很多用户在等待,这时候主进程(会话领导进程),又会fork()出进程,子进程又生成线程来服务客户端的连接请求的。进程的线程在不断服务连接请求,会不断申请内存释放内存,次数多了,难免会产生内存垃圾的。影响系统的稳定。所以,httpd服务器要不断使用新的进程替换老的进程。、


三、event:

   是基于信号驱动I/O 通知机制。工作方式是:使用每线程服务N个用户请求。event的工作模型要优于prefork和worker.

启动httpd服务

1
2
3
[root@stu13 httpd-2.4] # ./bin/apachectl start
[root@stu13 httpd-2.4] # pstree | grep httpd
      |-httpd---2*[httpd---26*[{httpd}]]

1、查看 httpd服务器的工用模型

1
2
[root@stu13 httpd-2.4] # ./bin/httpd  -M | grep mpm
  mpm_event_module (shared)

httpd服务器工作在event模式下线程池的控制。也worker的线程池很相似,但event的工作方式是:一个线程服务N个用户请求。

1
2
3
4
5
6
7
8
9
<IfModule mpm_event_module>
     StartServers             2         服务器启动的时候就生成2个子进程,
                                        该子进程共生成25个线程等待客户端的连接请求
     MinSpareThreads         25         线程池中保持最少25个空闲线程。
     MaxSpareThreads         75         线程池中保持最多75个空闲线程。
     ThreadsPerChild         25         每个进程最多可以生成25个线程。
     MaxRequestWorkers      150         最大并发用户数为:150
     MaxConnectionsPerChild   0          线程能够服务的用户请求数据。 0 表示不做限定。
< /IfModule >

httpd服务器没有服务用户请求时,所占据常驻物理集大小为

1
2
3
4
5
6
7
8
[root@stu13 ~] # test/test.sh
Date: 2014 /08/10_17 :04:58
user     pid     vsz      rss       comm
root     30948   5436     2352     httpd
daemon   30949   283168   2084     httpd
daemon   30950   283168   2088     httpd
--------------------total_Rss---------------------
6524

2、对该httpd进行压力测试,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@stu13 httpd-2.4] # declare -i num=40
[root@stu13 httpd-2.4] # while [ "$num" -gt 0 ]; do ab -c 100 -n 3000 http://192.168.60.99/index.html; sleep 2 ; let num--; done
.....
Date: 2014 /08/10_17 :08:26
user     pid     vsz      rss       comm
root     30948   5436     2352     httpd
daemon   30949   287172   6076     httpd
daemon   30950   288372   6704     httpd
--------------------total_Rss---------------------
15132
 
Date: 2014 /08/10_17 :08:27
user     pid     vsz      rss       comm
root     30948   5436     2352     httpd
daemon   30949   287172   6076     httpd
daemon   30950   288372   6704     httpd
--------------------total_Rss---------------------
15132

说明:

    通过并发测试后,进程的进程号并没有改变。则工作在 worker模型下的,压力测试后,进程号已经发生了改变。

    event 和 worker的线程池的配置都一样,由于 event 是基于信号驱动I/O 通知机制,每个进程可以服务N个用户请求。

    而worker是一个线程服务一个请求。在请求没有完成之前,该线程是与它服务的请求绑定的。

worker需要大量的创建进程生成线程,销毁线程,杀死进程的过程。而event则不需要频繁的创建销毁。







     本文转自成长的小虫 51CTO博客,原文链接:http://blog.51cto.com/9528du/1539109,如需转载请自行联系原作者


相关文章
|
4月前
|
机器学习/深度学习 弹性计算 缓存
阿里云服务器经济型e实例与通用算力型u1实例对比分析与选择指南
在阿里云服务器的实例规格中,经济型e实例和通用算力型u1实例是很多个人和普通企业级用户常见的选择,经济型e实例与通用算力型u1实例的主要区别在于性能、应用场景及价格策略。本文将详细对比这两种实例的性能、应用场景及价格策略,以供参考。
|
4月前
|
域名解析 弹性计算 缓存
阿里云国际云服务器全局流量分析功能详细介绍
阿里云国际云服务器全局流量分析功能详细介绍
|
4月前
|
弹性计算 安全 Linux
阿里云国际版ECS云服务器ping不通的原因分析
阿里云国际版ECS云服务器ping不通的原因分析
|
4月前
|
存储 数据采集 分布式计算
Hadoop-17 Flume 介绍与环境配置 实机云服务器测试 分布式日志信息收集 海量数据 实时采集引擎 Source Channel Sink 串行复制负载均衡
Hadoop-17 Flume 介绍与环境配置 实机云服务器测试 分布式日志信息收集 海量数据 实时采集引擎 Source Channel Sink 串行复制负载均衡
83 1
|
4月前
|
人工智能 运维 Kubernetes
87cloud案例分析:阿里云国际服务器如何支持在线教育
87cloud案例分析:阿里云国际服务器如何支持在线教育
|
5月前
|
存储 安全 算法
服务器数据恢复—Raid磁盘阵列的安全性分析及常见故障
出于尽可能避免数据灾难的设计初衷,RAID解决了3个问题:容量问题、IO性能问题、存储安全(冗余)问题。从数据恢复的角度讨论RAID的存储安全问题。 常见的起到存储安全作用的RAID方案有RAID1、RAID5及其变形。基本设计思路是相似的:当部分数据异常时,可通过特定算法将数据还原出来。以RAID5为例:如果要记录两个数字,可以通过再多记录这两个数字的和来达到记录冗余性的目的。例如记录3和5,同时再记录这2个数字的和8。在不记得到底是几和5的情况下,只需要用8-5就可以算出这个丢失的数字了,其余情况依此类推。
|
6月前
|
前端开发 大数据 数据库
🔥大数据洪流下的决战:JSF 表格组件如何做到毫秒级响应?揭秘背后的性能魔法!💪
【8月更文挑战第31天】在 Web 应用中,表格组件常用于展示和操作数据,但在大数据量下性能会成瓶颈。本文介绍在 JavaServer Faces(JSF)中优化表格组件的方法,包括数据处理、分页及懒加载等技术。通过后端分页或懒加载按需加载数据,减少不必要的数据加载和优化数据库查询,并利用缓存机制减少数据库访问次数,从而提高表格组件的响应速度和整体性能。掌握这些最佳实践对开发高性能 JSF 应用至关重要。
90 0
|
6月前
|
存储 设计模式 运维
Angular遇上Azure Functions:探索无服务器架构下的开发实践——从在线投票系统案例深入分析前端与后端的协同工作
【8月更文挑战第31天】在现代软件开发中,无服务器架构因可扩展性和成本效益而备受青睐。本文通过构建一个在线投票应用,介绍如何结合Angular前端框架与Azure Functions后端服务,快速搭建高效、可扩展的应用系统。Angular提供响应式编程和组件化能力,适合构建动态用户界面;Azure Functions则简化了后端逻辑处理与数据存储。通过具体示例代码,详细展示了从设置Azure Functions到整合Angular前端的全过程,帮助开发者轻松上手无服务器应用开发。
48 0
|
7月前
|
前端开发 JavaScript Java
文本----简单编写文章的方法(中),后端接口的编写,自己编写好页面就上传到自己的服务器上,使用富文本编辑器进行编辑,想写好一个项目,先分析一下需求,再理一下实现思路,再搞几层,配好参数校验,lomb
文本----简单编写文章的方法(中),后端接口的编写,自己编写好页面就上传到自己的服务器上,使用富文本编辑器进行编辑,想写好一个项目,先分析一下需求,再理一下实现思路,再搞几层,配好参数校验,lomb
|
8月前
|
监控 关系型数据库 MySQL

热门文章

最新文章