下面是一个 Python 脚本,用于监控 PHP-FPM 进程的 CPU 使用率,并在超过阈值时自动杀死这些进程。
#!/usr/bin/env python3
import os
import psutil
import time
import argparse
from datetime import datetime
def monitor_php_fpm(cpu_threshold, check_interval, max_duration):
"""
监控 PHP-FPM 进程,杀死 CPU 使用率超过阈值的进程
参数:
cpu_threshold (float): CPU 使用率阈值(百分比)
check_interval (int): 检查间隔(秒)
max_duration (int): 最大允许持续时间(秒)
"""
print(f"开始监控 PHP-FPM 进程,CPU 阈值: {cpu_threshold}%,检查间隔: {check_interval}秒")
# 存储进程和其高CPU使用的开始时间
high_cpu_processes = {}
while True:
try:
current_time = time.time()
# 查找所有 PHP-FPM 进程
for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'cpu_percent']):
try:
# 检查是否是 PHP-FPM 进程
if proc.info['name'] == 'php-fpm' or 'php-fpm' in ' '.join(proc.info['cmdline'] or []):
cpu_percent = proc.cpu_percent(interval=0.1)
if cpu_percent > cpu_threshold:
pid = proc.info['pid']
if pid not in high_cpu_processes:
high_cpu_processes[pid] = current_time
print(f"[{datetime.now()}] 检测到高CPU进程 PID: {pid}, CPU: {cpu_percent}%")
else:
duration = current_time - high_cpu_processes[pid]
if duration >= max_duration:
# 杀死进程
proc.kill()
print(f"[{datetime.now()}] 已杀死进程 PID: {pid}, 持续高CPU: {duration:.1f}秒, CPU: {cpu_percent}%")
del high_cpu_processes[pid]
else:
# CPU 恢复正常,从监控中移除
if proc.info['pid'] in high_cpu_processes:
del high_cpu_processes[proc.info['pid']]
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
# 清理已经不存在的进程
for pid in list(high_cpu_processes.keys()):
if not psutil.pid_exists(pid):
del high_cpu_processes[pid]
time.sleep(check_interval)
except KeyboardInterrupt:
print("\n监控已停止")
break
except Exception as e:
print(f"发生错误: {e}")
time.sleep(check_interval)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='监控 PHP-FPM 进程 CPU 使用率并自动杀死高占用进程')
parser.add_argument('--threshold', type=float, default=90.0, help='CPU 使用率阈值(百分比)')
parser.add_argument('--interval', type=int, default=5, help='检查间隔(秒)')
parser.add_argument('--duration', type=int, default=30, help='最大允许持续时间(秒)')
args = parser.parse_args()
monitor_php_fpm(args.threshold, args.interval, args.duration)
使用说明
- 将上述脚本保存为
php_fpm_monitor.py - 确保已安装 Python 3 和 psutil 库(可通过
pip install psutil安装) - 运行脚本:
python3 php_fpm_monitor.py
可选参数
--threshold: CPU 使用率阈值(默认90%)--interval: 检查间隔时间(默认5秒)--duration: 允许高CPU持续的最长时间(默认30秒)
示例:设置阈值为80%,检查间隔10秒,最大持续时间60秒
python3 php_fpm_monitor.py --threshold 80 --interval 10 --duration 60
注意事项
- 脚本需要以 root 权限运行才能杀死进程
- 建议先在测试环境中验证脚本行为
- 可以结合系统服务(如 systemd)将脚本设置为后台运行
- 频繁杀死 PHP-FPM 进程可能影响网站正常运行,建议先调查高CPU使用的原因
将Python脚本包装成systemctl服务
将Python脚本作为systemd服务运行可以让你的脚本在系统启动时自动运行,并且可以方便地管理(启动、停止、查看状态等)。以下是详细步骤:
1. 创建服务文件
在/etc/systemd/system/目录下创建一个以.service结尾的服务文件,例如:
vim /etc/systemd/system/php_fpm_monitor.service
2. 编写服务文件内容
[Unit] Description=PHP-FPM Monitor Service After=network.target [Service] User=root Group=root WorkingDirectory=/www/scripts ExecStart=/usr/bin/python3 /www/scripts/php_fpm_monitor.py Restart=always RestartSec=3 Environment=PYTHONUNBUFFERED=1 [Install] WantedBy=multi-user.target
参数说明:
- Description: 服务的描述
- User/Group: 运行脚本的用户和组
- WorkingDirectory: 脚本所在目录
- ExecStart: 启动命令(使用完整路径)
- Restart: 设置自动重启策略
- Environment: 设置环境变量(PYTHONUNBUFFERED=1确保日志实时输出)
3.重新加载systemd配置
systemctl daemon-reload
4.启用并启动服务
# 设置服务 systemctl enable php_fpm_monitor.service # 启动服务 systemctl start php_fpm_monitor.service
5.检查服务状态
systemctl status php_fpm_monitor.service
6. 常用命令
- 启动服务:
systemctl start php_fpm_monitor - 停止服务:
systemctl stop php_fpm_monitor - 重启服务:
systemctl restart php_fpm_monitor - 查看日志:
journalctl -u php_fpm_monitor -f
高级配置建议
- 日志记录:考虑在Python脚本中使用logging模块,并将日志输出到特定文件
- 环境变量:可以使用
EnvironmentFile指令加载包含环境变量的文件 - 资源限制:可以设置内存限制、CPU优先级等
- 依赖关系:使用
After和Requires指定服务依赖关系
示例完整服务文件
[Unit] Description=Web Scraping Service After=network.target postgresql.service [Service] User=scraper Group=scraper WorkingDirectory=/home/scraper/web_scraper EnvironmentFile=/home/scraper/web_scraper/.env ExecStart=/home/scraper/web_scraper/venv/bin/python /home/scraper/web_scraper/main.py Restart=on-failure RestartSec=30 StandardOutput=file:/var/log/web_scraper/out.log StandardError=file:/var/log/web_scraper/err.log [Install] WantedBy=multi-user.target