- 前言
- 为什么要写这本书
- 读者对象
- 如何阅读本书
- 勘误和支持
- 致谢
- 第一部分 安全运维篇
- 第 1 章 Linux 服务器安全运维
- 第 2 章 Linux 网络安全运维
- 第 3 章 数据安全工具 DRBD、extundelete
- 第二部分 运维故障排查篇
- 第 4 章 Linux 系统运维故障排查思路
- 第 5 章 Linux 故障排查案例实战
- 第三部分 自动化运维篇
- 第 6 章 轻量级运维利器 pssh、pdsh 和 mussh
- 第 7 章 分布式监控系统 Ganglia
- 第 8 章 基于 nagios 的分布式监控报警平台 Centreon
- 第 9 章 通过 Ganglia 与 Centreon 构建智能化监控报警平台
- 第四部分 集群架构篇
- 第 10 章 高性能 Web 服务器 Nginx
- 第 11 章 高性能集群软件 Keepalived
- 第 12 章 千万级高并发负载均衡软件 HAProxy
- 第 13 章 构建高性能的 MySQL 集群系统
- 第 14 章 高性能负载均衡集群软件 HAProxy
5.2 Apache 常见错误故障案例
本节主要介绍 Linux 系统下 Web 运维过程中常见的一些故障和案例,这些案例都是基于 Apache 的错误或者故障的,虽然和系统并没有直接关系,但是通过分析和排查发现,其实大部分故障都与系统参数设置有很大关系,所以,下面的案例都基于 Linux 系统的故障进行分析和排查,在介绍过程中,除给出了故障的解决方法外,同时也介绍了与故障相关的 Linux 系统知识,而这些知识是判断和解决问题必不可少的。
5.2.1 “No space left on device”错误与解决方法
1.错误现象
这也是一个客户案例,客户反映在执行“apachectl start”启动 Apache 时无报错信息,但是还是不能访问网页。客户的网站是基于 Apache+PHP+MySQL 的在线交易平台,听到客户描述的现象后,第一反应是防火墙屏蔽了 HTTP 端口或 SELinux 的问题,于是登录服务器查看相关信息,如图 5-20 所示。
图 5-20 查看系统防火墙和 SELinux 状态
从输出可知,防火墙所有策略都处于开放状态,并未作任何限制,而 SELinux 也处于关闭状态,应该不是防火墙问题导致的。
既然不是防火墙拦截的问题,那么看看 httpd 进程是否存在及 httpd 端口是否正常启动,操作过程如图 5-21 所示。
图 5-21 查看 httpd 进程运行状态
这个操作首先查看了服务器上的 httpd 进程,发现并没有 httpd 进程运行,同时 httpd 对应的端口 80 也并没有启动,于是重新启动 Apache,在启动 Apache 的过程中并没有报错,启动完成后发现仍然 httpd 进程没有运行,由此看来,应该是 Apache 内部出现了问题。
2.解决思路
在判定是 Apache 的问题后,首先要看的就是 Apache 的启动日志,在查看 Apache 的 error 日志后,发现了一个可疑输出,内容为:
No space left on device: mod_rewrite: could not create rewrite_log_lock Configuration Failed
看到这个错误提示,感觉应该是磁盘空间耗尽导致的,于是赶紧查看系统所有磁盘分区,结果发现所有磁盘分区都还有很多可用空间,这就有些奇怪了。
在前面的案例介绍中,详细介绍了 Linux 下对磁盘空间的占用分为三个部分:物理磁盘、inode 节点磁盘空间和信号量磁盘空间。通过检查服务器的物理磁盘空间,发现仍有很多剩余,因此排除物理磁盘空间的问题。接着通过“df -i”命令查看系统可用的 inode 节点,发现每个分区可用的 inode 还有很多,这样 inode 节点问题也被排除了,那么应该是信号量磁盘空间耗尽导致的。
这里简单介绍下 Linux 信号量相关的知识。信号量是一种锁机制,用于协调进程之间互斥的访问临界资源,以确保某种共享资源不被多个进程同时访问。Linux 系统的信号量是用于进程间通信的。它有两种标准实现,分别是 POSIX 及 System v,现在大多数 Linux 系统都实现了这两种标准。这两种标准都可用于进行线程间的通信,只是系统调用方式略有不同。
- System v 信号量通过系统调用 semget 来创建,通过 Linux 命令 ipcs 即可显示进程间通信用的 System v 类型信号量及共享内存。
- POSIX 信号量可用于线程和进程间通信,并可分为有名和无名两种。也可简单理解为是否保存在磁盘上。有名的信号量会以文件形式保存在/dev/shm 下,因此可用于不相关的进程间通信,而无名信号量只能用于线程间和父子进程间通信。
在对信号量有了简单了解后,可以发现 Apache 使用的进程间通信方式应该是 System v,因此就可以通过 ipcs 命令查看和解决这个问题了。
3.解决问题
在解决这个问题之前,首先查看下 Linux 系统默认信号量的设置值是多少,执行如下命令:
[root@localhost ~]# cat /proc/sys/kernel/sem 250 32000 32 128
这 4 个输出值的含义如下:
- SEMMSL,此参数用于控制每个信号集的最大信号数。
- SEMMNS,此参数用于控制整个 Linux 系统中信号(而不是信号集)的最大数量。
- SEMOPM,此参数用于控制每个 semop 系统调用可以执行的信号操作数。
- SEMMNI,此内核参数用于控制整个 Linux 系统中信号集的最大数量。
接着通过 ipcs 命令查看 httpd 进程占用了多少信号量,执行如下命令:
[root@localhost ~]# ipcs -s | grep daemon
其中 daemon 是启动 Apache 进程的用户,默认是 daemon,也可能是 nobody 用户,根据实际环境而定。在执行完此命令后,发现很多基于 daemon 的信号量输出,问题终于找到了。解决信号量耗尽的方法很简单,通过 ipcrm 命令清除即可,最简单方法是执行如下命令组合:
[root@localhost ~]# ipcs -s | grep nobody | perl -e 'while (<STDIN>) { @a=split(/\s+/); print `ipcrmsem $a[1]`}'
执行完上面这个命令后,再次启动 Apache,然后查看 httpd 进程是否启动,可以看到,此时 httpd 进程启动了,那么 Apache 也工作正常了。
5.2.2 apache(20014)故障与解决方法
1.错误现象
这是一个客户的简单案例。客户告知网站无法访问了,并且 Apache 也无法启动。客户的网站是基于 Apache+Tomcat+MySQL 构建的,于是登录服务器查看信息如图 5-22 所示。
图 5-22 Apache(20014)Internal error 现象
这里提示的是 httpd.pid 文件的错误,熟悉 Apache 的读者应该知道 httpd.pid 文件其实是 Apache 的进程 pid 文件,Apache 的启动进程 ID 就放在这个文件中。
2.解决思路
既然提示 httpd.pid 这个文件有问题,那么就先看看这个文件是否存在,以及其中的内容是什么。查看 httpd.pid 文件,操作如下:
linux:~ # more /usr/local/apache2/logs/httpd.pid
发现这个文件存在,但是内容为空,这里肯定有问题。要解决这个问题,首先要了解 Apache 的启动机制及 httpd.pid 文件的作用。
httpd.pid 文件为文本文件,内容只有一行,记录了 httpd 进程的 pid。通过 cat 命令可以看到该文件的内容,通过这个 pid 文件可以防止进程启动多个副本。只有能获得 pid 文件的进程才能正常启动并把自身的 pid 写入该文件中。同一个程序的多余进程则自动退出。同时,httpd.pid 文件在 Apache 正常启动时创建,正常关闭时自动删除,Apache 在启动时会查找 httpd.pid 文件是否存在,如果文件不存在就创建此文件,将 Apache 启动的进程 ID 写入 httpd.pid 中,并提示启动成功。如果文件存在但内容为空,那么就会出现“(20014)Internal error”的错误了。
在这个案例中,httpd.pid 文件存在,但是内容为空,这个现象可能是磁盘空间耗尽导致的,也可能是系统突然断电导致的,总之导致这个问题的原因有很多种,这里并不打算深究,因为找到解决问题的办法是我们的目的。
3.解决问题
解决这个问题有两个办法:一是直接删除 httpd.pid 这个空文件,二是将这个文件写入一个数字 ID 值,操作如下:
linux:~ # echo "28976">>/usr/local/apache2/logs/httpd.pid linux:~ # more /usr/local/apache2/logs/httpd.pid 28976
接着,再次启动 Apache:
linux:~ # /usr/local/apache2/bin/apachectl start
这次 Apache 可以正常启动了,此时查看 httpd.pid 文件内容,信息如下:
linux:~ # more /usr/local/apache2/logs/httpd.pid 7789
可以看到,Apache 成功启动后,已经自动获得了一个新的 pid 值,进程间通信就以这个 pid 进行。Apache 在启动后,保持这个 pid 值不变,直到下次重新启动 Apache 才更新 httpd.pid 的值。
5.2.3 "could not bind to address 0.0.0.0:80"错误与解决方法
1.错误现象
客户的一台 Web 服务器是基于 Apache+JK+Tomcat 构建的一个电商平台,在机器更换硬件重新启动后,客户反映 Apache 无法启动,但是 Tomcat 可以启动。启动 Apache 的错误信息如图 5-23 所示。
图 5-23 Apache 无法启动错误现象
于是又检查了操作用户和 Apache 监听的端口,如图 5-24 所示。
图 5-24 查看 Apache 的管理用户和监听端口
从输出可知,Apache 的启动用户是 www,监听端口为 80,接着查看到/usr/local/apache2 目录所有文件和目录的权限都是 www,看来不是读写权限的问题,于是继续排查,这里更换了 Apache 的监听端口,将其改为 8000,看能否成功启动,操作如图 5-25 所示。
图 5-25 修改 Apache 监听端口为 8000 后重启 Apache 服务
虽然这次启动没报错,但是根据 httpd 进程的状态来看,启动应该还有问题,于是查看 Apache 启动日志,如图 5-26 所示。
图 5-26 Apache 启动错误信息
从日志输出看,果然存在问题,通过日志基本判断是 Apache 的 pid 文件无权限导致的。接着检查 httpd.pid 文件的权限,操作如下:
[root@cloud1 logs]# ll /usr/local/apache2/logs/httpd.pid -rw-r--r-- 1 root www 6 Sep 16 17:33 /usr/local/apache2/logs/httpd.pid
从输出可知,httpd.pid 权限的属主为 root,将其修改为 www 用户,操作如下:
[root@cloud1 logs]# chown www /usr/local/apache2/logs/httpd.pid
然后,重启 Apache,操作如图 5-27 所示。
图 5-27 重启 Apache 服务并查看启动进程
可以看到,这次 Apache 启动成功了,看来 Apache 配置并无问题,通过 8000 端口可以启动,而通过 80 端口则无法启动,这是什么问题呢?
2.解决思路
既然这个案例是与端口相关的,那么就需要了解下 Linux 系统中的端口。在 Linux 系统下可用的端口范围是 1~65535,端口可分为三类,分别是公认端口、注册端口和动态端口。
- 公认端口的范围为 0~1023,属于系统预留端口,主要用于绑定一些服务,例如 80 端口绑定的是 HTTP 服务,21 端口绑定的是 FTP 服务,22 端口绑定的是 sshd 服务等。对于公认端口,Linux 系统做了一些安全限制,那就是普通用户无法绑定这类端口,只有 root 用户才能绑定和使用公认端口。
- 注册端口的范围是 1024~49151,主要用于分配给用户进程或应用程序,这些进程主要是用户自定义安装的一些应用程序。
- 动态端口的范围是 49152~65535,动态分配是指当一个系统进程或应用程序需要进行网络通信时,它就向主机申请一个端口,主机从可用的端口号中分配一个供它使用。当这个进程关闭时,同时也就释放了所占用的这个端口。
通过以上对端口的介绍,这个案例描述的问题也就明确了,在上面的错误现象中,普通用户 www 无法启动 Apache 的 80 端口,就是因为 80 端口属于公认端口,普通用户无权绑定,而 8000 端口属于注册端口,普通用户可以自由使用,这就是此案例要查找的原因。
3.解决问题
如何使用 Apache 的 80 端口呢?这里提供两种方法,分别是:
1)将 Apache 以 root 用户启动即可,这是最简单的方法。
2)修改 Apache 目录下 httpd 文件的 SUID 属性。
第一种方法实现简单,但是有安全问题,如果黑客入侵了 80 端口,那么他也就拥有了 root 权限,因此,不推荐使用第一种方法,因为保证程序的安全才是根本。这里简单介绍下第二种方法的实现过程。首先通过 root 用户进行如下授权,如图 5-28 所示。
图 5-28 对 Apache 的 httpd 文件进行授权
然后在 www 用户下再次启动 Apache,可以看到这次启动正常了,如图 5-29 所示。
图 5-29 通过 www 用户重启来启动 Apache 服务
从这个输出可以看出,其实 Apache 还是在 root 用户下启动的,上面的修改只不过是保证普通用户可以正常启动 Apache 而已。另外,启动的 httpd 进程对应的用户除了 root,还有 www 用户,这其实是一种父进程和子进程的关系,父进程由 root 用户启动后,会派生出多个子进程,而这些子进程的启动用户是可定义的,可以在配置文件 httpd.conf 的如下选项中修改:
User www Group www
至此,这个案例得到完整剖析!
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论