本文目录导读:

- 健康检查的核心层级
- 基础方案:简单脚本(适用于小型项目)
- 进阶方案:结构化健康检查(推荐)
- 线上生产环境的注意事项
- 进阶场景:深度业务检查(Deep Health)
- 监控集成建议
- 完整代码示例(原生PHP,无框架)
- 总结建议
在 PHP 项目中实施健康检查,关键在于分层设计和按需求关注点来构建,下面我从基础到进阶,结合实战代码,为你梳理一套完整的健康检查方案。
健康检查的核心层级
健康检查分为三个层次,你可以根据项目规模选择:
| 层级 | 目的 | 触发频率 | |
|---|---|---|---|
| Liveness | 进程是否存活、PHP-FPM是否响应 | 确认服务没死 | 高频(每10秒) |
| Readiness | 数据库连接、Redis、外部API连通性 | 确认服务能否处理请求 | 中频(每30秒) |
| Deep Health | 核心业务逻辑(如订单写入测试)、磁盘IO、队列堆积情况 | 确认“业务”是否健康 | 低频(每分钟) |
核心原则:必须使用
HTTP接口返回JSON,并配合正确的HTTP状态码(200/503)。
基础方案:简单脚本(适用于小型项目)
这是最快速的实现方式,直接创建一个路由或脚本文件。
创建检查文件 health.php(放置在Web根目录):
<?php
// 简单的健康检查:只检查PHP环境和应用是否能引导起来
require_once __DIR__ . '/vendor/autoload.php'; // 引入启动文件(如果有)
$health = [
'status' => 'ok',
'time' => date('c'),
'checks' => []
];
// 检查1:PHP版本
$health['checks']['php_version'] = phpversion();
// 检查2:类是否加载成功(如果框架核心类加载不了,这里会直接500错误)
if (!class_exists('YourFramework\Application')) {
http_response_code(503);
$health['status'] = 'error';
echo json_encode($health);
exit;
}
if ($health['status'] === 'ok') {
http_response_code(200);
} else {
http_response_code(503);
}
header('Content-Type: application/json');
echo json_encode($health);
缺点:只能检测应用能否启动,无法检测依赖服务(DB/Redis)是否可用。
进阶方案:结构化健康检查(推荐)
此方案关注 Readiness 和 Deep Health,适合中大型项目。
步骤 1:定义检查器接口
<?php
// app/Contracts/HealthCheckInterface.php
interface HealthCheckInterface
{
/**
* 执行健康检查
* @return array ['status' => 'ok'|'error', 'details' => '附加信息(如延迟ms)']
*/
public function check(): array;
}
步骤 2:实现具体检查类
示例A:数据库连接检查(MySQL / PostgreSQL)
<?php
// app/HealthChecks/DatabaseHealthCheck.php
class DatabaseHealthCheck implements HealthCheckInterface
{
protected $pdo;
public function __construct($host, $port, $name, $user, $pass)
{
// 注意:这里使用真实的短时连接,避免占用连接池
$this->pdo = new PDO("mysql:host=$host;port=$port;dbname=$name", $user, $pass, [
PDO::ATTR_TIMEOUT => 2 // 设置2秒超时
]);
}
public function check(): array
{
$start = microtime(true);
try {
$this->pdo->query('SELECT 1');
return [
'status' => 'ok',
'details' => 'Connection successful ('. (microtime(true) - $start) .'s)'
];
} catch (\Throwable $e) {
return ['status' => 'error', 'details' => $e->getMessage()];
}
}
}
示例B:Redis / 缓存检查
<?php
class RedisHealthCheck implements HealthCheckInterface
{
protected $redis;
public function __construct(\Redis $redis)
{
$this->redis = $redis;
}
public function check(): array
{
try {
$this->redis->ping(); // PING命令
return ['status' => 'ok', 'details' => 'PING success'];
} catch (\Throwable $e) {
return ['status' => 'error', 'details' => $e->getMessage()];
}
}
}
步骤 3:核心调度器(汇总 + 状态码判断)
<?php
// app/HealthCheck/Manager.php
class HealthCheckManager
{
protected $checks = [];
protected $criticalChecks = ['database', 'redis']; // 哪些是必须健康的?
public function addCheck(string $name, HealthCheckInterface $check, bool $isCritical = true)
{
$this->checks[$name] = ['check' => $check, 'critical' => $isCritical];
return $this;
}
public function diagnose(string $type = 'readiness'): array
{
$results = [];
$overallStatus = 'ok';
foreach ($this->checks as $name => $item) {
// 对于Liveness检查,只检查主进程
if ($type === 'liveness' && $name !== 'app_status') {
continue;
}
$result = $item['check']->check();
$results[$name] = $result;
// 关键检查失败 -> 整体状态设为error
if ($result['status'] === 'error' && $item['critical']) {
$overallStatus = 'error';
}
}
return [
'status' => $overallStatus,
'checks' => $results,
'timestamp' => time(),
'uptime' => (time() - $_SERVER['REQUEST_TIME_FLOAT'])
];
}
}
步骤 4:统一入口 Controller / Router
<?php
// routes/web.php (Laravel) 或 自定义路由
Route::get('/health/liveness', function () {
// 简化版:只要PHP进程活着,就返回200
return response()->json(['status' => 'ok']);
});
Route::get('/health/readiness', function () {
$manager = new HealthCheckManager();
// 注册依赖
$manager->addCheck('database', new DatabaseHealthCheck(env('DB_HOST'), env('DB_PORT'), env('DB_DATABASE'), env('DB_USERNAME'), env('DB_PASSWORD')));
$manager->addCheck('redis', new RedisHealthCheck(Redis::connection()->client()));
// 执行诊断
$result = $manager->diagnose('readiness');
// 关键:根据状态返回HTTP码
$statusCode = ($result['status'] === 'ok') ? 200 : 503;
return response()->json($result, $statusCode);
});
线上生产环境的注意事项
两个必做
- 禁用缓存:健康检查接口必须跳过所有业务缓存(包括OPcache、响应缓存),确保结果是实时的。
- 超时控制:所有连接必须设置
connect_timeout(建议 2-3秒),防止某个依赖服务“假死”导致健康检查接口本身也超时挂起。
三种特殊场景
- 数据库连接池:如果你的项目用了连接池(如Swoole),健康检查不要拿连接池里的连接去
SELECT 1,因为可能会取到已断连的旧连接,应该新建一个临时连接进行测试,用完立即销毁。 - 负载均衡器:如果有多台服务器,确保每台机器的健康检查都有独立的随机数参数(如
?ts=1641024000),避免CDN缓存返回旧结果。 - 只读端点:健康检查的URL应该完全公开,不要求JWT或Session认证,确保运维工具(如Prometheus、K8s探针)能直接访问。
日志记录
在健康检查失败时,不要将大量异常堆栈打印到应用日志(避免攻击者利用/日志爆炸),只记录错误码和简要信息:
// 在Manager diagnose方法中
if ($result['status'] === 'error') {
\Log::warning('Health Check Failed', [
'service' => $name,
'error' => (substr($result['details'], 0, 40)) // 截取前40字符
]);
}
进阶场景:深度业务检查(Deep Health)
当你的应用依赖大量中间件(消息队列、第三方支付)时,只查数据库往往不够。
示例:检查消息队列堆积是否超标
class QueueHealthCheck implements HealthCheckInterface
{
protected $redis;
public function check(): array
{
$queueLength = $this->redis->lLen('jobs_queue');
// 如果队列超过10000条,则视为“亚健康”
if ($queueLength > 10000) {
return [
'status' => 'error',
'details' => "Queue too long: {$queueLength}"
];
}
return ['status' => 'ok', 'details' => "Queue length: {$queueLength}"];
}
}
监控集成建议
如果你的健康检查接口已经返回JSON,推荐用以下工具采集:
- Kubernetes (K8s):配置
livenessProbe指向/health/liveness,readinessProbe指向/health/readiness。 - Prometheus:使用
php_exporter结合curl检查/health/readiness的 HTTP 状态码。 - 阿里云/腾讯云 SLB:配置 TCP 监听检查 + HTTP 请求检查。
完整代码示例(原生PHP,无框架)
如果你的项目没有框架,这个文件可以单独放在 public/ 目录下:
<?php
// health.php
header('Content-Type: application/json');
$response = ['status' => 'ok', 'timestamp' => time()];
// 1. 终极简单检查(Liveness)
if (php_sapi_name() === 'cli') {
// 命令行模式下无HTTP响应,直接退出
exit(0);
}
// 2. 检查数据库(Readiness)
try {
$pdo = new PDO('mysql:host=127.0.0.1;port=3306;dbname=app', 'user', 'pass', [
PDO::ATTR_TIMEOUT => 2
]);
$pdo->query('SELECT 1');
$response['checks']['database'] = 'ok';
} catch (\Exception $e) {
$response['status'] = 'error';
$response['checks']['database'] = $e->getMessage();
}
// 3. 检查磁盘写权限(对临时目录)
$testFile = sys_get_temp_dir() . '/health_' . uniqid() . '.txt';
if (@file_put_contents($testFile, 'test') === false) {
$response['status'] = 'error';
$response['checks']['disk'] = 'not writable';
} else {
unlink($testFile);
$response['checks']['disk'] = 'ok';
}
// 输出状态码
if ($response['status'] === 'error') {
http_response_code(503);
}
echo json_encode($response);
总结建议
- 小项目:用脚本检测核心依赖连接(基础方案即可)。
- 中大型项目:按 Liveness / Readiness / Deep Health 分层设计接口。
- 避免过度复杂:健康检查本身不应消耗过多资源,超时设置要短(3秒内),频率要合理。
建议你的健康检查接口返回结果包含 version 和 commit_hash,方便排查“哪次发布导致不健康”,这在排查问题时会很有帮助。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播