PHP看门狗脚本怎么写

wen PHP项目 1

本文目录导读:

PHP看门狗脚本怎么写

  1. 基础版 - 定时检查进程是否运行
  2. 进阶版 - 支持多进程和健康检查
  3. 守护进程版 - 作为系统服务运行
  4. 使用Systemd托管(Linux推荐)
  5. 使用建议

我来给你写几个不同场景的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

使用建议

  1. 配置文件化:将监控的服务信息放入配置文件(JSON/YAML)
  2. 增加通知机制:集成邮件、短信、企业微信等告警
  3. 合并到crontab:如果没有daemon环境,可以用crontab定期执行
  4. 增加状态持久化:重启后保留统计信息
  5. 完善日志记录:记录所有操作和异常

需要根据具体的使用场景选择合适的方案。

抱歉,评论功能暂时关闭!