1. 全局异常捕获(基础防护)
// 注册全局错误处理器(处理所有未被捕获的异常)
set_exception_handler(function (Throwable $e) {
// 记录到文件(实际生产环境应使用日志服务)
file_put_contents(
'/var/log/swoole_error.log',
"[UNCAUGHT_EXCEPTION] ".date('Y-m-d H:i:s')." {$e->getMessage()}\\n",
FILE_APPEND
);
// 发送报警(示例:调用企业微信机器人)
$this->sendAlert("Critical error: {$e->getMessage()}");
// 重要!防止异常导致进程退出
return true;
});
// 设置错误处理器(处理 E_ERROR 等)
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
知识点解析:
- set_exception_handler:捕获所有未处理的异常
- FILE_APPEND:追加写入日志文件
- ErrorException:将传统错误转换为异常处理
- 为什么重要:防止单个请求的异常导致整个 Worker 进程崩溃
2. Worker 进程管理(稳定性核心)
$server = new Swoole\\Http\\Server('0.0.0.0', 9501);
// Worker 进程设置
$server->set([
'worker_num' => 4,
'max_request' => 10000, // 每个 Worker 处理 10000 次请求后重启
'reload_async' => true // 安全重启模式
]);
// Worker 进程退出时回调
$server->on('WorkerExit', function ($server, $workerId) {
// 释放长连接等资源
$this->releaseDatabaseConnections();
echo "Worker {$workerId} is exiting gracefully\\n";
});
// Worker 进程错误处理
$server->on('WorkerError', function ($server, $workerId, $exitCode, $signal) {
$msg = "Worker {$workerId} crashed. Code:{$exitCode} Signal:{$signal}";
file_put_contents('/var/log/swoole_worker.log', $msg, FILE_APPEND);
$this->restartWorker($workerId); // 自定义重启逻辑
});
关键配置解析:
- max_request:预防内存泄漏的黄金配置
- reload_async:平滑重启不中断服务
- WorkerExit:用于资源清理的黄金时机
- WorkerError:最后的防护网,记录致命错误
3. 协程异常处理(关键细节)
$server->on('Request', function ($request, $response) {
// 每个请求创建新的协程
go(function () use ($request, $response) {
try {
// 业务逻辑代码
$result = $this->handleRequest($request);
// 发送响应
$response->end($result);
} catch (Throwable $e) {
// 业务异常处理
$response->status(500);
$response->end('Service Unavailable');
// 记录详细错误
$this->logError($e, [
'uri' => $request->server['request_uri'],
'params' => $request->get
]);
}
});
});
为什么需要:
- 协程内的异常不会自动冒泡到全局处理器
- 重要原则:每个协程都是独立的执行上下文,必须单独处理异常
4. 内存管理(防 OOM 关键)
// 定时内存检查(每秒执行)
Timer::tick(1000, function () {
$usedMem = memory_get_usage(true) / 1024 / 1024; // 单位 MB
// 当内存超过 512MB 时告警
if ($usedMem > 512) {
$this->sendAlert("Memory high: {$usedMem}MB");
}
// 超过 1GB 主动退出 Worker(由 Manager 进程重启)
if ($usedMem > 1024) {
posix_kill(posix_getpid(), SIGTERM); // 优雅终止当前进程
}
});
内存管理策略:
5. 网络连接可靠性(TCP 层防护)
$server->set([
'heartbeat_check_interval' => 60, // 60秒检测一次
'heartbeat_idle_time' => 600 // 600秒无活动断开连接
]);
// 处理连接关闭事件
$server->on('Close', function ($server, $fd) {
// 清理连接相关资源
$this->cleanConnectionResources($fd);
});
// 自定义连接管理器
class ConnectionManager {
private $connections = [];
public function add($fd) {
$this->connections[$fd] = [
'last_active' => time(),
'ip' => $server->getClientInfo($fd)['remote_ip']
];
}
public function checkAlive() {
foreach ($this->connections as $fd => $info) {
if (time() – $info['last_active'] > 300) {
$server->close($fd); // 关闭不活跃连接
}
}
}
}
网络层保护:
- 心跳检测:自动清理僵尸连接
- 连接追踪:防止连接泄露
- 资源回收:避免文件描述符耗尽
6. 熔断降级机制(防雪崩)
class CircuitBreaker {
private $failures = 0;
private $lastFailureTime = 0;
private $threshold = 5; // 5次失败触发熔断
private $timeout = 30; // 熔断30秒
public function call(callable $action) {
if ($this->isOpen()) {
throw new Exception('Service unavailable');
}
try {
$result = $action();
$this->reset();
return $result;
} catch (Exception $e) {
$this->recordFailure();
throw $e;
}
}
private function isOpen() {
return $this->failures >= $this->threshold &&
(time() – $this->lastFailureTime) < $this->timeout;
}
private function recordFailure() {
$this->failures++;
$this->lastFailureTime = time();
}
}
// 使用示例
$breaker = new CircuitBreaker();
$response = $breaker->call(function () {
return $this->callExternalService();
});
熔断器原理:
7. 全链路监控(可视化保障)
// 在请求入口处打点
$server->on('Request', function ($request, $response) {
$traceId = uniqid(); // 生成唯一追踪ID
// 记录开始时间
$startTime = microtime(true);
try {
// 处理请求…
} finally {
// 记录耗时和状态
$cost = round((microtime(true) – $startTime) * 1000, 2);
$this->logRequest($traceId, $request, $cost);
}
});
// Prometheus 监控示例
$registry = new Prometheus\\CollectorRegistry();
$counter = $registry->registerCounter(
'swoole',
'http_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
);
// 在请求处理中埋点
$counter->inc([
$request->server['request_method'],
parse_url($request->server['request_uri'], PHP_URL_PATH),
$response->statusCode
]);
监控维度:
完整错误处理流程图
请求进入
├─ 全局异常捕获(最后防线)
├─ 协程级 try-catch(业务异常)
├─ 熔断器检查(防雪崩)
├─ 资源限制检查(内存/连接数)
├─ 业务处理
├─ 网络超时控制
└─ 响应返回
├─ 成功:记录监控指标
└─ 失败:累计熔断计数
重点策略总结
全局异常捕获 | 未捕获异常导致的进程退出 | set_exception_handler |
Worker 管理 | 进程级稳定性 | max_request + 优雅重启 |
协程异常处理 | 协程内异常传播 | 协程级 try-catch |
内存管理 | OOM(内存溢出) | 定时检查 + 主动回收 |
连接管理 | 文件描述符耗尽 | 心跳检测 + 空闲断开 |
熔断降级 | 服务雪崩效应 | 失败计数 + 熔断状态机 |
全链路监控 | 快速定位问题 | 指标埋点 + 可视化仪表盘 |
代码实践建议
渐进式实施:
// 第一步:先添加全局异常处理
set_exception_handler(…);
// 第二步:添加 Worker 配置
'max_request' => 1000,
// 第三步:逐步添加其他机制
测试验证方法:
// 模拟内存泄漏
function leakMemory() {
static $data = [];
$data[] = str_repeat('*', 1024 * 1024); // 每次泄漏 1MB
}
// 模拟致命错误
function causeFatal() {
new NonExistingClass(); // 触发自动捕获
}
监控看板示例(Prometheus + Grafana):
- HTTP 请求成功率
- 内存/CPU 使用趋势
- 活跃连接数
- 熔断器状态
通过以上策略的组合实施,可以构建一个具备自我修复能力的 Swoole 服务。关键是要理解:错误处理不是单一技术点的堆砌,而是从进程管理、资源控制、异常捕获到监控告警的全方位体系。
评论前必须登录!
注册