1. 项目概述:为什么需要暴露/metrics端点?
在现代化应用监控体系中,/metrics端点就像应用程序的健康体检报告单。当你的PHP应用运行在内网环境时,暴露这个端点可以让Prometheus这类监控系统定期"问诊",采集内存使用、请求耗时、错误率等关键指标数据。不同于传统需要登录服务器查看日志的方式,这种方案实现了:
- 自动化采集:Prometheus会按配置的时间间隔(如15秒)自动抓取数据
- 可视化展示:通过Grafana可以制作直观的监控仪表盘
- 智能告警:当指标异常(如错误率>5%)时自动触发通知
典型应用场景包括:
- 电商促销期间实时监控PHP订单处理服务的队列堆积情况
- 跟踪Nginx的5xx错误率 spikes
- 统计PHP-FPM进程池的利用率波动
2. 环境准备与依赖检查
2.1 基础组件版本要求
在开始前,请确认你的环境满足以下版本要求(这是很多新手容易踩的坑):
| 组件 | 最低版本要求 | 检查命令 |
|---|---|---|
| PHP | 8.0+ | php -v |
| Nginx | 1.18+ | nginx -v |
| Prometheus | 2.30+ | prometheus --version |
注意:如果你看到类似
PHP Warning: 'c:\windows\system32\vcruntime140.dll' 14.0 is not compatible的错误,说明VC运行库版本不匹配,需要安装Visual C++ Redistributable 2015-2022。
2.2 Nginx模块检查
Nginx需要启用stub_status模块来暴露基础指标。执行以下命令验证:
nginx -V 2>&1 | grep -o with-http_stub_status_module如果没有任何输出,你需要重新编译Nginx:
./configure \ --prefix=/etc/nginx \ --with-http_stub_status_module # 关键模块 # 其他原有参数... make && sudo make install3. 配置Nginx暴露基础指标
3.1 基础监控配置
在Nginx的server配置块中添加(通常位于/etc/nginx/conf.d/default.conf):
server { listen 8080; location /nginx_status { stub_status; allow 192.168.1.0/24; # 只允许内网IP访问 deny all; } }重载配置后,访问http://your-server:8080/nginx_status将看到类似输出:
Active connections: 3 server accepts handled requests 14567 14567 36231 Reading: 0 Writing: 1 Waiting: 23.2 安全加固方案
对于生产环境,建议增加以下防护措施:
location /nginx_status { stub_status; auth_basic "Restricted Access"; auth_basic_user_file /etc/nginx/.htpasswd; # 生成密码文件:htpasswd -c /etc/nginx/.htpasswd admin satisfy any; allow 10.0.0.0/8; deny all; }4. PHP应用指标暴露实战
4.1 安装Prometheus PHP客户端
使用Composer安装官方库:
composer require promphp/prometheus_client_php4.2 创建指标收集脚本
新建/var/www/metrics/collector.php:
<?php require 'vendor/autoload.php'; $registry = new Prometheus\CollectorRegistry(new Prometheus\Storage\APC()); // 注册指标 $requestCounter = $registry->registerCounter( 'php', 'http_requests_total', 'Total HTTP requests', ['method', 'endpoint'] ); // 示例:记录一个GET请求 $requestCounter->inc(['GET', '/api/user']); // 暴露指标 $renderer = new Prometheus\RenderTextFormat(); header('Content-Type: ' . Prometheus\RenderTextFormat::MIME_TYPE); echo $renderer->render($registry->getMetricFamilySamples());4.3 Nginx代理配置
将/metrics路由到收集脚本:
location /metrics { alias /var/www/metrics; try_files $uri /collector.php; fastcgi_pass unix:/run/php/php8.2-fpm.sock; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }5. Prometheus服务发现配置
5.1 基础抓取配置
在prometheus.yml中添加:
scrape_configs: - job_name: 'php-app' static_configs: - targets: ['192.168.1.10:8080'] # 你的PHP服务器IP metrics_path: '/metrics' scheme: 'http' - job_name: 'nginx' static_configs: - targets: ['192.168.1.10:8080'] metrics_path: '/nginx_status' scheme: 'http'5.2 使用文件服务发现
对于动态环境,推荐使用文件服务发现:
scrape_configs: - job_name: 'php-app' file_sd_configs: - files: ['/etc/prometheus/targets/php-apps.json']创建目标文件/etc/prometheus/targets/php-apps.json:
[ { "labels": { "env": "production", "app": "order-service" }, "targets": ["192.168.1.10:8080"] } ]6. 实战问题排查指南
6.1 常见错误解决方案
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| 404 Not Found | 路径配置错误 | 检查Nginx的location块和PHP脚本物理路径是否匹配 |
| 502 Bad Gateway | PHP-FPM未运行 | 执行systemctl restart php8.2-fpm并检查sock文件权限 |
| 返回空白页面 | APC缓存未启用 | 安装APCu扩展:apt install php-apcu并重启PHP-FPM |
| Prometheus显示"up=0" | 防火墙阻止访问 | 检查服务器防火墙和云安全组规则:sudo ufw allow from 192.168.1.5 |
| 指标数据不更新 | 脚本未正确调用 | 在PHP脚本开头添加file_put_contents('/tmp/metrics_debug.log', date('Y-m-d H:i:s'));调试 |
6.2 性能优化技巧
缓存优化:
// 使用APCu替代默认的内存存储 $registry = new CollectorRegistry( new \Prometheus\Storage\APC(['prefix' => 'metrics_']) );采样控制:
location /metrics { access_log off; # 避免记录大量监控请求日志 log_not_found off; }指标分组:
// 按功能模块分组指标 $orderMetrics = new MetricGroup($registry, 'order_'); $paymentMetrics = new MetricGroup($registry, 'payment_');
7. 进阶:Grafana看板配置
7.1 导入Nginx基础看板
- 在Grafana中导入ID为12006的官方看板
- 配置Prometheus数据源
- 修改变量
$instance为你的服务器IP:port
7.2 自定义PHP监控看板
推荐监控的关键指标:
php_http_requests_total请求量统计php_memory_usage_bytes内存使用情况php_exceptions_total异常计数
示例PromQL查询:
# 计算5分钟错误率 sum(rate(php_http_requests_total{status=~"5.."}[5m])) / sum(rate(php_http_requests_total[5m]))8. 安全防护特别方案
8.1 网络层防护
location ~ ^/(metrics|nginx_status) { # 限制访问频率 limit_req zone=metric_zone burst=5 nodelay; # 只允许Prometheus服务器IP allow 192.168.1.5; deny all; # 启用HTTPS ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; }8.2 应用层防护
在PHP收集脚本开头添加:
// 验证请求来源IP $allowed_ips = ['192.168.1.5']; if (!in_array($_SERVER['REMOTE_ADDR'], $allowed_ips)) { header('HTTP/1.1 403 Forbidden'); exit; } // 验证Bearer Token if ($_SERVER['HTTP_AUTHORIZATION'] !== 'Bearer YOUR_SECRET_TOKEN') { header('HTTP/1.1 401 Unauthorized'); exit; }9. 容器化部署方案
9.1 Docker Compose配置示例
version: '3' services: app: image: php:8.2-fpm volumes: - ./src:/var/www/html ports: - "9000:9000" nginx: image: nginx:1.23 ports: - "8080:8080" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./src:/var/www/html prometheus: image: prom/prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml9.2 Kubernetes监控方案
创建ServiceMonitor资源:
apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: php-app-monitor spec: selector: matchLabels: app: php-app endpoints: - port: web path: /metrics interval: 30s我在实际部署中发现,当PHP应用与Nginx采用Unix Domain Socket通信时,需要特别注意容器内的socket文件权限问题。一个可靠的解决方案是在Dockerfile中创建共享卷:
RUN mkdir -p /var/run/php-fpm && \ chown -R www-data:www-data /var/run/php-fpm对于需要监控华为NPU等特殊硬件的场景,建议在Prometheus中配置额外的exporter容器,通过hostNetwork模式共享网络命名空间。这种方案在保证安全隔离的同时,也能获取到硬件层的监控指标。