使用应用程序跟踪对性能改变进行量化分析
使用 Apache Web 服务器作为示例,以了解如何分析公共配置的性能含义。使用应用程序跟踪来观察应用程序运行过程中进行的系统调用。通过统计调用的次数和发生的时间,您可以轻松地了解性能改变的影响。您可以对应用程序进行跟踪,以找出它们暂停或不运行的原因。并且可以使用同样的方法,了解更多关于应用程序的信息并理解某些配置的性能含义。因为 Apache 非常流行并且大多数读者对它都比较熟悉,所以本文使用 Apache 作为示例。Apache 所进行的每次系统调用都会对 Web 页面的提供带来延迟,通过跟踪不同配置下的 Web 服务器,您可以确定具体配置的影响。
应用程序跟踪概述
在应用程序的执行过程中,当需要打开文件、发送数据包或者使用系统资源时,它会对基础操作系统进行相应的系统调用。跟踪应用程序意味着可以在调用发生时观察到这些系统调用,这将使得您能够深入地了解该应用程序的行为。在 Solaris 和 IBM AIX® 操作系统 (AIX) 中,使用 truss 命令完成这项任务,而在 Linux® 中则使用 strace。清单 1 显示了对 pwd 命令进行跟踪的示例。
清单 1. 跟踪 pwd 命令
-bash-3.00$ truss pwd...getcwd("/export/home/sean", 1025)
= 0/export/home/seanwrite(1, " / e x p o r t / h o m e".., 18)
= 18_exit(0)
在删除开始处与加载该应用程序相关的输出内容后,您可以看到所进行的三次系统调用:
- getcwd 返回当前工作目录。输出内容中显示了字符串“/export/home/sean”返回到缓冲区。
- write 可以显示给定的字符串。因为在其执行之后才显示这个系统调用,所以先输出了它的执行结果。还可以注意到,write 系统调用的结果是写入字符的个数数目,在这个示例中为 17 加上一个回车。
- _exit 使用错误代码 0 退出该程序,这个错误代码通常表示成功结束。
尽管这是一个很简单的示例,但它演示了通过应用程序跟踪可以观察程序内部机制的程度。有关跟踪方面更深入的信息,请参见参考资料部分。
Apache 配置的简要介绍
可以通过一个名为 httpd.conf 的文件对 Apache Web 服务器进行配置。清单 2 显示了一个简单配置中的部分内容。
清单 2. 示例 httpd.conf
DocumentRoot "/var/apache/htdocs"<Directory />
Options FollowSymLinks
AllowOverride None</Directory><Directory "/var/apache/htdocs">
Options Indexes FollowSymLinks MultiViews</Directory>
第一行定义了在何处可以找到 HTML 文件。将所有的请求都映射到这个目录。如果请求 /project/charter.html,将使用 /var/apache/htdocs/project/charter.html 提供该页面。httpd.conf 中剩余的部分由两个 Directory 节组成。<Directory ...> 和 </Directory> 之间的任何内容都将应用于指定目录及其所有的子目录。在本例中,第一节将两项设置应用于根目录,而第二节则指向 /var/apache/htdocs。
如果多个节应用于单个请求,那么将会对这些命令进行组合,并且最适合的目录具有高优先级。例如,将使用 /var/apache/htdocs/project/charter.html 提供 /project/charter.html 请求的页面。/var/apache/htdocs 是 / 的子目录,所以 Options Indexes FollowSymLinks MultiViews 来自第二节,AllowOverride None 来自第一节。
可以对许多内容进行配置,并且每项内容都具有其性能含义。本文余下的内容重点关注于如何对这些改变的影响进行量化分析。
建立基准
在您进行任何调整之前,务必要了解系统当前的运行方式。使用 -X 参数启动 Apache,这个参数将强制 Apache 进入单进程调试模式。这样做可以确保将请求发送到正在进行跟踪的进程,并且消除常规进程间通信所带来的开销。
在守护进程启动之后,通过运行 ps -ef 找到相应的进程 ID,并查找 httpd 守护进程。在找到该进程之后,使用 truss -c -p PID 附加到该进程。-c 选项表示对系统调用进行计数,而不是逐个显示它们,而 -p 则表示将易做图附加于一个正在运行的进程。
使用 Web 浏览器请求文档。在页面加载之后,回到 truss 应用程序,然后按 Ctrl-C 以结束计数。对于静态 HTML 页面,您应该看到如清单 3 所示的内容(为使这些数字变得更有趣,本示例进行了 100 次相同的请求)。
清单 3. 系统调用基准
sunbox# truss -c -p 15026(make the Web request 100 times)^Csyscall
seconds
calls
errorsread
.009
200write
.020
200close
.020
200time
.004
300alarm
.018
1100fcntl
.009
300sigaction
.007
400munmap
.007
100llseek
.001
100pollsys
.005
100mmap64
.008
100stat64
.007
100open64
.006
100accept
.019
100getsockname
.002
100setsockopt
.002
100
--------
------
----sys totals:
.149
3600
0usr time:
.120elapsed:
8.960
truss 返回系统调用的列表、执行调用耗费的总时间、调用的次数和任何发现的问题。在这个报表的结尾处,返回了这些系统调用耗费的总时间,以及执行应用程序所耗费的时间。对于这些目的来说,所耗时间是没有意义的,因为它指的是从启动 truss 开始到其结束的时间,而与 Web 请求没有任何关系。
清单 3 显示了最简单的情况。在来自 Web 浏览器的连接请求到达后,accept 系统调用完成该连接。Web 服务器使用 read 调用获得请求的内容,将请求的内容映射到磁盘上的文件。Web 服务器首先使用 stat64 验证该文件是否存在,使用 open64 打开该文件以便进行读取,然后使用 mmap64 将该文件的内容映射到内存中。然后使用 write 将这个文件发送回客户端,使用另一个 write 生成日志文件,并且服务器执行来自浏览器的最后一个 read。该列表中其余的调用都是系统开销,并且当配置发生改变时,不会有显著的变化。
解释这些数值
100 次请求总共耗费 0.269 秒 (0.149 + 0.120),这样的性能相当不错,并且该服务器每秒钟应该可以提供大约 370 个页面 (100/0.269)。但是不能完全相信这些数值,因为它们仅表示进程耗费在 CPU 上的时间,而不是其真正的执行时间(也称为时钟时间)。还有更多的因素需要考虑,如磁盘和网络的速度、计算机上正运行的其他内容、该守护进程运行于调试模式的事实。您还需要考虑系统调用跟踪本身的开销。
本文中使用的方法重点关注这些操作的相对计时和使用应用程序跟踪消除浪费掉的操作。如果您需要了解 Web 服务器每秒可以提供的页面数目,参考资料部分中有相应的软件链接,它可以帮助您确定该数值。
跟踪 AllowOverride 范围
Apache 允许管理员通过 .htaccess 机制将配置权委托给个别的用户。.htaccess 是一个包含附加配置指令的文件,如果在 httpd.conf 中通过 AllowOverride 配置了请求的目录,那么 Web 服务器将搜索这个文件。清单 4 显示了前面的配置了 AllowOverride Limit 的配置信息,它允许用户获取访问 Web 页面的用户名和密码。
清单 4. 配置了 AllowOverride 的示例 httpd.conf
DocumentRoot "/var/apache/htdocs"<Directory />
Options FollowSymLinks
AllowOverride Limit</Directory><Directory "/var/apache/htdocs">
Options Indexes FollowSymLinks MultiViews</Directory>
重新启动 httpd 守护进程并再次运行这些测试,其结果如清单 5 所示。
清单 5. 开启了 AllowOverride Limit 的 100 次请求的结果
sunbox# truss -c -t write,read,open64,stat64,mmap64 -p 21136^Csyscall
seconds
calls
errorsread
.012
200write
.021
200mmap64
.007
100stat64
.007
100open64
.022
500
400
--------
------
----sys totals:
.072
1100
400usr time:
.141elapsed:
16.660
初看起来,系统调用耗费的时间下降了,但这是因为使用了 -t 选项将跟踪任务限制于一些有意义的系统调用。大多数系统调用并没有发生变化,但现在有 5