文章目录
linux云计算架构-Apache高级调优【运行模式、rewrite模块】
1. Apache运行模式介绍
web服务器apache共有3种稳定的MPM(multi-processing module
,多进程处理模块)。prefork(进程模式)
、worker(线程模式)
、event(事件模式)
。
在configure配置编译参数时,可以使用--with-mpm=prefork|worker|event
或者--enable-mpms-shared=all
配置支持MPM。
可以通过以下两种方式查看主机的apache是配置的哪种运行模式,源码安装的apache2.4.46
自带的是worker
,yum安装的apache
自带的是prefork
。
源码查看:
yum安装查看:
①prefork:实现了一个非线程的、多进程的、预派生的web服务器。在apache启动时,会预派生一些子进程,然后等待连接,可以减少频繁创建和销毁进程带来的开销。每个子进程只有一个线程,在某个时刻,只能处理一个请求。由于进程相对占用资源,消耗大量内存,不适用于高并发场景。将maxClients
设置为一个足够大的数值以处理潜在请求高峰,但不能设置太大,导致需要使用的内存超过物理内存。在apache2.4版本以后,默认的MPM为worker。
优点:每个进程使用独立的内存空间,当某个进程坏了,不影响其他进程,较安全。
缺点:占用内存较大
②worker:使用了多进程和多线程混合模式,当apache启动时,主进程会预派生一些子进程,每个子进程又创建一些线程,其中包括一个监听线程,一个线程处理一个请求。由于线程是共享父进程的内存空间,所以比起进程更轻量。当一个线程出了问题,只会影响同一父进程下的其他线程,而不会影响到其他进程下的线程,即影响到的仅仅是部分。当使用keepalive长连接时,线程会被占用一定时间,即使中间没有请求,也需要等待到超时才会被释放。
优点:可以处理海量请求,系统资源开销小。
缺点:当一个线程故障,整个进程都会故障。存在keepalive长连接占用资源时间过长的问题。
当一个进程中所有线程完成一定数量的请求后,自动关闭线程,再重新打开线程。【如一个线程完成10000个请求后,线程自动关闭再重新打开。】
prefork和worker运行模式的共同点:都会提前派生子进程用来处理即将到来的请求,这样当客户端发起请求时,就不需要等待子进程的产生。
③event:该运行模式在2.4版本后稳定运行,是目前apache最新的工作模式。该工作模式相较于worker,解决了keepalive长连接占用线程资源导致资源浪费的问题。在event模式下,有一些专门的线程用来管理keepalive类型的线程,当有请求时,会将请求传递给服务器的线程,执行完毕后,当该连接没有新的请求时,会主动关闭连接。
综上,在生产中,若要求有更高伸缩性和支持高并发,可以使用worker或event模式。若需要可靠安全或与旧软件兼容的站点,可以使用prefork。

2. prefork模式优化
# 将apache运行模式切换为prefork
[root@server ~]# vim /usr/local/apache/conf/httpd.conf
66 LoadModule mpm_prefork_module modules/mod_mpm_prefork.so # 去除注释
67 #LoadModule mpm_worker_module modules/mod_mpm_worker.so # 加上注释
[root@server ~]# /etc/init.d/apache restart
[root@server ~]# /usr/local/apache/bin/httpd -M | grep mpm
mpm_prefork_module (shared)
prefork模式优化:
# 启用httpd-mpm.conf配置
[root@server ~]# vim /usr/local/apache/conf/httpd.conf
464 # Server-pool management (MPM specific)
465 Include conf/extra/httpd-mpm.conf
# mpm具体配置
[root@server ~]# vim /usr/local/apache/conf/extra/httpd-mpm.conf
28 <IfModule mpm_prefork_module>
29 StartServers 5 # 启动apache时创建的服务进程数
30 MinSpareServers 5 # 最小空闲进程数
31 MaxSpareServers 10 # 最大空闲进程数
32 MaxRequestWorkers 250 # 最大并发进程数
33 MaxConnectionsPerChild 0 # 最大连接限制数,0为不限制。
34 </IfModule>
prefork调优的几点解读:
①MinSpareServers:若当前空闲子进程数(没有正在处理请求的子进程)少于MinSpareServers,apache会以每秒2的n-1次方诞生子进程,直到MinSpareServers的值大于等于5,这些空闲的子进程用来应对即将到来的请求。
②MaxSpareServers:若当前空闲的子进程数多余MaxSpareServers,apache会杀死多余的子进程,使得当前空闲子进程小于等于MaxSpareServers。
③一般MinSpareServers和MaxSpareServers的值不宜设置过大,较多的空闲子进程会占用内存资源,一般设置为最大并发的十分之一。
④MaxRequestWorkers:最大同时处理请求的进程数,也是最大同时连接数,表示最大请求并发能力,超过该值的请求,将进行排队。
⑤MaxConnectionsPerChild:在一个进程的生命周期内,处理的最大请求数,处理的请求达到这个数值后,会终止进程,当进程处理完最后的请求,进程将自动被杀死。【若开启keepalive长连接,在一次连接中即使有多个请求,也只算一次请求。】
⑥将MaxConnectionsPerChild值设置非0,可以防止内存泄露无限进行,从而耗尽内存。给进程一个有限寿命,有助于当服务器负载减轻时减少活动进程的数量。
3. worker模式优化
44 <IfModule mpm_worker_module>
45 StartServers 3 # 启动时apache产生的进程数
46 MinSpareThreads 75 # 最小空闲线程数
47 MaxSpareThreads 250 # 最大空闲线程数
48 ThreadsPerChild 25 # 每个进程可以启动的线程数
49 MaxRequestWorkers 400 # 所有线程数量的的最大值,通常表示可以同时处理的请求数。
50 MaxConnectionsPerChild 0 # 最大连接数限制
51 </IfModule>
worker调优几点解读:
①MinSpareThreads:基于整个服务器监视的最小空闲线程数,若空闲线程小于设定值,apache会自动创建线程,若服务器负载较大,可以加大该值。
②MaxSpareThreads:基于整个服务器监视的最大空闲进程数,若空闲进程大于设定值,apache会自动杀死多余的进程,若服务器负载较大,可以加大改值。
③ThreadsPerChild:每个进程包含的线程数,若并发量较大,可以加大此值。影响较大,慎重使用。
④MaxRequestWorkers:所有线程数量的最大值,一般为web服务器的最大并发值,必须是ThreadsPerChild的整数倍。【MaxRequestWorkers = StartServers * ThreadsPerChild
】
# event模式配置与worker模式配置一致。
# event模式解决了keepalive长连接导致空闲进程过多,占用内存资源过多的问题
61 <IfModule mpm_event_module>
62 StartServers 3
63 MinSpareThreads 75
64 MaxSpareThreads 250
65 ThreadsPerChild 25
66 MaxRequestWorkers 400
67 MaxConnectionsPerChild 0
68 </IfModule>
4. 常见worker模式配置实战:
①子进程数由StartServers
的值决定
②查看每个apache子进程占用的内存数
# apache所有进程占用的内存数
[root@server ~]# ps aux | grep httpd | awk '{print $6}'
2936
4204
4208
4192
984
# apache子进程占用的内存数
[root@server ~]# ps aux | grep httpd | grep daemon | awk '{print $6}'
4204
4208
4192
# apache进程占用的总内存
[root@server ~]# ps aux | grep httpd | awk '{sum += $6;n++};END{print sum}'
16524
# apache子进程占用的总内存
[root@server ~]# ps aux | grep httpd | grep daemon | awk '{sum += $6;n++};END{print sum}'
12604
# apache进程占用的平均内存
[root@server ~]# ps aux | grep httpd | awk '{sum += $6;n++};END{print sum/n}'
3304
# apache子进程占用的平均内存
[root@server ~]# ps aux | grep httpd | grep daemon | awk '{sum += $6;n++};END{print sum/n}'
4201.33
子进程使用的总内存大概12.31M。这是apache子进程占用的初始内存大小。随着服务器上线,apache进程处理的web请求的增加,每个进程使用的内存也会增加,建议上线一天后查看apache进程占用的内存数。
通过apache每个进程所需内存大小,可以计算apache需要的总内存。
③cpu核心数和内存比例配置
服务器类型 | cpu核心数 | 内存大小 | cpu核心数:内存大小 |
---|---|---|---|
通用型服务器 | 8核 | 32G | 1:4 |
计算型服务器 | 8核 | 16G | 1:2 |
内存型服务器 | 8核 | 64G | 1:8 |
了解了以上内容,下面来看两个实战:
生产场景1:一台服务器,16核心cpu,64G内存,apache最大可以设置多少个work子进程,即多少个子进程,或者说StartServers的值最大是多少?
关于内存分配,系统使用和apache使用占比如下:
内存总量 | 系统使用 | apache使用 | 系统使用占比 |
---|---|---|---|
8G | 2G | 6G | 1/4 |
16G | 4G | 12G | 1/4 |
32G | 8G | 24G | 1/4 |
64G | 8G | 56G | 1/8 |
一般来说,系统使用8G内存就足够了。
在本案例中,64G内存,可以提供给apache使用的应该是56G。为了方便计算,不妨假设当服务器上线后,每个work子进程需要使用内存56M,故最大work子进程数为:56*1024/56=1024个。即StartServers的值最大是1024。
# 修改worker mpm配置
[root@server ~]# vim /usr/local/apache/conf/extra/httpd-mpm.conf
<IfModule mpm_worker_module>
StartServers 1024
MinSpareThreads 750
MaxSpareThreads 2500
ThreadsPerChild 250
MaxRequestWorkers 25000
MaxConnectionsPerChild 250000
</IfModule>
==========================以下检测还是使用worker运行模式默认值=====================
==========================修改了worker运行模式的参数值,也可以使用以下方法监控=======
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
# 重启服务后,持续监控
# pgrep = ps + grep
[root@server ~]# pgrep httpd | wc -l
4
# 查看apaceh最大连接数,每1秒刷新一次
[root@server ~]# watch -n 1 "pgrep httpd | wc -l"
# ab压测
[root@server ~]# ab -n 10000 -c 100 http://192.168.8.138/index.html
# 可以看到进程数为7,子进程数由3变为了6。
# 这说明要处理10000个请求,预派生的3个子进程已经不够用了,第1秒1个子进程,第二秒1个子进程。故总共有3+1+2=6个子进程。
# 第1秒产生多一个子进程,此时为4个,每个子进程最大产生25个线程,故总共有100个线程,此时的最大并发请求应该是100。
# 而压测的并发请求就是100,故4个子进程无法稳定处理100个并发请求。
# 故需要第2秒产生多2个子进程,此时为6个子进程,总共有150个线程,才能稳定的处理100个并发请求。
[root@server extra]# ps aux | grep httpd
root 6894 0.0 0.1 76996 2964 ? Ss 07:33 0:00 /usr/local/apache/bin/httpd -k start
daemon 8148 0.0 0.3 1547692 6100 ? Sl 07:45 0:01 /usr/local/apache/bin/httpd -k start
daemon 8149 0.0 0.3 1744300 6096 ? Sl 07:45 0:01 /usr/local/apache/bin/httpd -k start
daemon 8150 0.0 0.3 1678764 6128 ? Sl 07:45 0:01 /usr/local/apache/bin/httpd -k start
daemon 9350 0.5 0.3 1678764 6132 ? Sl 08:30 0:00 /usr/local/apache/bin/httpd -k start
daemon 9382 0.0 0.3 1547692 6060 ? Sl 08:30 0:00 /usr/local/apache/bin/httpd -k start
daemon 9383 0.0 0.3 1613228 6072 ? Sl 08:30 0:00 /usr/local/apache/bin/httpd -k start
root 9609 0.0 0.0 112728 988 pts/0 S+ 08:32 0:00 grep --color=auto httpd
[root@server extra]# pgrep httpd | wc -l
7
生产场景2:一台服务器,8核心cpu,32G物理内存,apache要达到2000并发,worker模式的参数应该怎么配置?
# 根据内存分配,apache可以使用的内存应该24G。
# StartServers一般可以设置为CPU核心数或者2倍CPU核心数。
<IfModule mpm_worker_module>
StartServers 16
MinSpareThreads 75 # 假设最小并发是25,该值为最小并发的3倍。
MaxSpareThreads 1250 # 假设最大并发为2500,该值为最大并发的一半
ThreadsPerChild 125 # 子进程数为16,要完成2000的并发,每个子进程应该产生2000/16=125个线程。可以通过调大子进程数来增加并发值。
MaxRequestWorkers 2000 # 所有线程数量的最大值,也称最大并发值。
MaxConnectionsPerChild 12500 # 最大连接数限制。每个子进程处理12500个请求,平均下来每个线程处理100个请求,处理完12500个请求,该进程自动终止并关闭。这么做是为了预防线程处理太多的请求,出现内存溢出,导致进程崩溃。
</IfModule>
5. Rewrite 规则使用
rewrite
的功能是为了实现URL的跳转,也称为重定向,其正则表达式是基于perl语言的。
为了使用该模块,可以在configure编译时增加参数--enable-rewrite
安装该模块。也可以通过DSO模式
安装动态安装。
在rewrite模块使用方面,可以基于服务器设置(httpd.conf) 也可以基于目录设置(.htaccess) 重定向的范围。
若基于服务器的设置,需要修改httpd.conf文件,在全局或者局部,或者每个virtualhost虚拟主机下,添加RewriteEngine on
开启重定向rewrite功能。
# 在configure编译时加入了rewrite模块,但是还是没有安装上去。需要修改配置httpd.conf
[root@server ~]# /usr/local/apache/bin/apachectl -M | grep rewrite
[root@server ~]# vim /usr/local/apache/conf/httpd.conf
158 LoadModule rewrite_module modules/mod_rewrite.so
[root@server ~]# /etc/init.d/apache restart
[root@server ~]# /usr/local/apache/bin/apachectl -M | grep rewrite
rewrite_module (shared)
以下介绍两个使用rewrite模块的案例:
案例1:当访问的主机名不是以www.abong.com或192.168.8.138为前缀的,都跳转到www.abong.com。
[root@server ~]# vim /usr/local/apache/conf/httpd.conf
RewriteEngine on # 开启rewrite重定向功能
RewriteCond %{
HTTP_HOST} !^www.abong.com [NC] # 访问的主机不是以www.abong.com前缀的
RewriteCond %{
HTTP_HOST} !^192.168.8.138 [NC] # 访问的主机不是以192.168.8.138前缀的
RewriteCond %{
HTTP_HOST} !^$ # 访问的主机不是空地址
RewriteRule ^/(.*) http://www.abong.com/ [L] # 满足以上RewriteCond条件的请求,都直接跳转到http://www.abong.com/
[root@server ~]# /etc/init.d/apache graceful # 重新加载apache配置文件,不停服务。
[root@server ~]# vim /etc/hosts # 配置本地域名解析
192.168.8.138 www.abong.com
192.168.8.138 bbs.abong.com
192.168.8.138 www.abong.cn
192.168.8.138 bbs.abong.cn
打开本地浏览器进行测试:
通过以上测试结果,可以看到192.168.8.138
虽然对应了4个域名,但访问不是www.abong.com
的域名,都会被重定向到www.abong.com
。
案例2:当访问www.abong.com时,自动跳转到www.jd.com
[root@server ~]# vim /usr/local/apache/conf/httpd.conf
RewriteEngine on
RewriteCond %{
HTTP_HOST} ^www.abong.com [NC]
RewriteRule ^/(.*) http://www.jd.com/ [L]
[root@server ~]# /etc/init.d/apache graceful
[root@server ~]# vim /etc/hosts
192.168.8.138 www.abong.com
192.168.8.138 www.jd.com
经过以上两个案例,可以看出,rewrite模块的主要功能是实现URL的跳转。
想要了解更多apache rewrite模块的内容,可以查看官网信息。
http://httpd.apache.org/docs/current/mod/mod_rewrite.html
6. apache防盗链配置
apache防盗链设置,实际上即是使用rewrite模块,当请求主机名不是限定的部分时,会跳转到指定内容。
RewriteEngine on
RewriteCond %{
HTTP_REFERER} !^http://www.abong.com/data$
RewriteCond %{
HTTP_REFERER} !^http://www.abong.com/data/.*$
RewriteCond %{
HTTP_REFERER} !^http://www.abong.com/data2$
RewriteCond %{
HTTP_REFERER} !^http://www.abong.com/data2/.*$
RewriteRule .*\.(gif|jpg|swf|png)$ http://www.abong.com/
从以上配置可以看出,当请求的地址是以.gif .jpg .swf .png
结尾的,都会跳转到http://www.abong.com/
,这样别人就无法引用自身服务器上的图片了,就不会被盗了。
在本文中的rewrite模块的使用,仅仅是介绍基本的使用,在生产环境中,需要根据实际需求进行配置。
7. 禁止解析某个目录下的php文件
# 禁止访问网站数据目录下的data目录下的php文件
[root@server ~]# vim /usr/local/apache/conf/httpd.conf
# DocumentRoot "/usr/local/apache/htdocs"
# <Directory "/usr/local/apache/htdocs">
# ...
# </Directory>
<Directory "/usr/local/apache/htdocs/data/">
<Files ~ ".php">
Options Indexes FollowSymLinks
AllowOverride None
Require all denied
</Files>
</Directory>
apache调优总结:有关于apache调优的内容,记录了两篇博客。在实际生产环境中,可以根据其中介绍的各点排查服务器中的apache运行情况。生产环境的情况比测试环境复杂很多,需要根据实际需求,结合这两篇博客以及官方介绍进行配置。