本文目录导读:

我来给你写几个不同场景的PHP看门狗脚本示例:
基础版 - 定时检查进程是否运行
<?php
/**
* 基础看门狗脚本 - 检查指定进程是否运行
* 运行方式:php watchdog.php
*/
class Watchdog {
private $processName;
private $restartCommand;
private $checkInterval = 60; // 检查间隔(秒)
private $logFile;
public function __construct($processName, $restartCommand, $logFile = 'watchdog.log') {
$this->processName = $processName;
$this->restartCommand = $restartCommand;
$this->logFile = $logFile;
}
// 检查进程是否运行
private function isProcessRunning() {
// Linux/Mac 系统
if (PHP_OS_FAMILY === 'Linux' || PHP_OS_FAMILY === 'Darwin') {
exec("pgrep -f '{$this->processName}'", $output);
return !empty($output);
}
// Windows 系统
else {
exec("tasklist | findstr /i \"{$this->processName}\"", $output);
return !empty($output);
}
}
// 重启进程
private function restartProcess() {
$this->log("进程 {$this->processName} 未运行,正在重启...");
// 后台执行重启命令
if (PHP_OS_FAMILY === 'Linux' || PHP_OS_FAMILY === 'Darwin') {
exec($this->restartCommand . " > /dev/null 2>&1 &");
} else {
exec("start /B " . $this->restartCommand);
}
$this->log("重启命令已执行");
}
// 记录日志
private function log($message) {
$time = date('Y-m-d H:i:s');
file_put_contents($this->logFile, "[{$time}] {$message}\n", FILE_APPEND);
echo "[{$time}] {$message}\n";
}
// 启动看门狗
public function run() {
$this->log("看门狗启动,监控进程: {$this->processName}");
while (true) {
if (!$this->isProcessRunning()) {
$this->restartProcess();
} else {
$this->log("进程 {$this->processName} 正常运行中");
}
sleep($this->checkInterval);
}
}
}
// 使用示例
$watchdog = new Watchdog(
'my_worker.php', // 要监控的进程名
'php /path/to/my_worker.php', // 重启命令
'/var/log/watchdog.log' // 日志文件
);
$watchdog->run();
进阶版 - 支持多进程和健康检查
<?php
/**
* 进阶版看门狗 - 支持多进程监控和HTTP健康检查
* 运行方式:php watchdog_advanced.php
*/
class AdvancedWatchdog {
private $services = [];
private $checkInterval = 30;
private $logFile = 'watchdog.log';
private $maxMemoryUsage = 104857600; // 100MB
public function __construct($logFile = 'watchdog.log') {
$this->logFile = $logFile;
}
// 添加要监控的服务
public function addService($name, $config) {
$this->services[$name] = array_merge([
'command' => '',
'process_name' => '',
'health_check_url' => null,
'restart_command' => null,
'max_restarts' => 5, // 最大重启次数
'restart_count' => 0,
'last_restart_time' => 0,
'min_restart_interval' => 60 // 最小重启间隔(秒)
], $config);
}
// 检查进程状态
private function checkProcessStatus($service) {
$processName = $service['process_name'];
if (PHP_OS_FAMILY === 'Linux' || PHP_OS_FAMILY === 'Darwin') {
exec("pgrep -f '{$processName}'", $pids);
return !empty($pids);
} else {
exec("tasklist | findstr /i \"{$processName}\"", $output);
return !empty($output);
}
}
// HTTP健康检查
private function healthCheckUrl($url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 检查响应
if ($httpCode != 200) {
return false;
}
// 如果需要,可以检查响应内容
// return strpos($response, 'OK') !== false;
return true;
}
// 检查内存使用
private function checkMemoryUsage($processName) {
if (PHP_OS_FAMILY !== 'Linux') {
return true; // 非Linux系统跳过内存检查
}
exec("ps aux | grep '{$processName}' | grep -v grep", $output);
foreach ($output as $line) {
// 解析内存使用(RSS列)
$parts = preg_split('/\s+/', $line);
if (isset($parts[5])) {
$memoryKB = (int)$parts[5];
if ($memoryKB * 1024 > $this->maxMemoryUsage) {
return false;
}
}
}
return true;
}
// 重启服务
private function restartService($name, $service) {
$now = time();
// 检查重启次数限制
if ($service['restart_count'] >= $service['max_restarts']) {
$this->log("服务 {$name} 已达到最大重启次数,发送告警", 'ERROR');
$this->sendAlert("服务 {$name} 连续失败,需要人工介入");
return;
}
// 检查重启间隔
if (($now - $service['last_restart_time']) < $service['min_restart_interval']) {
$this->log("服务 {$name} 重启过于频繁,跳过此次重启", 'WARNING');
return;
}
$this->log("重启服务: {$name}", 'INFO');
// 执行重启命令
$restartCommand = $service['restart_command'] ?? $service['command'];
if (PHP_OS_FAMILY === 'Linux' || PHP_OS_FAMILY === 'Darwin') {
exec($restartCommand . " > /dev/null 2>&1 &");
} else {
exec("start /B " . $restartCommand);
}
// 更新状态
$service['restart_count']++;
$service['last_restart_time'] = $now;
$this->services[$name] = $service;
$this->log("服务 {$name} 已重启 ({$service['restart_count']}/{$service['max_restarts']})", 'INFO');
}
// 发送告警
private function sendAlert($message) {
// 这里可以集成短信、邮件、微信等告警
// 示例:发送邮件
// mail('admin@example.com', 'Watchdog Alert', $message);
// 或者写日志
$this->log("告警: {$message}", 'CRITICAL');
}
// 记录日志
private function log($message, $level = 'INFO') {
$time = date('Y-m-d H:i:s');
$logMessage = "[{$time}] [{$level}] {$message}\n";
file_put_contents($this->logFile, $logMessage, FILE_APPEND);
echo $logMessage;
}
// 运行看门狗
public function run() {
$this->log("高级看门狗启动,监控 " . count($this->services) . " 个服务");
while (true) {
foreach ($this->services as $name => $service) {
$this->checkService($name, $service);
}
sleep($this->checkInterval);
}
}
// 检查单个服务
private function checkService($name, $service) {
// 1. 检查进程是否存在
if (!$this->checkProcessStatus($service)) {
$this->log("服务 {$name} 进程不存在", 'WARNING');
$this->restartService($name, $service);
return;
}
// 2. 健康检查(可选)
if ($service['health_check_url']) {
if (!$this->healthCheckUrl($service['health_check_url'])) {
$this->log("服务 {$name} HTTP健康检查失败", 'WARNING');
$this->restartService($name, $service);
return;
}
}
// 3. 内存检查
if (!$this->checkMemoryUsage($service['process_name'])) {
$this->log("服务 {$name} 内存使用过高", 'WARNING');
$this->restartService($name, $service);
return;
}
$this->log("服务 {$name} 运行正常", 'INFO');
}
}
// 使用示例
$watchdog = new AdvancedWatchdog('/var/log/advanced_watchdog.log');
// 添加Web服务监控
$watchdog->addService('webapp', [
'command' => 'php -S 0.0.0.0:8080',
'process_name' => 'php -S',
'health_check_url' => 'http://localhost:8080/health',
'restart_command' => 'nohup php -S 0.0.0.0:8080 &',
'max_restarts' => 10,
'min_restart_interval' => 120
]);
// 添加队列处理器监控
$watchdog->addService('worker', [
'command' => 'php worker.php',
'process_name' => 'worker.php',
'restart_command' => 'nohup php /path/to/worker.php &',
'max_restarts' => 20
]);
$watchdog->run();
守护进程版 - 作为系统服务运行
<?php
/**
* 守护进程版看门狗 - 通过daemonize实现后台运行
* 运行方式:php watchdog_daemon.php start|stop|status
*/
class DaemonWatchdog {
private $pidFile;
private $logFile;
private $daemonName = 'watchdog';
public function __construct($pidFile = '/tmp/watchdog.pid', $logFile = '/tmp/watchdog.log') {
$this->pidFile = $pidFile;
$this->logFile = $logFile;
}
// 守护进程化
private function daemonize() {
// 创建子进程
$pid = pcntl_fork();
if ($pid == -1) {
die("无法创建子进程\n");
} elseif ($pid > 0) {
// 父进程退出
exit(0);
}
// 子进程继续执行
posix_setsid(); // 创建新的会话
// 第二次fork,防止获取终端
$pid = pcntl_fork();
if ($pid == -1) {
die("第二次fork失败\n");
} elseif ($pid > 0) {
exit(0);
}
// 保存进程号
file_put_contents($this->pidFile, posix_getpid());
// 重定向标准输入输出
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$stdin = fopen('/dev/null', 'r');
$stdout = fopen($this->logFile, 'ab');
$stderr = fopen($this->logFile, 'ab');
return true;
}
// 启动守护进程
public function start() {
if ($this->isRunning()) {
echo "看门狗已经在运行 (PID: " . $this->getPid() . ")\n";
return;
}
echo "启动看门狗守护进程...\n";
$this->daemonize();
// 这里写看门狗的主要逻辑
$this->mainLoop();
}
// 停止守护进程
public function stop() {
if (!$this->isRunning()) {
echo "看门狗没有在运行\n";
return;
}
$pid = $this->getPid();
echo "停止看门狗 (PID: {$pid})...\n";
posix_kill($pid, SIGTERM);
// 等待进程退出
usleep(500000);
if (file_exists($this->pidFile)) {
unlink($this->pidFile);
}
echo "看门狗已停止\n";
}
// 查看状态
public function status() {
if ($this->isRunning()) {
echo "看门狗状态: 运行中 (PID: " . $this->getPid() . ")\n";
} else {
echo "看门狗状态: 未运行\n";
}
}
// 检查是否在运行
private function isRunning() {
if (!file_exists($this->pidFile)) {
return false;
}
$pid = $this->getPid();
return posix_kill($pid, 0); // 发送信号0检查进程是否存在
}
// 获取进程ID
private function getPid() {
return (int)file_get_contents($this->pidFile);
}
// 主循环
private function mainLoop() {
$this->logMessage("看门狗守护进程启动");
// 在这里实现具体的监控逻辑
while (true) {
// 监控逻辑
$this->monitorProcesses();
// 每隔60秒检查一次
sleep(60);
}
}
// 监控进程
private function monitorProcesses() {
// 检查关键进程
$processes = [
'mysql' => 'service mysql start',
'nginx' => 'service nginx start',
'php-fpm' => 'service php-fpm start'
];
foreach ($processes as $process => $restartCommand) {
exec("pgrep -f '{$process}'", $output);
if (empty($output)) {
$this->logMessage("{$process} 未运行,执行重启");
exec($restartCommand);
}
}
}
// 记录日志
private function logMessage($message) {
$time = date('Y-m-d H:i:s');
file_put_contents($this->logFile, "[{$time}] {$message}\n", FILE_APPEND);
}
// 命令行接口
public function commandLine() {
global $argv;
if (!isset($argv[1])) {
echo "使用方法: php watchdog_daemon.php {start|stop|status}\n";
exit(1);
}
switch ($argv[1]) {
case 'start':
$this->start();
break;
case 'stop':
$this->stop();
break;
case 'status':
$this->status();
break;
default:
echo "无效的命令: {$argv[1]}\n";
echo "使用方法: php watchdog_daemon.php {start|stop|status}\n";
exit(1);
}
}
}
// 使用
$daemon = new DaemonWatchdog();
$daemon->commandLine();
使用Systemd托管(Linux推荐)
创建一个systemd服务文件:
# /etc/systemd/system/watchdog.service [Unit] Description=PHP Watchdog Service After=network.target [Service] Type=simple User=www-data WorkingDirectory=/var/www ExecStart=/usr/bin/php /path/to/watchdog.php Restart=always RestartSec=60 StartLimitInterval=300 StartLimitBurst=5 EnvironmentFile=/etc/watchdog.env [Install] WantedBy=multi-user.target
使用systemd命令:
# 启动服务 sudo systemctl start watchdog # 设置开机启动 sudo systemctl enable watchdog # 查看状态 sudo systemctl status watchdog # 查看日志 journalctl -u watchdog -f
使用建议
- 配置文件化:将监控的服务信息放入配置文件(JSON/YAML)
- 增加通知机制:集成邮件、短信、企业微信等告警
- 合并到crontab:如果没有daemon环境,可以用crontab定期执行
- 增加状态持久化:重启后保留统计信息
- 完善日志记录:记录所有操作和异常
需要根据具体的使用场景选择合适的方案。