真正可用的 /api/health 接口需分通道显式检查主库、redis缓存、队列,均加 try/catch 与 500ms 超时控制,组合 ping() 和 select 1 验证连接有效性,返回含 db_write、cache_redis、queue_default 等字段的结构化状态数据,顶层 overall 仅当全部 up 才为 up。

ThinkPHP 没有开箱即用的“系统监控功能”,所谓监控必须拆解为具体可观测维度——健康接口、耗时统计、日志采集、异常捕获、队列/DB/缓存状态检查,每个环节都要手动补全逻辑,否则线上就是盲跑。
如何写一个真正可用的 /api/health 接口
别只返回 200 {"status":"ok"}。主库挂了、Redis连不上、队列积压 10 万条,这个接口照样能通。
- 显式分通道检查:
Db::connect('write')连主库 +Db::query('SELECT 1');用Cache::store('redis')->getInfo()拿 hits/misses,再Cache::get('health_test')写读一次;对 Redis 驱动调queue()->connection()->getRedis()->ping()+queue()->size('default') - 所有操作必须加
try/catch,捕获PDOException、RedisException、ThinkPHP\exception\DbException - 超时统一设为 500ms:在数据库配置里加
'params' => [PDO::ATTR_TIMEOUT => 0.5],Redis 配置加'timeout' => 0.5 - 返回结构必须含
db_write、cache_redis、queue_default字段,每项带status(up/down)、latency_ms、error(失败时填简短原因),顶层overall仅当全部 up 才为 up
请求耗时统计为什么总不准
常见错误是只记 microtime(true) 开始时间,却在 Response::send() 之后才取结束时间,漏掉 Gzip 压缩、输出缓冲、Header 发送等环节。
- 起点用
$_SERVER['REQUEST_TIME_FLOAT'],比手动打点更准(排除框架加载耗时) - 终点必须在
think\ResponseSend事件回调中取,即Response::send()调用前一刻 - 写入响应头:
$response->header('X-Response-Time', round($cost * 1000, 2) . 'ms'),方便 Nginx 日志或前端采集 - 别在中间件里用
trace()——它依赖应用实例,在中间件执行阶段可能未初始化,结果为空
错误日志监控容易漏掉 Fatal Error
think\exception\Handle 对 Fatal Error 完全无效,因为 PHP 在解析或执行阶段崩溃时根本进不了框架生命周期。
- 必须在
public/index.php最顶部注册register_shutdown_function,且放在所有其他 shutdown handler 之前 - 只捕获
E_ERROR、E_PARSE、E_CORE_ERROR、E_COMPILE_ERROR四类,E_WARNING不在此列 - 日志路径必须是绝对路径,如
/var/log/thinkphp/fatal.log;相对路径在 CLI 模式下极易错位 -
error_get_last()只返回最后一次错误,所以该钩子不能被覆盖或延迟注册
队列和缓存监控为什么查不到真实状态
ThinkPHP 的 Cache::get() 返回 null,可能是 key 不存在、过期、连接失败、序列化异常——三者处理方式完全不同,但默认不暴露原因。
- Redis 缓存驱动支持
getInfo(),能拿到hits/misses计数,但其他驱动(如 file、apcu)不支持 - 队列监控不能只看
queue()->pending(),要结合queue()->failed()和queue()->size('default')判断积压趋势 - 别依赖
Cache::has()判断存在性——它本身也是一次网络调用,高并发下反而加重 Redis 压力 - 高频检查(如每 10 秒)务必加锁或限频,否则单点故障会拖垮整个服务链路
所有监控逻辑都绕不开「边界」:PHP-FPM 是短连接模型,没有真正的连接池;trace() 仅限开发环境;log.php 的 level 配置漏一项(比如没加 notice),关键警告就进不了日志;Zabbix Agent 的 EnableRemoteCommands=1 不开,自愈脚本就永远不执行——这些不是可选项,是上线前必须逐项核对的硬条件。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











