Apache HTTP Server应用的几个场景

前言

尽管Apache具有重量级、耗资源、低性能(相比其它的WebServer)的特点,但是同时它也具有兼容性强、稳定性高、模块丰富等特点,且处理动态请求比大多Web Server要优越。另外,它对Windows的支持要比Nginx与Lighttpd要好。

在选择Web服务器时,我们最经常关注的一点是性能(注1),以下附上一个简单的性能测试结果:

测试服务器的配置:

分别安装了Nginx、Cherokee、Lighttpd和Apache,然后使用并发工具测试,得到如下的结果:

(图片顺序为Nginx、Cherokee、Lighttpd、Apache1、Apache2)

Apache HTTP Server应用的几个场景-LMLPHPApache HTTP Server应用的几个场景-LMLPHPApache HTTP Server应用的几个场景-LMLPHPApache HTTP Server应用的几个场景-LMLPHPApache HTTP Server应用的几个场景-LMLPHP

结果显示Apache的性能并是最好的,但即使如此,由于它对windows的支持以及丰富的模块,还有它于Web领域具有霸主地位。所以我们会经常接触它,本文就总结自己实际应用到的一些场景。

Apache安装

下载地址http://httpd.apache.org/download.cgi

Apache HTTP Server应用的几个场景-LMLPHP

值得注意的是2.0.64以后的版本,官网中只提供源码和netware压缩包,而之前的版本提供msi文件。由于目标环境为windows,为了简单起见,本文选择2.0.64。另,因为安装都是“next”,所以不再截图。

Web服务器

一个典型的配置如下

Alias /url "you/local/path"

<Directory "you/local/path">

Options Indexes FollowSymLinks –ExecCGI

DirectoryIndex index.html home/index.php home/index.html

Order allow,deny

Allow from all

Deny from google.com

</Directory>

说明如下

Alias /url "you/local/path":资源访问的路径。

Directory "you/local/path":暴露的本地资源之路径。

Options Indexes FollowSymLinks –ExecCGI:允许列出目录的内容;允许目录的符号链;不允许执行CGI脚本。

DirectoryIndex index.php index.html home/index.php home/index.html:默认首页

Order allow,deny:后者优先级大于前者,这一点在后面解释。

Allow from all:允许来自任何地方的HTTP访问请求。

Deny from google.com :禁止域名为google.com的HTTP访问请求。 还记得前面的Order吗?Deny优先级优于Allow,故Allow指令虽然声明允许所有的访问请求,但是apache仍然禁止来自google.com的请求。

反向代理负载均衡服务器

反向代理是指,以代理服务器来接受来自Internet上某个客户端的连接请求,然后将该请求转发至内部网络上的目标服务器,并将从目标服务器上得到的结果返回给客户端的过程。

Apache HTTP Server应用的几个场景-LMLPHP

反向代理示意图

反向代理的使用场景主要以下几个:

1. 加密和SSL加速

2. 负载均衡

3. 缓存静态内容

4. 压缩页面

5. 减速上传

6. 安全

7. 外网发布

基于反向代理的负载均衡常用的场景为实现动静态分离。

使用Apache+Tomcat+缓存服务器来实现动静态分离的方式有三种:JK、http_proxy、ajp_proxy。其中,JK相对后两者来说配置相对复杂,但是性能较好。JK方式是我们常用的方式。

下面的就是JK一个典型的例子。

JK方式需要额外下载mod_jk模块,地址为

http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/windows/。下载完成后将其中的mod_jk.so文件拷贝至%APACHE_HOME%/modules目录下。

JK的配置最关键的有三个文件:

文件名

说明

http.conf 前面提到的,Apache服务器的配置文件,这里用来加载JK模块以及JK配置文件信息。
workers.properties 到Tomcat服务器的链接定义文件。
uriworkermap.properties URI映射文件,用来指定哪些URI由Tomcat处理,也可以直接在httpd.conf中配置,但是将这些配置文件单独放置有一个好处就是JK模块会定期更新该文件的内容,使得我们修改配置的时候无需重启Apache服务器。

下面是一个典型的httpd.conf对JK的配置

# (httpd.conf)

# 加载 mod_jk 模块

LoadModule jk_module modules/mod_jk.so

JkWorkersFile conf/workers.properties

JkMountFile conf/uriworkermap.properties

JkLogFile logs/mod_jk.log

JkLogLevel warn

接下来需要在conf目录创建两个文件分别是workers.properties、uriworkermap.properties。

内容大概如下

#

# workers.properties

#

# list the workers by name

worker.list=DLOG4J, status

# localhost server 1

# ------------------------

worker.s1.port=8009

worker.s1.host=localhost

worker.s1.type=ajp13

# localhost server 2

# ------------------------

worker.s2.port=8109

worker.s2.host=localhost

worker.s2.type=ajp13

worker.s2.stopped=1

worker.DLOG4J.type=lb

worker.retries=3

worker.DLOG4J.balanced_workers=s1

worker.DLOG4J.sticky_session=1

worker.status.type=status

这里我们配置了两个类型为 ajp13 的 worker 分别是 s1 和 s2,它们指向同一台服务器上运行在两个不同端口 8009 和 8109 的 Tomcat。接着我们配置了一个类型为 lb(也就是负载均衡的意思)的 worker,它的名字是 DLOG4J。需要说明的是lb是逻辑的 worker,职责是管理前面配置的两个物理连接 s1 和 s2。最后我们还配置了一个类型为 status 的 worker,用来监控 JK 本身。但是有了这三个 worker 还不够,我们还需要告诉 JK,哪些 worker 是可用的,所以就有 worker.list = DLOG4J, status 这行配置。

/*=DLOG4J

/jkstatus=status

!/*.gif=DLOG4J

!/*.jpg=DLOG4J

!/*.png=DLOG4J

!/*.css=DLOG4J

!/*.js=DLOG4J

!/*.htm=DLOG4J

!/*.html=DLOG4J

配置说明所有的请求都由 DLOG4J 这个 worker 进行处理,除了下面的几个例外。/jkstatus 请求由 status 这个 worker 处理。另外感叹号开头且符合规则的URI 不要由 JK 进行,包含图片、css 文件、js 文件以及静态 html 文本文件。

缓存服务器

这里只考虑Apache自带的cache模块,关于与Squid或者varnish等整合另外介绍。

httpd.conf配置如下:

LoadModule cache_module modules/mod_cache.so

LoadModule disk_cache_module modules/mod_disk_cache.so

UseCanonicalName On

<IfModule mod_cache.c>

CacheDefaultExpire 3600

CacheMaxExpire 86400

<IfModule mod_disk_cache.c>

CacheEnable disk /

CacheRoot d:/cache

CacheDirLevels 2

CacheDirLength 1

CacheMaxFileSize 1048576

CacheMinFileSize 10

</IfModule>

</IfModule>

配置说明

UseCanonicalName:指令设置为 On 可以使用disk缓存时显著提高缓存的命中率。

CacheDefaultExpire:设置那些既没有包含"Expires" 或"Cache-Control"头,也没有包含"Last-Modified"头的缓存对象的默认有效期(按秒计),默认是为86400秒。

CacheMaxExpire: 指定失效周期的最大值;默认值是一天 (86400)。

CacheEnable disk / 使用disk 缓存类型 ,这里为缓存目录

CacheRoot d:/cache 存放缓存文件的目录,需保证运行的用户拥有该目录的写入权限。

CacheDirLevels指定了子目录的层数,

CacheDirLength指定了每级子目录名的字符数

CacheMaxFileSize 缓存文件的最大值(byte)

CacheMaxFileSize:缓存文件的最小值(byte)。

日志服务

(注2)一个典型的例子:

[Wed Oct 11 14:32:52 2000] [error] [client 127.0.0.1] client denied by server configuration: /export/home/live/ap/htdocs/test

第一项是事件发生的日期和时间;第二项是事件的严重性, LogLevel指令使只有高于指定严重性级别的事件才会被记录;第三项是产生事件的IP地址;此后是事件本身,在此例中,服务器拒绝了这个客户的访问。服务器在记录被访问文件时,用的是文件系统路径,而不是Web路径。

本文仅介绍日志服务使用的模块和常用的日志格式。

1. 访问日志

相关模块

相关指令

· mod_log_config

· mod_setenvif

· CustomLog

· LogFormat

· SetEnvIf

访问日志中会记录服务器所处理的所有请求,其文件名和位置取决于 CustomLog 指令,LogFormat指令可以简化日志的内容。这里阐述访问日志的服务器配置。

不同版本的Apache httpd用了不同的模块和指令来控制对访问的记录,包括mod_log_referer, mod_log_agent, 模块和 TransferLog 指令。现在,CustomLog 指令包含了旧版本中相关指令的所有功能。

2. 日志格式

这是一个典型的记录格式

LogFormat "%h %l %u %t \"%r\" %>s %b" common

CustomLog logs/access_log common

上述定义了一种特定的日志格式字符串,并给它起了个 别名 叫 common,其中的"%"指示服务器用某种信息替换,其他字符信息则不作替换。引号(")必须加转义符反斜杠,以避免被解释为字符串的结束。格式字符串还可以包含特殊控制符,如换行"\n"、制表符"\t"。

CustomLog指令建立新的使用指定日志格式的日志文件,除非其文件名以斜杠开头,否则其路径是一个相对于ServerRoot的相对路径。

上述配置是一个普通的日志格式,被称为Common Log Format (CLF),它被许多不同的Web服务器所采用,并可以为许多日志分析程序所辩识,它产生的事件记录有如:

127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326

记录的各部分说明如下。

127.0.0.1(%h)

这是发送请求到服务器的客户的IP地址。如果 HostnameLookups 设为 On,则服务器会尝试解析这个IP地址的主机名,但是,并不推荐这样配置,因为会显著拖慢服务器,最好是用一个日志后续处理器还判断主机名,比如 logresolve。如果客户和服务器之间存在代理,那么记录中的这个IP地址就是那个代理,而不是客户面前的那个机器的IP地址。

-(%l)

这是由客户端 identd 判断的RFC 1413身份,输出中的符号 "-" 表示此处信息无效。除非在严格控制的内部网络中,此信息通常并不可靠,不应该被使用。只有在IdentityCheck 设为 On时,Apache才会试图得到这项信息。

frank(%u)

这是由HTTP认证系统得到的访问该网页的客户名称,环境变量 REMOTE_USER 会被设为该值并提供给CGI脚本。如果状态码是401,表示客户没有通过认证,则此值没有意义。如果网页没有设置密码保护,则此项应该是"-"。

[10/Oct/2000:13:55:36 -0700](%t)

这是服务器完成对请求的处理时的时间,其格式是:

[day/month/year:hour:minute:second zone]
day = 2*digit
month = 3*letter
year = 4*digit
hour = 2*digit
minute = 2*digit
second = 2*digit
zone = (`+' | `-') 4*digit

可以在格式字符串中使用 %{format}t 改变时间的输出形式,format与C标准库中的 strftime(3) 用法相同。

"GET /apache_pb.gif HTTP/1.0"(\"%r\")

引号中是客户发出的包含了许多有用信息的请求内容。可以看出,该客户的动作是GET,请求的资源是/apache_pb.gif,使用的协议是HTTP/1.0。另外,还可以记录其他信息,如:格式字符串 "%m %U%q %H" 会记录动作、路径、请求串、协议,结果其输出会和"%r" 一样。

200(%>s)

这个是服务器返回给客户端的状态码。这个信息非常有价值,因为它指示了请求的结果,或者是被成功响应了(以2开头),或者被转向了(以3开头),或者出错了(以4开头),或者产生了服务器端错误(以5开头)。完整的状态码列表参见HTTP specification (RFC2616 section 10).

2326(%b)

最后这项是返回给客户端的不包括响应头的字节数。如果没有信息返回,则此项应该是 "-",如果希望记录为 "0" 的形式,就应该用%B

伪静态技术

伪静态是一种将动态页面请求伪装成静态页面请求的手段,目的是改善动态页面对搜索引擎不好友好的缺点。同时也可以解决动态页面不被浏览器缓存的问题,提高系统性能。

一个典型的配置:

#

#httpd.conf 配置rewriter模块

LoadModule rewrite_module modules/mod_rewrite.so

#

<IfModule mod_rewrite.c>

RewriteEngine On

RewriteRule   ^(.*)/forum-([0-9]+)-([0-9]+)\.html$$1/forumdisplay.jsp?fid=$2&page=$3

</IfModule>

RewriteEngine 指令打开或关闭运行时的重写引擎。如果设置为off,则此模块在运行时不执行任何重写操作。使用该指令可以使此模块无效,而无须注释所有的RewriteRule指令!

RewriteRule指令是重写引擎的根本。此指令可以多次使用。每个指令定义一个简单的重写规则。这些规则的定义顺序尤为重要——在运行时,规则是按这个顺序逐一生效的。

指令后面的参数均为正则表达式,以下是正则表达式的常见的用法:

文本

. 任意一个单字符

[chars] 字符类: "chars"中的任意一个字符

[^chars] 字符类: 不在"chars"中的字符

text1|text2 选择: text1 或 text2

[num1 – num2] 数字类:从num1~num2

量词

? 前面的字符出现 0 或 1 次

* 前面的字符出现 0 或 N 次(N > 0)

+ 前面的字符出现 1 或 N 次(N > 1)

分组

(text) text 组

(常用于设置一个选择的边界,或用于生成后引用:

在RewriteRule中可以用 $N 引用第N个分组)

^ 以之开头

$ 以之结尾

转义

\c 对给定的字符c进行转义

(比如对".[]()"进行转义,等等)

当请求URL符合“^(.*)/forum-([0-9]+)-([0-9]+)\.html$”正则表达式时,RewriteRule将使用后者“$1/forumdisplay.jsp?fid=$2&page=$3”(同样是正则表达式)代替前者。代替的顺序为
“.*”=>“$1”、“ [0-9]”=>“ $2”、“ [0-9]”=>“
$3”。比如/hh/forum-1-2.html的URL将被替换为/hh/forumdisplay.jsp?fid=1&page=2。

更加详细的配置请参考注3

AB测试工具

ab全称apache benchmark,为apache server自带的性能测试工具,具有轻量、强大等特点。

Apache HTTP Server应用的几个场景-LMLPHP

结果说明

ServerSoftware: Apache/2.0.64

//待测试服务器使用之软件版本

Server Hostname: 127.0.0.1

//服务器名称

Server Port: 80

//服务器端口

Document Path: /apache_pb.gif

//访问路径

Document Length: 2326 bytes

//页面大小

Concurrency Level: 10

//(ab测试的)使用的并发数

Time taken for tests: 0.374986 seconds

//总花费时间

Complete requests: 100

//完成的总请求数量

Failed requests: 0

//失败的请求数量

Write errors: 0

//写入失败的次数

Total transferred: 257400 bytes

//总的数据传输量

HTML transferred: 232600 bytes

//总的HTML内容传输量

Requests per second: 266.68 [#/sec] (mean)

//最重要的指标之一,平均每次请求花费的时间

Time per request: 37.499 [ms] (mean)

//最重要的指标之二,平均每秒处理多少个请求

Time per request: 3.750 [ms] (mean, across all concurrent requests)

//与以上的结果差别在于:这个结果是先算每次并发的平均时间t1,

最后再对这些时间求平均值t=(t1…tn)/n。

Transfer rate: 669.36 [Kbytes/sec] received

//平均每秒传输的流量,可以帮助排除是否存在网络流量过大导致响应时间延长的问题

Connection Times (ms)

min mean[+/-sd] median max

Connect: 0 0 0.0 0 0

Processing: 15 35 15.9 31 93

Waiting: 15 35 15.9 31 93

Total: 15 35 15.9 31 93

Percentage of the requests served within a certain time (ms)

50% 31

66% 31

75% 46

80% 46

90% 62

95% 78

98% 78

99% 93

100% 93 (longest request)

//所有请求的响应情况,重点关注90%用户的响应时间。

常用参数说明

-n 所有请求数

-c 单次产生的请求数,执行次数等于n/c

-t 限制所有请求在制定时间内完成。默认没有时间限制。

-p 表单提交之数据

-T 表单提交使用之Content-type头信息。

-v 设置显示信息的等级: - 4或以上显示头信息, 3或以上显示响应代码(404, 200等), 2或以上显示警告和其他信息。

-V 显示版本号并退出。

-w 以HTML格式输出结果。

-i 执行HEAD请求,与GET请求不同的是,HEAD请求并不会下载页面至本地。

注释

注1 测试结果引自文章http://www.whisperdale.net/11-nginx-vs-cherokee-vs-apache-vs-lighttpd.html

注2 Apache日志模块官网文档:http://man.chinaunix.net/newsoft/ApacheManual/logs.html

注3 Apache mod_rewriter模块官方文档:

http://www.phpchina.com/resource/manual/apache/mod/mod_rewrite.html

05-11 11:35