PHP 与 Laravel 应用接入 Prometheus 监控
PHP/Laravel 接入 Prometheus 监控:promphp/prometheus_client_php 客户端、Counter/Gauge/Histogram 埋点、存储后端选择(Redis/APCu)、Laravel 中间件集成与 FAQ。
PHP 的请求模型(每请求一个进程生命周期,FPM 下尤其明显)让它的指标埋点有些特殊——指标必须落到一个跨请求共享的存储里。本文讲清正确姿势。
安装客户端
composer require promphp/prometheus_client_php
关键差异:指标存储后端
Go/Java 的指标存在进程内存里,而 PHP-FPM 每个请求结束进程状态就重置。客户端库需要外部存储:
use Prometheus\Storage\Redis;
use Prometheus\CollectorRegistry;
// 生产推荐 Redis(跨进程共享)
Redis::setDefaultOptions(['host' => '127.0.0.1', 'port' => 6379]);
$registry = new CollectorRegistry(Redis::getDefault());
// 测试/单机可用 APCu
// $registry = new CollectorRegistry(new \Prometheus\Storage\APCu());
埋点三种指标
// Counter:请求总数
$counter = $registry->getOrRegisterCounter('app', 'http_requests_total',
'Total HTTP requests', ['method', 'route', 'status']);
$counter->inc(['GET', '/api/users', '200']);
// Gauge:瞬时值(当前活跃请求、内存占用)
$gauge = $registry->getOrRegisterGauge('app', 'memory_usage_bytes', 'Memory usage');
$gauge->set(memory_get_usage(true));
// Histogram:延迟分布
$hist = $registry->getOrRegisterHistogram('app', 'request_duration_seconds',
'Request duration', ['route'], [0.01, 0.05, 0.1, 0.5, 1, 5]);
$hist->observe($duration, ['/api/users']);
暴露 /metrics 端点
// routes/web.php 或独立入口
Route::get('/metrics', function () {
$registry = new CollectorRegistry(Redis::getDefault());
$renderer = new \Prometheus\RenderTextFormat();
return response($renderer->render($registry->getMetricFamilySamples()))
->header('Content-Type', 'text/plain; version=0.0.4');
});
Laravel 中间件统一采集
class PrometheusMiddleware
{
public function handle($request, Closure $next)
{
$start = microtime(true);
$response = $next($request);
$route = $request->route()?->uri() ?? 'unknown'; // 路由模板,不是原始 URL
$registry = new CollectorRegistry(Redis::getDefault());
$registry->getOrRegisterCounter('app', 'http_requests_total', '', ['method','route','status'])
->inc([$request->method(), $route, $response->getStatusCode()]);
$registry->getOrRegisterHistogram('app', 'request_duration_seconds', '', ['route'])
->observe(microtime(true) - $start, [$route]);
return $response;
}
}
$route 务必用路由模板——用 $request->path() 会把 /users/123 这种 ID 路径变成基数炸弹。
观测云对照
PHP 应用更完整的路径是观测云 APM 探针:无需手写埋点即可获得请求速率、错误率、延迟分布、慢事务与数据库调用分解;自定义业务指标照走 Prometheus 端点由 DataKit 抓取汇聚,两套数据在同一平台关联。FPM 特有指标(活跃进程、队列长度)也有现成的 PHP-FPM 集成。
常见问题(FAQ)
Q:为什么指标值重启 FPM 后还在?
A:因为存在 Redis/APCu 里——这正是目的。注意这意味着需要手动清理过期序列(长期不再出现的标签组合),客户端库提供 wipeStorage() 之类的能力,建议在发布流程里定期清。
Q:APCu 和 Redis 怎么选?
A:单机部署 APCu 零依赖;多机部署必须 Redis(否则 Prometheus 每次抓到的是不同机器的部分数据)。
Q:CLI/队列任务(Artisan command、Horizon)怎么埋点?
A:同样写 Redis 存储即可,/metrics 端点由 Web 进程统一渲染——Web 与 CLI 共享 Redis 存储是这套架构成立的关键。