/ 中存储网

优化Apache服务器的负载

2013-08-30 10:31:44 来源:itjs.cn

在百年的时候,倒是一直用 Apache 服务器,不过貌似没有对其进行过优化,自从把博客迁移到了 Linode VPS 上,权限更大了,但是就要自己关注博客性能问题了,用 ab 测试我的博客,性能数据惨不忍睹,没办法谁叫我只买了 512MB 的 VPS 呢。

Apache 虽然是 Linux 系统排名第一的 Web 服务端程序,Apache 是用的传统的阻塞式网络 I/O,只对大内存服务器支持较好,像 VPS 这样的小内存环境下 Apache 运行效率很低,网站访问量一大就会出问题。所以如果未来我的博客访问量上去了的话,我会考虑用 Nginx 替代 Apache,毕竟 Nginx 是有名的轻量级 http 服务器。不过这都是后话了,言归正传,下面我来说说 Apache 的优化过程:

1. 关闭 HostnameLookups

HostnameLookups 设置如果一旦启用,服务器会对客户端的hostname进行nslookup查询。这将延迟对用户的响应。

2. 关闭 AllowOverride

一般,将 AllowOverride 设置为 None 的性能是最优的。如果该值设置 All,目录设置允许被 .htaccess 文件覆盖。那么Apache则会在文件名的每一个组成部分都尝试打开 .htaccess 文件。要避免这种情况,可以将 AllowOverride 设置为 None。 不过,由于我的博客用的是 WordPress 架设起来的,有些 rewrite 规则被 WordPress 写在了 .htaccess 文件中,虽然我可以把这些规则写到 httpd.conf 文件中,但是有些 WordPress 插件同样需要 .htaccess 文件来限制权限,这对安全性而言十分重要,比如验证码插件。所以,我没有优化 AllowOverride 属性。

3. 配置 DirectoryIndex

当用户访问的 URL 以一个”/”结尾的时候,DirectoryIndex 则指明了要寻找的资源列表。也就是说,Apache 会依次找 index.php, index.html 等等。所以,DirectoryIndex 指定的资源列表顺序与数量都会影响性能,我们推荐数量不宜太多,把最常用的资源放在列表的最前面。配置如下:

DirectoryIndex index.php index.html index.html.var

4. 开启 EnableMMAP

尽可能地打开内存映射文件设置。所谓内存映射文件,指的就是 Linux 内核通过内核调用 mmap() 将磁盘文件与进程某段内存地址空间(有可能是物理内存,但也有可能是虚拟内存)对映起来,自此 Apache 就可以通过访问内存直接访问磁盘文件,它不需要使用 read() 和 write() 等系统内核调用来访问磁盘了。

所以,在大多数情况下,可以通过内存映射文件的机制来提高磁盘 I/O 性能。Apache2 开始支持 mmap 功能,对于较大的静态文件,Apache 是不会使用 mmap 的,因为需要不小的内存开销。另外,mmap 仅对较小的静态文件有效。也就是说,Apache 对于较小的静态文件,才会启用 mmap 将文件映射到进程内存地空间。

5. 开启 EnableSendfile

如果你的系统支持 Sendfile 机制的话,可以开启该机制。Sendfile 机制可以提高 Apache 性能。所谓 Sendfile,就是我们平常所提到过的”零拷贝”。

一般,我们对一个磁盘文件写操作,要经过几次拷贝才能够完成。首先用户进程,通过 fgets() 向请求系统内核调用 read,这时候 read 会将磁盘文件数据拷到系统内核空间的缓冲区,然后系统内核调用返回的数据拷到用户空间的缓冲区。当回写数据的时候,又会通过 fwrite() 函数请求系统内核调用 write,将数据写回磁盘。磁盘设备->内核缓冲(内存)->用户缓冲(内存)来回共4次拷贝。对于一个静态文件请求,我们会发现,首先从磁盘设备将数据拷贝到内核空间缓冲区,又从内核空间缓冲区拷贝到用户空间缓冲区,马上又从用户空间缓冲区拷贝回内核缓冲区,接着从内核缓冲区写入到网络接口设备。我们发现,静态数据从内核空间交给用户空间之后,并没有被程序做任何处理,又原原本本地传回了内核空间,数据就这样白白地兜了一圈。

所以,Linux 自支持 Sendfile 机制以后,它可以让数据不用交给用户空间缓冲区,直接在内核空间处理掉。这样节约了内核态的切换和用户态数据的复制开销。Apache 对于较大的静态资源请求,会启用 Sendfile。

6. 控制模块的加载

服务器的物理内存资源是非常有限且宝贵,加载没有使用到的模块会占用额外的内存空间,而且一直占用着,直到关闭进程。

请将关闭一大堆一个基本的 WordPress 网站不需要用到的模块。事实上,我建议你注释掉除了下面列出的模块之外的所有模块:

# cat /etc/httpd/conf/httpd.conf | grep “LoadModule” | grep -v

“^#”

LoadModule authz_host_module modules/mod_authz_host.so

LoadModule log_config_module modules/mod_log_config.so

LoadModule expires_module modules/mod_expires.so

LoadModule deflate_module modules/mod_deflate.so

LoadModule headers_module modules/mod_headers.so

LoadModule setenvif_module modules/mod_setenvif.so

LoadModule mime_module modules/mod_mime.so

LoadModule autoindex_module modules/mod_autoindex.so

LoadModule dir_module modules/mod_dir.so

LoadModule alias_module modules/mod_alias.so

LoadModule rewrite_module modules/mod_rewrite.so

下面是你可能注释掉的一行:

LoadModule negotiation_module modules/mod_negotiation.so

mod_negotiation 提供了一些你不需要的函数:自动完成输入错误的链接,提供多种语言选择的网站,也会用到这个模块。如果你的网站提供了多种语言选择,你就不要注释掉这个模块了。

当你注释掉了 mod_negotiation.so 模块,找到下面的两行(它们在不同的位置),注释掉,进而获得更多的性能提高:

LanguagePriority en ca cs da de el eo es et fr he hr it ja ko

ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW

ForceLanguagePriority Prefer Fallback

关闭这些模块后重启服务器,你将看到明显的性能提升。是的,它们消耗了一大块你有限的系统资源。

7. 关闭 ServerSignature

默认情况下,很多 Apache 安装时会显示版本号及操作系统版本,甚至会显示服务器上安装的是什么样的 Apache 模块。这些信息可以为黑客所用,并且黑客还可以从中得知你所配置的服务器上的很多设置都是默认状态。所以,请加入如下两条:

ServerSignature Off

ServerTokens Prod

ServerSignature 出现在 Apache 所产生的像 404 页面、目录列表等页面的底部。ServerTokens 目录被用来判断 Apache 会在 Server http 响应包的头部填充什么信息。如果把 ServerTokens 设为 Prod,那么 http 响应包头就会被设置成:server:apache

8. 改进 Apache MPM prefork 模块

我的 Apache 运行在 prefork 模式下(如果你的服务器是个小内存 VPS,强烈推荐使用该模式)。

这个模块将对 Apache 开始运行的进程和空闲进程数量进行控制和优化。当你使用小内存 VPS 来处理 MySQL 和 Apache 时,这个模块显得尤其重要。修改后我的配置如下:

StartServers 8

MinSpareServers 5

MaxSpareServers 20

ServerLimit 256

MaxClients 256

MaxRequestsPerChild 4000

MinSpareservers 和 MaxSpareServers 分别设置空闲子进程的最小和最大数量,StartServers 设置了服务器启动时建立的子进程数量。ServerLimit 则是控制 MaxClients 所能使用的最大值。缩减 MaxClient s能让运行动态内容(比如:WordPress)的服务器有很大的改变。如果你的 VPS 遭遇到流量的大幅增加,而你的 MaxClients 设置的太高的话,你的服务器将会无限循环工作于从物理内存交换页面到虚拟内存中,最终导致宕机。 一般计算适当的 MaxClients 值取决于你总共可用的系统内存除于每个 Apache 进程使用的内存。例如,如果你还有 500MB 的内存可用于 Apache,每个 Apache 进程大约使用 10MB 的内存,你可以设置你的 MaxClients 为(512-12)/ 10 = 50。使用命令 top 可以得到 VPS 的实时内存的使用情况。MaxRequestsPerChild 设置每个子进程在其生存期内允许伺服的最大请求数量。我们可以安全地缩减此项值,从而得到一个小的提升。如果你对 MPM 的 prefork 模式和 worker 模式的区别感兴趣,请参考这里。

9. 最优化 KeepAlive

KeepAlive 允许你的访问者在同一个 TCP 连接上完成多个请求,理论上它有助于提升反应时间,因为你的访问者可以在同一个连接上请求你的网页,图片和 javascripts。遗憾地是,Apache 对于每个请求都需要一个工作进程去处理。默认的每个工作进程将持续打开15秒来处理每个请求,即使你的访问者已经不再使用它了!这也就意味着你的系统在任何时间都是缺少工作进程的。我们都希望我们那只有有限资源的小 VPS 能有确实在工作的工作进程。

不过,如果你的网站有大量的图片和 javascripts,通常最好还是让 KeepAlive 保持打开,然后做些调整。

如果你决定让 KeepAlive 保持打开状态,改变默认的 KeepAliveTimeout 值就显得很重要了。它能避免连接没有在使用时仍然打开。缩减 KeepAliveTimeout 值为 3 秒钟,这已经足够用户打开大部分必须的文件。修改如下:

KeepAliveTimeout 3

如果你希望让 KeepAlive 保持打开状态,同时应该增加 MaxKeepAliveRequests。设置它为更大的值让每个连接可以处理更多的请求,从而增加效率。修改如下:

MaxKeepAliveRequests 200

10. 调整 Timeout 参数

调整 Timeout 参数可以得到小的性能提升和减小 DDOS 攻击的效果。这个指令用于设置 Apache 当接收新请求,处理请求和返回响应前需等待多少秒。修改如下:

Timeout 40

11. 其他

如果没有必要记日志,把日志记录关闭有时候出于维护原因。我们可能会建立一些虚拟目录,进行一些数据受限访问。这种情况,我们建议不要记录日志,因为读日志文件与写日志是磁盘 I/O 操作。操作 I/O 操作始终很昂贵。

目录的层级不要太深,越简单越好目录的层次结构,不要太深。我们推荐3层就差不多了。因为,我们常常需要 lstat(), stat(), cd() 等操作于这些目录。虽然,这些内核调用微不足道,但是我们还是要遵守这样一条优化原则:减少不必要的系统内核调用。

还可以使用 gzip 来压缩 http 协议传输的内容来改进 Web 应用程序性能,加快 http