• 转:浅谈UNIX下Apache的MPM及httpd.conf配置文件中相关参数配置


    为什么要并发处理

    以Apache为代表的web服务器中,如果不支持并发,则在一个客户端连接的时候,如果该客户端的任务没有处理完,其他连接的客户端将会一直处于等待状态,这事不可想象的,好像没有为什么要不要这一说,是必须有的。

    常用的集中并发处理模式

    • 通过生成多个进程
    • 不通过进程,使用线程
    • 监控输入事件,在事件发生时进行切换处理,即可以使用单线程进行并发处理,这是事件驱动的处理模式

    Apache的并发处理模块

    Apache以模块化的方式组合了多种功能,并发处理的核心部分也是以模块化的方式来出现,通常称为MPM(Multi Processing Module)。根据选择的MDM的不公,用户可以配置不同的并发处理模式。UNIX环境下主要由两个:

    • prefork:提取生成(prefork)多个进程供客户端连接的多进程模式
    • worker:多线程和多进程的混合型模式

    一般是在通过源码编译Apache的时候就通过configure 指令来指定了哪种模式,但是在Red Hat Enterprise Linux 和基于Red Hat的Cent OS Linux 上,同时安装了两种模式,默认使用prefork模式,想切换到worker模式的话,可以在通过/etc/sysconfig/httpd 这个文件来更改,如图: 
    /etc/sysconfig/httpd配置

    prefork 和worker,进程和线程

    prefork是多进程模式,worker是多线程和多进程的混合模式。后者占得内存更小,适合在高并发环境下使用。 
    多线程和多进程的差异:

    • 多个进程中不存在进程间直接共享内存,内存孔氏是独立且安全的
    • 在多线程中,多个线程间共享内存空间,需要注意不能发生资源冲突,这是多线程编程比较复杂的原因。

    优缺点如下:

    • profork:稳定性和向后兼容性较高
    • worker:可扩展性更强

    从性能角度来看下多进程/多线程的差异

    基于以下两点原因后者更轻更快:

    • 多进程使用独立的内存空间,无法共享;而多线程使用共享的内存空间,内存消耗少(其实也不是绝对的,因为写时复制技术,父子进程间也能共享一些内存)
    • 因为多线程共享内存空间,所以线程切换的成本低于多进程

    下面解释两个概念:写时复制和上下文切换

    写时复制

    写时复制和进程间的通信有点像,进程间通信原理图: 
    虚拟内存示意图 
    当某个进程需要内存是,像内核申请,内核返回给进程一个内存地址,这个地址不是实际的物理内存地址,而是虚拟内存,映射的是实际的物理内存地址,存再多个进程映射同一块物理内存这种可能,这就实现了进程间的通信,写时复制的示意图如下: 
    写时复制示意图 
    /proc/<pid>/smaps文件

    上下文切换

    什么是上下文切换:在多任务操作系统中,一个逻辑cpu不可能真正的实时处理多个请求,必须轮着来,这就是上下文切换,可以通过sar -c命令来查询。

    httpd.conf 中两个模式相关参数说明

    在centos上查看httpd.conf的配置如下:

    [root@localhost www]# cat /etc/httpd/conf/httpd.conf | grep -v "#"
    
    
    ServerTokens OS
    
    ServerRoot "/etc/httpd"
    
    PidFile run/httpd.pid
    
    Timeout 60
    
    KeepAlive Off
    
    MaxKeepAliveRequests 100
    
    KeepAliveTimeout 15
    
    
    <IfModule prefork.c>
    StartServers       8
    MinSpareServers    5
    MaxSpareServers   20
    ServerLimit      256     #服务器数量,即进程数的上限,一般配置两个值相同
    
    MaxClients       256     #这个值比较关键,能同时连接客户端数量的上限
    
    MaxRequestsPerChild  4000 #这里设置的是,每个进程处理4000个请求,该进程处理完第4000个请求后会自动结束,通过合理配置这个参数,可以避免使用mod_perl和mod_php模块运行的应用程序引起的内存泄露。在会接收到大量请求的大型服务器中,如果这个参数配置的值太小,就就会频繁的重复进行进程的建立和结束。因为基于写时复制的内存共享,共享率会越来越低,最终会导致大部分内存将被持续挤占而不能共享,必须根据实际情况合理设置该值。
    
    </IfModule>
    
    ##这是工作在work模式下的配置,work模式是多进程和多线程的混合型模式
    
    <IfModule worker.c>
    StartServers         4
    MaxClients         300
    MinSpareThreads     25
    MaxSpareThreads     75
    ThreadsPerChild     25
    MaxRequestsPerChild  0
    </IfModule>
    
    Listen 80
    #以下配置省略......

    profork模式

    在profork模式中配置比较简单,只关注 Server和MaxClients这两个参数即可,一般配置二者相等。

    如何来设定这两个值呢?

    一般根据服务器的物理可用内存和每个进程平均消耗的内存来确定。物理内存可用用free等指令查看,那么怎么看每个进程占用的内存大小呢,通过ps和top命令能得到部分信息,但是从/proc文件系统可以看的更详细,一般在/proc/< pid >/status这个文件中看进程的内存使用详情。如下:

    linux-qvvt:/var/log # ps -ef | grep httpd
    
    root       2188      1  0 14:04 ?        00:00:00 /usr/sbin/httpd2-prefork -f /etc/apache2/httpd.conf -DZABBIX -D SYSTEMD -DFOREGROUND -k start
    wwwrun     2915   2188  0 14:04 ?        00:00:00 /usr/sbin/httpd2-prefork -f /etc/apache2/httpd.conf -DZABBIX -D SYSTEMD -DFOREGROUND -k start
    wwwrun     2916   2188  0 14:04 ?        00:00:00 /usr/sbin/httpd2-prefork -f /etc/apache2/httpd.conf -DZABBIX -D SYSTEMD -DFOREGROUND -k start
    wwwrun     2919   2188  0 14:04 ?        00:00:01 /usr/sbin/httpd2-prefork -f /etc/apache2/httpd.conf -DZABBIX -D SYSTEMD -DFOREGROUND -k start
    wwwrun     2920   2188  0 14:04 ?        00:00:01 /usr/sbin/httpd2-prefork -f /etc/apache2/httpd.conf -DZABBIX -D SYSTEMD -DFOREGROUND -k start
    wwwrun     2921   2188  0 14:04 ?        00:00:01 /usr/sbin/httpd2-prefork -f /etc/apache2/httpd.conf -DZABBIX -D SYSTEMD -DFOREGROUND -k start
    wwwrun     3151   2188  0 14:07 ?        00:00:00 /usr/sbin/httpd2-prefork -f /etc/apache2/httpd.conf -DZABBIX -D SYSTEMD -DFOREGROUND -k start
    root       8442   2936  0 14:52 pts/0    00:00:00 grep httpd
    linux-qvvt:/var/log # more /proc/2915/status
    Name:     httpd2-prefork
    State:     S (sleeping)
    Tgid:     2915
    Pid:     2915
    PPid:     2188
    TracerPid:     0
    Uid:     30     30     30     30
    Gid:     8     8     8     8
    FDSize:     64
    Groups:     8
    VmPeak:       182972 kB
    VmSize:       181688 kB
    VmLck:            0 kB
    VmPin:            0 kB
    VmHWM:        17840 kB     #实际使用物理内存的大小
    VmRSS:        16732 kB
    VmData:        11064 kB
    VmStk:          136 kB
    VmExe:          528 kB
    VmLib:        21616 kB
    VmPTE:          348 kB
    VmSwap:            0 kB
    Threads:     1
    SigQ:     0/3679
    SigPnd:     0000000000000000
    ShdPnd:     0000000000000000
    SigBlk:     0000000000000000
    SigIgn:     0000000001001000
    SigCgt:     000000018c0046eb
    CapInh:     0000000000000000
    CapPrm:     0000000000000000
    CapEff:     0000000000000000
    CapBnd:     0000001fffffffff
    Seccomp:     0
    Cpus_allowed:     ffffffff,ffffffff,ffffffff,ffffffff
    Cpus_allowed_list:     0-127
    Mems_allowed:     00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,
    00000000,00000000,00000001
    Mems_allowed_list:     0
    voluntary_ctxt_switches:     258
    nonvoluntary_ctxt_switches:     1195在这个例子中,实际使用了17.4M的内存,要多看几个例子,得出一个平均值值,如果内存为4GB,则留给操作系统1GB,剩余3GB,3×1024/18=1723 ,考虑到父进程和子进程间还共享了一部分内存还可以给的宽裕点。

    还有一个参数如 MaxRequestsPerChild 4000 ,这里设置的是,每个进程处理4000个请求,该进程处理完第4000个请求后会自动结束,通过合理配置这个参数,可以避免使用mod_perl和mod_php模块运行的应用程序引起的内存泄露。在会接收到大量请求的大型服务器中,如果这个参数配置的值太小,就就会频繁的重复进行进程的建立和结束。因为基于写时复制的内存共享,共享率会越来越低,最终会导致大部分内存将被持续挤占而不能共享,必须根据实际情况合理设置该值。

    worker模式

    worker模式下多进程+多线程组合的方式。

    • 生成多个进程
    • 在一个进程中生成多个线程,一个客户端的请求交由一个线程进行处理

    因此支持的并发数为:进程数 x 每个进程的线程数;因此进程数可以像profork模式进行优化,在优化线程数的时候考虑两个点:

    • 线程共享全部内存空间,不用考虑写时复制的情况
    • 每个线程最大不能超过8M 的内存做为栈空间

    因此有下面几个参数:

    • MaxClients : 最大连接数,即进程数*线程数
    • ServerLimit : 最大进程数
    • ThreadLimit: 每个进程的最大线程数
    • TheadPerChild: 每个进程的最大线程数,和ThreadLimit基本相同

    一般先确定 MaxClients再确定TheadPerChild后就可以确定ServerLimit了,如下面这个配置,StartServers=MaxClients / MaxSpareThreads 
    StartServers 4 
    MaxClients 300 
    MinSpareThreads 25 
    MaxSpareThreads 75 
    ThreadsPerChild 25 
    MaxRequestsPerChild 0 
    要看系统中运行了多少线程,在ps 命令上加上 -L参数就可以看了。

    最后,系统超载的情况下,修改MaxClients需要了解

    当业务比较繁忙的时候,在服务器应用日志中可能会报MaxClient有关的错误,并提示要求调整这个参数,有的时候这只是个表象,当一个请求过来后将输出提交给ap服务器处理,ap服务器提交数据库查询,然后这个请求一直等待输出数据库的返回结果,当数据库查询较慢或者数据库hang住的时候,该进程/线程也是会表现为阻塞的状态,长时间得不到释放,当后面同样的请求过来后,同样被阻塞,这样服务器不断生成新的线程/进程,而之前的进程/线程因为等待输出,得不到释放,最终会导致达到最大进程/进程数,导致服务器报错。

    原文地址:http://blog.csdn.net/x6_9x/article/details/50098019

  • 相关阅读:
    Delphi Try Except 实例
    如何有效地让一个“ParentFont = False”子控件使用与父母相同的字体名称?
    WPF的本质:数据和行为
    WPF-触发器
    WPF TextBox 验证输入
    wpf数据绑定更新通知
    asp.net *.ashx类型的文件使用说明
    asp.net 定时间点执行任务的简易解决办法
    asp.net 页面延时五秒,跳转到另外的页面
    Asp.net 基于Cookie简易的权限判断
  • 原文地址:https://www.cnblogs.com/zjhblogs/p/5970429.html
Copyright © 2020-2023  润新知