本文目录导读:

我来帮你详细解释PHP的自动恢复机制和相关实现方法。
🚀 PHP自动恢复的主要方式
进程管理器的自动重启
使用进程管理器(如Supervisor、PM2)监控PHP进程:
# Supervisor配置示例 [program:php-worker] command=php /path/to/your/script.php autostart=true autorestart=true startretries=3 user=www-data
PHP内置错误处理与恢复
<?php
// 设置错误处理函数
set_error_handler(function($errno, $errstr, $errfile, $errline) {
// 记录错误
error_log("Error: [$errno] $errstr in $errfile on line $errline");
// 尝试恢复
if ($errno == E_WARNING || $errno == E_NOTICE) {
// 对于警告和通知,尝试继续执行
return true;
}
// 对于致命错误,执行恢复逻辑
if ($errno == E_ERROR || $errno == E_USER_ERROR) {
restoreErrorHandler();
die("致命错误,正在尝试恢复...");
}
return false;
});
?>
异常捕获与自动恢复
<?php
class AutoRecovery {
private $maxRetries = 3;
private $retryDelay = 5; // 秒
public function executeWithRecovery($callback, $args = []) {
$attempts = 0;
while ($attempts < $this->maxRetries) {
try {
return call_user_func_array($callback, $args);
} catch (Exception $e) {
$attempts++;
// 记录错误
error_log("Attempt $attempts failed: " . $e->getMessage());
if ($attempts >= $this->maxRetries) {
throw new Exception("All recovery attempts failed");
}
// 等待后重试
sleep($this->retryDelay);
// 执行恢复清理
$this->performCleanup();
}
}
}
private function performCleanup() {
// 关闭所有数据库连接
// 重置状态
// 清理临时文件等
}
}
?>
使用信号处理实现平滑重启
<?php
// 设置信号处理器
pcntl_signal(SIGTERM, function($signal) {
// 优雅关闭
echo "Received termination signal, shutting down gracefully...\n";
// 保存状态
// 关闭连接
// 执行清理
exit(0);
});
// 设置重生信号
pcntl_signal(SIGUSR1, function($signal) {
echo "Received restart signal, restarting...\n";
// 创建子进程
$pid = pcntl_fork();
if ($pid == -1) {
die("Could not fork");
} else if ($pid) {
// 父进程退出
exit(0);
}
// 子进程继续执行
});
?>
守护进程模式
<?php
class DaemonProcess {
private $running = true;
private $maxMemory = 100 * 1024 * 1024; // 100MB
public function run($callback) {
// 成为守护进程
$this->daemonize();
while ($this->running) {
try {
call_user_func($callback);
// 检查内存使用
if (memory_get_usage() > $this->maxMemory) {
$this->restart();
}
// 检查时间,定期重启
if (time() - $GLOBALS['startTime'] > 3600) {
$this->restart();
}
} catch (Exception $e) {
error_log("Error in daemon: " . $e->getMessage());
$this->restart();
}
}
}
private function daemonize() {
$pid = pcntl_fork();
if ($pid == -1) {
die("Could not fork");
} else if ($pid > 0) {
exit(0); // 退出父进程
}
// 子进程继续
posix_setsid();
// 关闭标准I/O
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$GLOBALS['startTime'] = time();
}
private function restart() {
// 发送重启信号给自己
posix_kill(getmypid(), SIGUSR1);
}
}
?>
使用PHP-FPM的自动恢复
# php-fpm.conf 配置 pm.max_children = 50 pm.start_servers = 5 pm.min_spare_servers = 2 pm.max_spare_servers = 10 pm.max_requests = 500 # 处理500个请求后重启worker
健康检查与自动恢复
<?php
class HealthChecker {
private $checkInterval = 30; // 30秒
private $failureCount = 0;
private $maxFailures = 3;
public function monitor($processName) {
while (true) {
if ($this->isProcessAlive($processName)) {
$this->failureCount = 0;
} else {
$this->failureCount++;
if ($this->failureCount >= $this->maxFailures) {
$this->restartProcess($processName);
$this->failureCount = 0;
}
}
sleep($this->checkInterval);
}
}
private function isProcessAlive($processName) {
exec("pgrep -f $processName", $output, $returnCode);
return $returnCode == 0;
}
private function restartProcess($processName) {
exec("pkill -f $processName");
sleep(2);
exec("php /path/to/$processName > /dev/null 2>&1 &");
error_log("Restarted process: $processName");
}
}
?>
🛠️ 最佳实践建议
完整示例:结合多种恢复机制
<?php
class RobustWorker {
private $maxRetries = 5;
private $redis;
private $db;
public function __construct() {
$this->initConnections();
$this->setupSignalHandlers();
}
public function start() {
while (true) {
try {
$this->processQueue();
} catch (Exception $e) {
$this->handleFailure($e);
}
// 定期休息
usleep(100000); // 100ms
}
}
private function initConnections() {
try {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
$this->db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
} catch (Exception $e) {
// 连接失败,等待后重试
sleep(5);
$this->initConnections();
}
}
private function setupSignalHandlers() {
pcntl_signal(SIGTERM, function() {
$this->gracefulShutdown();
});
pcntl_signal(SIGHUP, function() {
$this->reloadConfig();
});
}
private function processQueue() {
$data = $this->redis->rpop('queue');
if ($data) {
$this->processData($data);
}
}
private function processData($data) {
$retries = 0;
while ($retries < $this->maxRetries) {
try {
// 处理数据
$this->db->beginTransaction();
// ... 业务逻辑
$this->db->commit();
return true;
} catch (PDOException $e) {
$this->db->rollBack();
$retries++;
if ($retries >= $this->maxRetries) {
// 重新连接数据库
$this->reconnectDB();
return false;
}
sleep(pow(2, $retries)); // 指数退避
}
}
}
private function reconnectDB() {
$this->db = null;
sleep(5);
$this->initConnections();
}
private function gracefulShutdown() {
echo "Shutting down gracefully...\n";
// 完成当前任务
// 保存状态
exit(0);
}
private function reloadConfig() {
echo "Reloading configuration...\n";
// 重新加载配置
}
private function handleFailure($exception) {
error_log("Worker failure: " . $exception->getMessage());
// 记录到监控系统
// 发送告警
sleep(5); // 等待后继续
}
}
// 启动worker
$worker = new RobustWorker();
$worker->start();
?>
📊 监控与告警建议
-
使用系统监控工具
- Monit
- Nagios
- Zabbix
-
日志记录
// 使用Monolog记录关键错误 $log->error('Process crashed, restarting...', [ 'pid' => getmypid(), 'memory' => memory_get_usage(true) ]); -
设置资源限制
; php.ini max_execution_time = 300 memory_limit = 256M display_errors = Off log_errors = On error_log = /var/log/php_errors.log
这些方法可以根据你的具体需求组合使用,实现可靠的PHP自动恢复机制,记得根据实际场景调整重试次数、等待时间等参数。