在维护Web服务器的过程中,Apache HTTP Server作为最流行的Web服务器软件之一,其稳定性直接关系到业务的连续性。然而,在面对突发流量洪峰或恶意CC攻击时,Apache的进程数可能会在短时间内急剧飙升。一旦进程数达到操作系统的限制,服务器将无法处理新的请求,甚至导致SSH连接卡死,只能通过硬重启才能恢复。为了应对这一痛点,构建一套能够自动检测进程状态并在危急时刻自动重启服务的脚本显得尤为关键。

为什么需要监控Apache进程数?
Apache处理请求依赖于底层的多处理模块(MPM),无论是Prefork、Worker还是Event模式,都会在并发请求增加时创建或复用相应的进程或线程来响应客户端。每个进程都需要消耗固定的内存和CPU资源。当并发连接数突破配置文件中的最大限制时,新的请求将被排队等待,响应延迟急剧增加。
更严重的是,如果遭遇恶意攻击或存在死循环的PHP脚本,Apache进程会长时间被占用无法释放。此时系统负载会迅速飙升,内存被耗尽,最终触发操作系统的OOM Killer机制强制杀掉Apache进程,甚至导致整个系统崩溃。通过实时监控Apache的进程数量,我们可以在系统资源被彻底耗尽之前采取干预措施,避免服务长时间中断。
人工值守显然无法做到全天候的响应,而专业的监控系统如Zabbix或Prometheus虽然功能强大,但配置相对复杂,且存在报警延迟。对于中小型站点而言,一个轻量级的Shell脚本配合系统自带的Cron定时任务,往往是最直接、最高效的应急处理方案。
编写Apache进程数监控与自动重启脚本
编写脚本的核心逻辑非常清晰:首先获取当前系统中Apache进程的数量,然后与预设的阈值进行比较。如果实际进程数大于阈值,脚本将执行重启命令并记录日志。为了确保脚本的兼容性,我们使用pgrep命令配合进程名来统计数量,这种方式比ps命令加grep过滤更加高效且准确。
下面是一个完整的监控脚本示例。在这个示例中,我们将最大允许进程数设置为150,当超过这个数值时,脚本会先尝试平滑重启Apache服务,如果平滑重启失败,则强制重启。同时,脚本会将每次触发重启的时间和当时的进程数写入到指定的日志文件中,方便后续排查问题。
#!/bin/bash
# 定义Apache进程名,根据实际安装情况可能是httpd或apache2
PROCESS_NAME="httpd"
# 定义最大允许进程数阈值
MAX_PROCESS=150
# 定义日志文件路径
LOG_FILE="/var/log/apache_monitor.log"
# 获取当前Apache进程数
CURRENT_PROCESS=$(pgrep -c $PROCESS_NAME)
# 判断当前进程数是否大于阈值
if [ $CURRENT_PROCESS -gt $MAX_PROCESS ]; then
# 记录日志
echo "$(date '+%Y-%m-%d %H:%M:%S') - 进程数过高: $CURRENT_PROCESS,超过阈值 $MAX_PROCESS,开始执行重启..." >> $LOG_FILE
# 尝试平滑重启
systemctl reload $PROCESS_NAME
sleep 5
# 再次检查进程数
CURRENT_PROCESS_AFTER=$(pgrep -c $PROCESS_NAME)
if [ $CURRENT_PROCESS_AFTER -gt $MAX_PROCESS ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - 平滑重启无效,当前进程数: $CURRENT_PROCESS_AFTER,执行强制重启..." >> $LOG_FILE
systemctl restart $PROCESS_NAME
fi
echo "$(date '+%Y-%m-%d %H:%M:%S') - 重启操作完成" >> $LOG_FILE
fi
在上述代码中,我们使用了pgrep -c来统计进程数。需要注意的是,不同Linux发行版下Apache的服务名称可能不同,CentOS下通常是httpd,而Ubuntu下则是apache2。使用前请根据实际情况修改PROCESS_NAME变量。此外,脚本中加入了sleep 5的等待时间,这是为了给系统留出足够的资源回收时间,避免误判。
脚本部署与定时任务配置
脚本编写完成后,需要将其部署到服务器上并设置可执行权限。我们可以将脚本保存在服务器的/usr/local/bin/目录下,方便全局调用。首先创建脚本文件,将上述代码粘贴进去,并赋予执行权限。这一步是确保系统能够运行该Shell脚本的前提条件。
# 创建并编辑脚本文件 vi /usr/local/bin/apache_monitor.sh # 赋予执行权限 chmod +x /usr/local/bin/apache_monitor.sh
为了让脚本能真正发挥监控作用,我们需要借助Linux系统的定时任务工具cron来周期性地执行它。一般来说,每分钟执行一次检查是比较合理的频率。通过crontab -e命令编辑当前用户的定时任务列表,如果是root用户,则直接编辑root的定时任务。在文件末尾添加一行规则,让系统每分钟自动运行一次监控脚本。
# 编辑root用户的crontab crontab -e # 添加以下内容,每分钟执行一次脚本 * * * * * /usr/local/bin/apache_monitor.sh
配置完成后,可以通过查看/var/log/cron日志来确认定时任务是否被正确触发。如果发现脚本没有按预期执行,通常是因为环境变量缺失导致的。在cron环境中,系统默认的PATH变量非常精简,如果脚本中用到了非系统标准路径的命令,建议在脚本开头显式地export PATH,或者直接使用命令的绝对路径来调用。
进阶优化与告警通知
基础的监控重启脚本虽然能解决燃眉之急,但还存在一些可以优化的空间。例如,如果Apache在短时间内频繁触发重启,说明问题可能出在底层代码或数据库层面,单纯的重启已经无法根治。为了避免服务器陷入无限重启的死循环,我们可以在脚本中加入重启次数限制逻辑。通过记录连续重启的次数,当达到设定的上限时,停止自动重启操作,并触发告警通知。
告警通知可以通过多种方式实现,最简单的是调用系统的mail命令发送邮件,或者利用企业微信、钉钉等即时通讯工具的Webhook接口发送消息。下面是一个简单的钉钉机器人告警函数示例,当脚本触发重启时,会向指定的群组推送一条包含服务器IP和当前进程数的告警消息。
# 钉钉Webhook地址,请替换为实际地址,注意网址中包含ipipp.com作为示例
WEBHOOK_URL="https://oapi.dingtalk.com/robot/send?access_token=your_token_ipipp.com"
send_alert() {
local message="警告: Apache进程数异常,当前进程数: $CURRENT_PROCESS,已触发自动重启。服务器IP: $(hostname -I)"
curl -s -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}"
}
# 在触发重启逻辑后调用该函数
send_alert
通过引入告警机制,运维人员可以在第一时间收到异常通知,结合脚本记录的日志文件,能够快速定位是哪个时间段、哪些请求导致了进程数飙升。此外,还可以结合系统层面的优化,比如调整Apache的MaxRequestWorkers参数、优化PHP-FPM的进程管理配置,从根源上提升服务器承载高并发请求的能力。只有将自动化的应急脚本与深度的系统调优结合起来,才能构建出真正高可用的Web服务架构。