PHP应用需通过/metrics端点暴露严格符合Prometheus文本协议的指标,推荐使用promphp/promphp等轻量库单例复用,避免手拼格式出错;禁用耗时操作与敏感标签,确保响应头为text/plain; version=0.0.4。

PHP 应用怎么暴露 Prometheus 指标?
直接在 PHP 中暴露 /metrics 端点是可行的,但别手写 HTTP 响应头和文本格式——Prometheus 官方不强制要求服务端实现,但要求指标必须严格遵循 Exposition Format v1.0.0(换行分隔、# TYPE 注释、类型一致、无非法字符)。手拼容易出错,比如漏转义 { 或 },或时间戳写成毫秒而非秒+纳秒。
推荐用轻量库:promphp/promphp(无依赖、纯 PHP)或 open-telemetry/opentelemetry-sdk(若已接入 OTel)。前者更直白:
use PromPHP\PromPHP;
$prom = new PromPHP();
$requestsTotal = $prom->createCounter(
'http_requests_total',
'Total HTTP Requests',
['method', 'status']
);
$requestsTotal->inc(['GET', '200']);
// 输出到 /metrics:echo $prom->render();注意:不要在每次请求都 new 一个 PromPHP 实例——计数器状态会丢失;应单例复用,或用 static 存储在长生命周期脚本中(如 PHP-FPM worker 内)。
PHP-FPM 状态页能当监控数据源吗?
可以,但仅限基础进程级指标(活跃进程数、请求队列长度、慢请求数),且需开启 pm.status_path 并配好权限。它不是为监控设计的,没有时间序列、无标签、无历史聚合,只反映当前快照。
立即学习“PHP免费学习笔记(深入)”;
常见踩坑点:
-
pm.status_path = /status后,Nginx 配置里没加fastcgi_param SCRIPT_NAME /status;→ 返回 404 或空白 - PHP-FPM pool 配了
slowlog但没设request_slowlog_timeout = 5s→ 慢请求从不触发日志 - 直接用
curl http://127.0.0.1:9000/status?full解析文本 → 字段顺序不固定,start time:和start since:混用,建议用现成解析器如php-fpm-exporter
真实场景建议:用 php-fpm-exporter(Go 写的轻量代理)把 FPM status 转成 Prometheus 格式,再由 Prometheus 抓取——它自动处理字段映射和类型转换,比自己写正则可靠得多。
APCu / OPcache 缓存命中率怎么算才准?
OPcache 的 opcache_get_status() 返回数组里有 opcache_statistics['hits'] 和 opcache_statistics['misses'],但注意:这些是自进程启动以来的累计值,不是每秒增量。直接用当前值除以总数会失真(比如刚重启,命中率永远是 0)。
正确做法是两次采样做差值:
- 第一次调用
opcache_get_status(),记录hits1、misses1 - 等 30 秒后第二次调用,得
hits2、misses2 - 命中率 =
(hits2 - hits1) / (hits2 - hits1 + misses2 - misses1)
APCu 类似,但得用 apcu_cache_info('user') 或 'system' 分开看;它的 num_hits/num_misses 也是累计值。另外,APCu 默认不统计 hits/misses(尤其 PHP 8.0+),需确认 apc.enable_cli=1(CLI 场景)且 apc.stat=1(否则缓存键变更不触发重载,统计失效)。
为什么用 Blackfire 或 XHGui 就不能替代 Prometheus?
Blackfire 和 XHGui 是性能剖析(profiling)工具,核心价值在「单次请求深度分析」:函数耗时、内存分配、SQL 调用栈。它们不适合做长期指标采集,因为:
- 开销大:启用 profiling 会让请求延时增加 20%~200%,无法全量开启
- 数据非结构化:XHGui 存的是 trace 文件,Blackfire 是二进制 profile,没法直接喂给 Prometheus 的
counter或histogram - 无聚合能力:你无法问「过去一小时平均响应时间 P95 是多少」,只能查某几个慢请求的火焰图
合理分工是:Prometheus 抓 http_request_duration_seconds_bucket 这类指标做 SLO 监控;一旦发现 P95 异常升高,再临时开 Blackfire 对特定 URL 手动 profiling 定位瓶颈。两者不是替代关系,而是指标层 + 排查层的配合。
最易被忽略的一点:PHP 的 max_execution_time 和 memory_limit 本身不会自动上报为指标。如果没显式用 register_shutdown_function() 捕获 fatal error 并打点,OOM 或超时崩溃就完全静默——这类故障恰恰最需要提前预警。



















