书籍摘录:DevOps 故障排除:Linux 服务器最佳实践
本摘录来自 Kyle Rankin 撰写的书籍《DevOps 故障排除:Linux 服务器最佳实践》,由 Pearson/Addison-Wesley Professional 出版,ISBN 0321832043,2012 年 11 月,版权 2013 Pearson Education, Inc.。有关更多信息,请访问:http://www.informit.com/store/devops-troubleshooting-linux-server-best-practices-9780321832047
第 8 章:网站是否宕机?追踪 Web 服务器问题
获取 Web 服务器统计信息虽然您可以在服务器外部执行相当多的 Web 服务器故障排除,但最终您会遇到想要了解以下信息的情况:当前有多少 Web 服务器进程正在处理请求?有多少 Web 服务器进程处于空闲状态?繁忙的进程现在在做什么?要提取此类数据,您可以启用一个特殊的服务器状态页面,该页面会为您提供各种有用的服务器统计信息。
Apache 和 Nginx 都提供服务器状态页面。对于 Apache,它需要您启用一个名为 status 的内置模块。启用模块的方式因您的发行版而异;例如,在 Ubuntu 服务器上,您需要键入 a2enmod status。在其他发行版上,您可能需要浏览 Apache 配置文件并查找已注释掉的加载状态模块的部分;它可能看起来像这样
LoadModule status_module /usr/lib/apache2/modules/mod_status.so
在 Ubuntu 系统上加载模块后,已配置服务器状态页面以供 localhost 使用。在其他系统上,您可能需要将以下配置添加到您的 Apache 配置
ExtendedStatus On <IfModule mod_status.c> # # Allow server status reports generated by mod_status, # with the URL of http://servername/server-status # Uncomment and change the ".example.com" to allow # access from other hosts. # <Location /server-status> SetHandler server-status Order deny,allow Deny from all Allow from localhost ip6-localhost # Allow from .example.com </Location> </IfModule>
请注意,在此配置示例中,我们通过拒绝所有主机并仅允许来自 localhost 的连接,真正锁定了可以访问该页面的人员。这是一个安全的默认设置,因为您通常不希望全世界都能够查看此类调试信息。如您在注释掉的示例中所见,您可以添加其他 Allow from 语句以添加允许查看该页面的 IP 或主机名。
对于 Nginx,您可以将以下配置添加到您现有的 Nginx 配置中。在此示例中,Nginx 将仅监听 localhost,但您可以更改此设置以允许本地网络上的其他计算机连接
server { listen 127.0.0.1:80; location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; } }
设置配置并重新加载 Web 服务器后,如果您允许某些远程 IP 查看该页面,请打开 Web 浏览器并访问 Web 服务器上的 /server-status。例如,如果您的 Web 服务器位于 http://www.example.net,则您将加载 http://www.example.net/server-status 并看到如图 8-1 所示的页面。

图 8-1:标准 Apache 状态页面
在状态页面的顶部,您将看到有关 Web 服务器的常规统计信息,包括它运行的 Apache 版本以及有关其正常运行时间、总体流量以及每秒处理的请求数量的数据。下面是一个记分板,它很好地概述了您的 Web 服务器有多繁忙,下面是一个表格,该表格提供了有关每个进程处理的最后一个请求的数据。
虽然所有这些数据在不同的故障排除情况下都很有用,但记分板对于快速评估服务器的运行状况特别有用。记分板中的每个点都对应于一个特定的 Web 服务器进程,并且用于该进程的字符会为您提供有关该进程正在做什么的信息
_
S
R
W
K
D
C
L
G
I
.
等待连接
正在启动
正在读取请求
正在发送回复
作为 keepalive 进程保持打开状态,以便它可以发送多个文件
正在执行 DNS 查找
正在关闭连接
正在记录
正在优雅地完成
正在执行工作程序的空闲清理
没有当前进程的开放槽
图 8-1 显示了一个相当空闲的 Web 服务器,只有一个进程处于 K(-keep-alive)状态,一个进程处于 W(发送回复)状态。如果您好奇这些进程最后在做什么,只需向下滚动到该表并找到记分板中编号正确的进程。因此,例如,W 进程将被找到为 server 2-16。在屏幕截图中不明显,但该进程实际上是对 server-status 页面本身的请求的响应。您还会注意到记分板中有一些 _(等待连接)进程,这些进程对应于 Apache 配置为始终运行以响应新请求的进程数。记分板的其余部分充满了 .,它们表示新进程可以进入的槽—基本上是 MaxClients 设置(Apache 将生成的最大进程数)。
当您刷新此页面时,您会注意到记分板中的对象应该在每个请求期间更改。当您想要密切关注您的 Web 服务器时,此记分板非常方便;只需不断刷新页面即可。在峰值期间,您可以查看生成的新进程,切换到 W 以处理请求,然后,如果流量中的峰值消退,则这些进程会缓慢更改为 _,最终更改为 .,因为它们不再需要。
一般来说,当您访问服务器状态页面时,您会从登录到 Web 服务器的命令行执行此操作。这使您可以限制哪些主机可以查看该页面,同时仍然提供您需要的所有信息。现在,默认情况下,如果您针对常规服务器状态页面运行 curl,您将获得 HTML 输出。但是,如果您将 auto 选项传递给 server-status 页面,您将获得文本输出,该输出对于命令行查看和脚本解析更有用
$ curl https://127.0.0.1/server-status?auto % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 117 586 117 586 0 0 2579 0 --:--:-- --:--:-- --:--:-- 2579117 586 11 7 586 0 0 1905 0 --:--:-- --:--:-- --:--:-- 0 Total Accesses: 2343235 Total kBytes: 265925501 CPULoad: .0773742 Uptime: 6801454 ReqPerSec: .34452 BytesPerSec: 40036.7 BytesPerReq: 116210 BusyWorkers: 53 IdleWorkers: 28 Scoreboard: WW_W__W_W__W_K_W_W_K___WWWWW_WWKWWWW_WWWWWWWWWWWWWWWWWWKKKKKK_KW_.WC.CW_____K__ ____....................................................................................... ........................................................................................... ........................................................................................... ................................................
当您想要在命令行中监视服务器的状态页面时,虽然您可以一次又一次地运行 curl 命令,但您可以使用一个名为 watch 的便捷命令,该命令将每x秒(默认为 2 秒)运行您指定的任何命令。因此,如果您想密切关注状态页面并使其在命令行上每 5 秒刷新一次,您可以键入
$ watch -n 5 'curl https://127.0.0.1/server-status?auto'
要退出 watch,只需按 Ctrl-C。
解决常见的 Web 服务器问题虽然很难记录如何解决任何和所有的 Web 服务器问题,但您可能会遇到一些具有可识别症状的常见问题。本节将重点介绍您可能会发现的一些常见问题类型、它们的症状以及如何解决这些问题。
配置问题Web 服务器中一个常见且相对容易识别的问题是配置问题。由于需要重新加载 Web 服务器才能接受其配置中的更改,因此可能会很想在不重新加载 Web 服务器的情况下进行多次更改;但是,如果您这样做,您可能会在服务器维护期间(或者当您需要重新启动服务器以加载新的 SSL 证书时)发现您的配置文件中存在一些语法错误,并且您的服务器将拒绝启动。
Apache 和 Nginx 都会在您启动、重新启动或重新加载服务时验证其配置文件,因此这是查找配置错误的一种方法—不幸的是,这也意味着在出现问题的情况下,服务器在您修复错误时会宕机。幸运的是,这两种 Web 服务器都提供了测试配置语法并在服务器仍在运行时突出显示任何语法错误的方法。
对于 Apache,该命令是 apache2ctl configtest。请务必以可以读取所有配置文件(可能是 root 用户)的用户身份运行此命令。成功运行如下所示
$ sudo apache2ctl configtest Syntax OK
当存在语法错误时,此命令将标识错误的文件和行号,因此很容易找到
$ sudo apache2ctl configtest apache2: Syntax error on line 233 of /etc/apache2/apache2.conf: Could not open configuration ↪file /etc/apache2/conf/: No such file or directory
在这种情况下,配置文件中存在拼写错误—您想要包含的目录是 /etc/apache2/conf.d。
Nginx 还通过运行以下命令提供语法检查nginx -t:
$ sudo nginx -t the configuration file /etc/nginx/nginx.conf syntax is ok configuration file /etc/nginx/nginx.conf test is successful
与 Apache 一样,当 Nginx 检测到错误时,它会告诉您文件和行号
$ sudo nginx -t [emerg]: unknown directive "included" in /etc/nginx/nginx.conf:13 configuration file /etc/nginx/nginx.conf test failed权限问题
权限问题是一个常见的难题,尤其是对于新的 Web 服务器管理员而言。虽然 Apache 和 Nginx 的初始进程都以 root 身份运行,但实际执行提供内容的所有子进程都以具有更多限制权限的用户身份运行—通常是像www-data或apache这样的用户。例如,如果您以不同的用户身份上传网页,您可能会最初遇到权限问题,直到您确保您想要提供的每个文件都可由www-data或apache用户读取。
那么,从外部看,权限问题是什么样的?此示例采用基本的 Nginx 设置并更改主 index.html 文件的权限,使其不再可被外界读取。然后它使用 curl 尝试加载该页面
$ curl https://127.0.0.1 <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/0.7.65</center> </body> </html>
来自网页的输出告诉我们 HTTP 错误,甚至无需告诉 curl 显示它:403 Forbidden 错误。不幸的是,虽然我们可以看到该页面是被禁止的,但从此输出中,我们还不确定原因。但是,此时,我们将转向 Nginx 错误日志并查看
2012/07/07 16:13:37 [error] 547#0: *2 open() "/var/www/nginx-default/index.html" failed ↪(13: Permission denied), client: 127.0.0.1, server: localhost, request: "GET / ↪HTTP/1.1", host: "localhost"
此错误日志让我们知道 Nginx 尝试打开 /var/www/nginx-default/index.html,但权限被拒绝。此时,我们可以查看该文件的权限并确认它不可被 Nginx 运行的 www-data 用户读取
$ ps -ef | grep nginx root 545 1 0 15:19 ? 00:00:00 nginx: master process /usr/sbin/nginx www-data 547 545 0 15:19 ? 00:00:00 nginx: worker process $ ls -l /var/www/nginx-default/index.html -rw-r----- 1 root root 151 2006-08-30 03:39 /var/www/nginx-default/index.html
在这种情况下,您可以使用 chmod o+r 命令解决此权限问题,该命令会将世界读取权限添加到该文件。或者,您也可以更改该文件的组所有权,使其归 www-data 组(或 www-data 是其成员的组)所有。
虽然某些管理员可能会通过基本上使所有人都可以读取和写入所有文件来规避权限问题,但这样做的安全风险不值得轻松修复。相反,请考虑在系统上创建一个组,其成员包括 www-data 或 apache 用户(取决于您的 Web 服务器运行的用户)以及您上传文件的用户。如果您确实尝试了“chmod 777”方法来使每个人都可以读取该文件,请仅将其用作临时的健全性检查,以确认该问题确实是权限问题。请务必在解决问题后将权限更改回更安全的状态。
缓慢或不可用的 Web 服务器虽然配置和权限问题定义明确,但您可能会遇到的更常见的 Web 服务器问题之一可能是不错且含糊不清的—服务器似乎很慢,甚至可能暂时不可用。虽然导致此类问题的原因有很多,但本节将指导您了解 Web 服务器缓慢的一些常见原因及其症状。
高负载当服务器缓慢或暂时不可用时,我首先检查的事情之一是其负载。如果您尚未通读第 2 章,请阅读它以了解如何确定服务器是否承受高负载,如果是,则该高负载是否是您的 Web 服务器进程的结果;如果是,您将学习如何确定负载是受 CPU、RAM 还是 I/O 限制。
一旦您确定负载很高,并且问题出在您的 Web 服务器进程上,如果负载是 CPU 密集型的,那么您可能需要对您的 Web 服务器执行的任何 CGIs、PHP 代码等进行故障排除,以生成动态内容。查看您的 Web 服务器日志,尝试确定在此高负载期间正在访问哪些页面;然后尝试自己加载它们(如果您的主服务器已过载,则可能在测试服务器上),以衡量各种动态页面消耗多少 CPU。
如果负载似乎是 RAM 密集型的,并且您注意到您正在使用越来越多的交换存储,甚至可能完全耗尽 RAM,那么您可能面临着可怕的 Web 服务器交换死亡螺旋。这种情况通常出现在 Apache prefork 服务器中,但也可能在 Apache worker 甚至 Nginx 服务器中出现。本质上,当您配置 Web 服务器时,您可以配置服务器将生成的最大 Web 服务器实例数以响应流量。在 Apache prefork 中,这被称为 MaxClient 设置。当服务器接收到如此多的流量,以至于它生成的 Web 服务器进程数量超过了 RAM 的容量时,进程最终会使用速度慢得多的交换空间。这导致这些进程的响应速度比驻留在 RAM 中的进程慢得多,这导致请求需要更长的时间,进而导致需要更多的进程来处理当前的负载,直到最终 RAM 和交换空间都被消耗殆尽。
要解决此问题,您需要计算有多少 Web 服务器进程可以容纳到 RAM 中。首先计算单个 Web 服务器进程将占用多少 RAM,然后从您的总 RAM 中减去您的操作系统开销。然后计算出当前有多少 Apache 进程可以在不进入交换空间的情况下容纳到剩余的空闲 RAM 中。然后,您应该配置您的 Web 服务器,使其启动的进程永远不要超过它可以容纳到 RAM 中的进程数。
当然,对于现代动态生成的网页,设置这个值可能会有点棘手。毕竟,例如,一些 PHP 脚本使用的 RAM 很少,而另一些脚本可能使用相当多的 RAM。在这种情况下,最好的策略是查看繁忙的 Web 服务器上的所有 Web 服务器进程,并尝试衡量进程消耗的最大、最小和平均 RAM 量。然后,您可以决定是根据最坏的情况(最大 RAM 量)还是平均情况来设置 Web 服务器的数量。
如果您的负载是 I/O 密集型的,并且 Web 服务器在同一台机器上有一个数据库后端,那么您可能只是用数据库请求饱和了您的磁盘 I/O。当然,如果您遵循了第 2 章中的负载故障排除指南,您应该已经能够识别出数据库进程是罪魁祸首,而不是 Web 服务器进程。在任何一种情况下,您可能需要考虑将您的数据库放在单独的服务器上,升级您的存储速度,或者转到第 9 章以获取有关如何排除数据库问题故障的更多信息。即使数据库服务器位于单独的机器上,每个等待来自网络数据库响应的 Web 服务器进程仍然可能产生很高的负载平均值。
否则,如果服务器是 I/O 密集型的,但问题似乎来自 Web 服务器本身而不是数据库,则可能是驱动您网站运行的软件只是用请求饱和了磁盘 I/O。或者,如果您在日志中启用了反向 DNS 解析,以便将 IP 地址转换为主机名,那么您的 Web 服务器进程可能只需要等待每个 DNS 查询解析才能完成其请求。
服务器状态页面诊断服务器运行缓慢时,除了排除系统上的高负载之外,另一个主要关注点是服务器状态页面。在本章的前面,我们讨论了如何在 Web 服务器中启用和查看服务器状态页面。在 Web 服务器缓慢或不可用的情况下,此状态页面提供了 Web 服务器运行状况的良好总体视图。您不仅可以看到系统负载平均值,还可以看到当前有多少进程处于繁忙状态以及它们正在做什么。
例如,如果您看到类似这样的情况,
$ curl https://127.0.0.1/server-status?auto . . . Scoreboard: WWWWWWWWWWWWWKWWWWWKWWWWWWWWWWWKWWWWWWWWWWWWWWWWWWWWWWWKKKKKKWKWWWWCWCWWWWWWKWW ____WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
您就会知道这台服务器完全被请求压垮了。当您刷新此页面时,您可能会偶尔看到一个进程打开,但显然,几乎每个进程都在忙于满足请求。在这种情况下,您可能只需要允许您的 Web 服务器生成更多的进程(如果您可以将它们放入 RAM 中),或者,可能是时候添加另一台 Web 服务器来帮助分担负载了。
再次,如果您看到像前面显示的记分板,但注意到您的 Web 服务器似乎响应非常迅速,则可能是每个 Web 请求都必须等待后端上的某些东西。当应用程序服务器被等待请求压垮时(有时最终是因为它所依赖的数据库服务器已过载),可能会发生这种行为,因此尽管所有 Web 服务器进程都处于繁忙状态,但添加更多进程不一定会解决问题——它们仍然会等待后端响应。
另一方面,您可能会看到类似这样的情况
Scoreboard: WW_W__W_W__W_K_W_W_K___WWWWW_WWKWWWW_WWWWWWWWWWWWWWWWWWKKKKKK_KW_.WC.CW_____K__ ____....................................................................................... ........................................................................................... ........................................................................................... ................................................
这是一个有许多可用进程的服务器,包括已加载到 RAM 中的进程和正在等待加载的进程。如果您的服务器运行缓慢但您的记分板看起来像这样,那么您需要深入研究您的 Web 服务器日志,并尝试确定当前正在加载哪些页面。最终,您需要确定您站点上的哪些页面需要很长时间才能响应,然后您需要深入研究该软件,尝试找到根本原因。当然,也可能只是您的 Web 服务器对于它运行的软件来说功率不足,如果是这样,那么是时候考虑硬件升级了。
© 版权所有 Pearson Education。保留所有权利。