本文目录导读:

在 PHP 项目的负载均衡架构中,健康检测的目的是确保负载均衡器只将流量转发到正常工作的后端节点,避免请求失败或响应超时。
根据你的负载均衡器类型(Nginx、HAProxy、云服务商 LB 等),健康检测的方式和配置有所不同,以下是几种主流的方案及其 PHP 侧的最佳实践。
基于 HTTP 的主动健康检测(最常用)
负载均衡器定期(如每 5 秒)向每个 PHP 后端节点发送一个 HTTP 请求(如 GET /health),如果返回的状态码在 200-399 之间,则认为该节点健康;否则标记为宕机。
1 PHP 端实现一个健康检查端点
这是推荐做法,你需要在 PHP 应用中创建一个专门的路由(如 /health 或 /healthz),该路由不依赖数据库、Redis 或外部 API。
// health_check.php 或 Laravel/Symfony 的路由
header('Content-Type: application/json');
$status = [
'status' => 'ok',
'timestamp' => time(),
'hostname' => gethostname() // 方便调试
];
// 可选:检查 PHP-FPM 是否存活(如果使用 fastcgi)
// 如果代码能执行到这里,说明 PHP-FPM 是活的
// 返回 200
http_response_code(200);
echo json_encode($status);
exit;
配置示例:
-
Nginx + PHP-FPM 场景: 确保
/health请求不经过复杂的 PHP 框架路由,或者创建一个独立的、无依赖的健康检查文件。 -
Nginx 配置(upstream):
upstream php_backend { server 192.168.1.10:9000; server 192.168.1.11:9000; } server { listen 80; # ... # 注意:Nginx 的 health_check 需要商业版(NGINX Plus)或使用第三方模块 # 标准 Nginx 通常需要外部工具或结合 nginx_http_upstream_check_module # 更常见的做法:使用外部检查脚本(如 curl)并配合 Nginx 的 fail_timeout # 或者配合 keepalived + consul 等 }
2 负载均衡器配置示例
-
HAProxy:
frontend http-in bind *:80 default_backend php_servers backend php_servers mode http # 主动检查:每 2 秒检查一次 /health,超时 1 秒 option httpchk GET /health http-check expect status 200 server php1 192.168.1.10:8080 check inter 2s fall 3 rise 2 server php2 192.168.1.11:8080 check inter 2s fall 3 rise 2 -
AWS ALB(应用负载均衡器): 在 Target Group 设置中,指定健康检查路径为
/health,协议为 HTTP,响应超时和间隔。 -
Kubernetes (K8s) Liveness Probe / Readiness Probe: PHP 运行在 Pod 中:
livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 5 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 5
基于 TCP 的被动健康检测(简易)
负载均衡器只检查 PHP 后端的端口(如 9000 或 8080)是否处于监听状态。
- 优点: 简单,无需编写额外代码。
- 缺点: 不精准,PHP-FPM 可能已经挂起、处于死锁状态或内存耗尽,但端口依然在监听(由 master 进程保持),流量依然会被转发,导致 502 或超时。
# Nginx 示例(使用 fail_timeout)
upstream php_backend {
server 192.168.1.10:9000 max_fails=2 fail_timeout=30s;
server 192.168.1.11:9000 max_fails=2 fail_timeout=30s;
}
Nginx 会将连接失败视为请求失败,将节点暂时标记为不可用。
不建议仅依赖 TCP 检测,建议结合 HTTP 检测。
自定义健康检查逻辑(推荐用于复杂场景)
在 /health 端点中,可以加入更详细的检查,以确保 PHP 应用的核心功能正常。
// /health endpoint
$checks = [
'php_version' => PHP_VERSION,
'db' => false, 'redis' => false, 'temp_dir' => false
];
// 1. 检查数据库连接(重要)
try {
$dbh = new PDO('mysql:host=...;dbname=...', 'user', 'pass', [PDO::ATTR_TIMEOUT => 1]);
// 执行一个简单的查询
$dbh->query('SELECT 1');
$checks['db'] = true;
} catch (Exception $e) {
// 数据库挂了,可能仍返回 200?取决于你的策略
// DB 挂了但网站读缓存,可能还能提供服务
$checks['db'] = false;
}
// 2. 检查 Redis 缓存
try {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 1);
$redis->ping();
$checks['redis'] = true;
} catch (Exception $e) {
$checks['redis'] = false;
}
// 3. 判定整体健康度
$overallHealthy = $checks['db'] && $checks['redis'];
if ($overallHealthy) {
http_response_code(200);
} else {
// 如果某个服务挂了,返回 503,负载均衡器会标记节点为不健康
http_response_code(503);
}
header('Content-Type: application/json');
echo json_encode(['status' => $overallHealthy ? 'ok' : 'degraded', 'checks' => $checks]);
注意: 如果健康检查太复杂或超时时间长,会导致所有节点被误判为不健康,建议健康检查端点保持轻量、快速(超时 < 1 秒)。
动态移除与恢复
健康检测通常伴随以下机制:
- 失败次数(fall): 连续失败 N 次后,节点被标记为“不健康”。
- 恢复次数(rise): 连续成功 M 次后,节点恢复。
- 恢复后缓慢启动(slow start): 节点恢复后,先少量分配流量,防止大量请求瞬间涌入造成雪崩。
HAProxy 示例:
server php1 192.168.1.10:8080 check inter 5s fall 3 rise 2 slowstart 30s
常见问题与注意事项
- OPcache 与健康检测: 健康检测请求本身会触发 OPcache 检查,PHP 代码有问题,健康检查端点也会报错,这是正常的。
- Session 亲和性(Sticky Session): 如果使用 Session,健康检测不会包含 Session 信息,当一个节点宕机后,用户的 Session 会丢失(除非 Session 存储在 Redis/Memcached 等中心化外部存储中)。
- 高并发下的健康检测: 健康检测本身会产生压力,如果节点很多(>100),调整检查间隔(如 10s)减轻压力。
- 不要与主应用路由冲突: 确保
/health路由不受框架中间件(如 CSRF、Auth)影响。 - Laravel 等框架示例(在
routes/web.php或routes/api.php中):Route::get('/health', function () { return response()->json(['status' => 'ok']); })->middleware([]); // 空中间件
总结建议
- 首选方案: 使用HTTP + 特定路径(/health) 进行健康检测。
- PHP 侧: 实现一个轻量级的
/health端点,检查但不一定必须依赖外部服务(根据业务容忍度决定)。 - 负载均衡器: HAProxy 或云服务商的 LB 配置
option httpchk GET /health并检查 200 状态码。 - 避免仅使用 TCP 检测,它无法反映 PHP 应用的真实状态。
这样配置后,当一个 PHP 节点发生故障(如 PHP-FPM 进程 Hung、内存溢出、数据库连接池满),负载均衡器会很快将其摘除,对其他用户无影响。