PHP应用监控告警:基于Prometheus的SLO/SLA指标设计与阈值配置

PHP 应用监控告警:基于 Prometheus 的 SLO/SLA 指标设计与阈值配置

大家好!今天我们来聊聊如何使用 Prometheus 对 PHP 应用进行监控告警,并基于此设计 SLO/SLA 指标,配置合理的阈值。这将帮助我们更好地保障 PHP 应用的稳定性和性能。

一、监控的重要性与挑战

监控是保障任何应用稳定运行的基础。对于 PHP 应用来说,有效的监控可以帮助我们:

  • 及时发现问题: 在问题影响用户之前预警。
  • 快速定位问题: 通过监控数据分析问题根源。
  • 优化应用性能: 识别性能瓶颈并进行优化。
  • 保障服务质量: 确保应用满足服务水平协议 (SLA)。

然而,PHP 应用的监控也存在一些挑战:

  • 语言特性: PHP 作为解释型语言,执行过程相对动态,增加了监控的复杂度。
  • 框架多样性: 存在多种 PHP 框架,监控方案需要具有一定的通用性。
  • 部署环境复杂: 应用可能运行在各种不同的环境,包括容器化环境。
  • 指标选择: 如何选择合适的指标来反映应用的健康状况。

二、Prometheus 简介与架构

Prometheus 是一套开源的监控告警系统,特别适用于监控云原生环境。它具有以下特点:

  • 多维数据模型: 所有监控数据都以 key-value 对的形式存储,方便查询和分析。
  • 强大的查询语言 (PromQL): 用于灵活地查询和聚合监控数据。
  • 基于 HTTP 的 pull 模型: Prometheus 定期从目标服务拉取监控数据。
  • 高度可扩展性: 支持多种存储后端和集群部署。
  • Alertmanager 集成: 用于处理告警规则并发送告警通知。

Prometheus 的基本架构如下:

  • Prometheus Server: 负责抓取、存储和查询监控数据。
  • Exporters: 用于暴露监控数据的组件,例如 Node Exporter (监控主机资源) 和 MySQL Exporter (监控 MySQL 数据库)。
  • Alertmanager: 负责处理告警规则并发送告警通知。
  • Pushgateway (可选): 用于接收短期任务的监控数据。

三、PHP 应用监控指标设计

我们需要根据应用的特点和业务需求来选择合适的监控指标。以下是一些常用的 PHP 应用监控指标:

  • 请求相关指标:
    • 请求总数 (http_requests_total): 记录应用接收到的 HTTP 请求总数。
    • 请求延迟 (http_request_duration_seconds): 记录请求的处理时间,通常需要统计不同分位数的延迟。
    • 请求状态码 (http_request_status_codes): 记录不同状态码的请求数量,例如 200, 400, 500。
    • 每秒请求数 (RPS): 反映应用的吞吐量。
  • 资源使用指标:
    • CPU 使用率 (cpu_usage): 反映 PHP 进程的 CPU 占用情况。
    • 内存使用量 (memory_usage_bytes): 反映 PHP 进程的内存占用情况。
    • 磁盘 I/O (disk_io): 反映 PHP 进程的磁盘读写情况。
  • PHP 内部指标:
    • 错误日志数量 (php_errors_total): 记录 PHP 错误日志的数量,可以按错误级别分类。
    • 异常数量 (php_exceptions_total): 记录 PHP 异常的数量。
    • Opcache 命中率 (opcache_hit_rate): 反映 Opcache 的效率。
    • 数据库查询时间 (db_query_duration_seconds): 记录数据库查询耗时。
  • 业务相关指标:
    • 用户注册数量 (user_registrations_total): 记录用户注册数量。
    • 订单数量 (orders_total): 记录订单数量。
    • 支付成功率 (payment_success_rate): 记录支付成功的比例。

指标命名规范:

  • 使用有意义的名称,反映指标的含义。
  • 使用 _total 后缀表示累计值。
  • 使用 _seconds 后缀表示时间单位为秒。
  • 使用 _bytes 后缀表示大小单位为字节。

四、Prometheus Exporter 的选择与实现

为了让 Prometheus 能够抓取 PHP 应用的监控数据,我们需要使用 Exporter。 以下是几种常用的方法:

  1. 使用现有的 Exporter:

    • php-fpm_exporter: 监控 php-fpm 的状态,例如活跃进程数、空闲进程数等。
    • Third-party application exporters: 针对一些通用的应用程序,比如 Redis,MySQL等,可以使用已经存在的exporter。
  2. 自定义 Exporter:

    如果我们没有找到合适的现有 Exporter,或者需要监控一些特定的指标,我们可以自定义 Exporter。 自定义 Exporter 的基本流程如下:

    • 收集指标数据: 在 PHP 代码中收集需要监控的指标数据。
    • 暴露 HTTP 接口: 创建一个 HTTP 接口,将收集到的指标数据以 Prometheus 的文本格式 (exposition format) 暴露出来。
    • 配置 Prometheus: 配置 Prometheus,使其能够定期从 Exporter 的 HTTP 接口拉取数据。

    PHP 代码示例 (自定义 Exporter):

    <?php
    
    // 收集指标数据
    $requests_total = 0;
    $errors_total = 0;
    
    // 模拟请求处理
    function handleRequest() {
      global $requests_total, $errors_total;
      $requests_total++;
    
      // 模拟错误发生
      if (rand(0, 9) == 0) { // 10% 的概率发生错误
        $errors_total++;
        error_log("Simulated error occurred.");
      }
    
      // 模拟处理时间
      usleep(rand(10000, 50000)); // 10-50 毫秒
    }
    
    // 处理多个请求
    for ($i = 0; $i < 100; $i++) {
      handleRequest();
    }
    
    // 暴露 HTTP 接口
    if ($_SERVER['REQUEST_URI'] == '/metrics') {
      header('Content-Type: text/plain');
    
      echo "# HELP http_requests_total Total number of HTTP requests.n";
      echo "# TYPE http_requests_total countern";
      echo "http_requests_total " . $requests_total . "n";
    
      echo "# HELP php_errors_total Total number of PHP errors.n";
      echo "# TYPE php_errors_total countern";
      echo "php_errors_total " . $errors_total . "n";
    
      exit;
    } else {
      echo "Metrics endpoint: /metrics";
    }
    ?>

    Prometheus 配置示例 (scrape_configs):

    scrape_configs:
      - job_name: 'php-app'
        static_configs:
          - targets: ['localhost:8000'] # 假设 PHP 应用运行在 8000 端口

    代码解释:

    • PHP 代码模拟了请求处理和错误发生,并记录了 http_requests_totalphp_errors_total 指标。
    • 当访问 /metrics 路径时,代码会返回 Prometheus 的文本格式的指标数据。
    • Prometheus 的 scrape_configs 配置指定了 Prometheus 需要抓取的目标地址。
  3. 使用 PHP 库:

    有一些 PHP 库可以帮助我们更方便地创建 Exporter,例如:

    • Prometheus PHP Client: 提供了 Metric 类的定义和 Registry 类的实现,可以更方便地管理指标。

    使用 Prometheus PHP Client 的代码示例:

    <?php
    
    require 'vendor/autoload.php';
    
    use PrometheusCollectorRegistry;
    use PrometheusCounter;
    use PrometheusRenderTextFormat;
    
    // 创建 Registry
    $adapter = new PrometheusStorageInMemory(); // 使用内存存储,生产环境建议使用 Redis 或其他存储
    $registry = new CollectorRegistry($adapter);
    
    // 创建 Counter 指标
    $counter = $registry->getOrRegisterCounter(
        'http_requests',
        'total',
        'Total number of HTTP requests',
        ['path']
    );
    
    // 创建 Gauge 指标 (用于记录当前活跃连接数)
    $gauge = $registry->getOrRegisterGauge(
      'http_active_connections',
      'current',
      'Current number of active HTTP connections',
    );
    
    // 模拟请求处理
    function handleRequest(CollectorRegistry $registry, string $path) {
        global $gauge;
        $gauge->inc(); //增加活跃连接数
    
        // 增加请求计数
        $registry->getCounter('http_requests', 'total')->inc(['path' => $path]);
    
        // 模拟处理时间
        usleep(rand(10000, 50000)); // 10-50 毫秒
    
        $gauge->dec(); //减少活跃连接数
    }
    
    // 处理多个请求
    for ($i = 0; $i < 10; $i++) {
      handleRequest($registry, '/example');
    }
    
    // 暴露 HTTP 接口
    if ($_SERVER['REQUEST_URI'] == '/metrics') {
      header('Content-Type: text/plain');
    
      $renderer = new RenderTextFormat();
      $result = $renderer->render($registry->getMetricFamilySamples());
    
      echo $result;
    
      exit;
    } else {
      echo "Metrics endpoint: /metrics";
    }

    代码解释:

    • 使用 PrometheusCollectorRegistry 创建 Registry 对象,用于管理指标。
    • 使用 getOrRegisterCounter 方法创建 Counter 指标,并指定指标的名称、帮助信息和标签。
    • 使用 inc() 方法增加指标的值。
    • 使用 RenderTextFormat 类将指标数据转换为 Prometheus 的文本格式。
    • 需要使用 composer require promphp/prometheus_client_php 安装该包。

五、SLO/SLA 指标设计

SLO (Service Level Objective) 和 SLA (Service Level Agreement) 是衡量服务质量的重要指标。 SLO 定义了我们期望达到的服务水平,而 SLA 则定义了我们承诺提供的服务水平。

常用的 SLO/SLA 指标:

  • 可用性 (Availability): 服务正常运行的时间比例。 例如,99.9% 的可用性意味着服务每年最多允许 8.76 小时的 downtime。
  • 错误率 (Error Rate): 请求失败的比例。 例如,错误率小于 0.1%。
  • 延迟 (Latency): 请求的处理时间。 例如,95% 的请求延迟小于 200 毫秒。
  • 吞吐量 (Throughput): 单位时间内处理的请求数量。 例如,每秒处理 1000 个请求。

基于 Prometheus 的 SLO/SLA 指标计算:

我们可以使用 PromQL 来计算 SLO/SLA 指标。

1. 可用性 (Availability):

sum(up{job="php-app"}) / count(up{job="php-app"})

这个 PromQL 查询计算了 php-app 这个 job 的可用性。 up 指标表示服务是否正常运行 (1 表示正常,0 表示异常)。

2. 错误率 (Error Rate):

rate(http_request_status_codes{job="php-app", code=~"5.."}[5m]) / rate(http_requests_total{job="php-app"}[5m])

这个 PromQL 查询计算了 php-app 这个 job 的错误率。 它计算了过去 5 分钟内 5xx 状态码的请求数量与总请求数量的比率。

3. 延迟 (Latency):

histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{job="php-app"}[5m])) by (le))

这个 PromQL 查询计算了 php-app 这个 job 的 95 分位数的请求延迟。 它使用了直方图 (histogram) 指标来统计延迟分布。

4. 吞吐量 (Throughput):

rate(http_requests_total{job="php-app"}[5m])

这个 PromQL 查询计算了 php-app 这个 job 的吞吐量。 它计算了过去 5 分钟内每秒的请求数量。

SLO/SLA 指标表格示例:

指标 SLO SLA PromQL 查询
可用性 >= 99.9% >= 99.5% sum(up{job="php-app"}) / count(up{job="php-app"})
错误率 <= 0.1% <= 0.5% rate(http_request_status_codes{job="php-app", code=~"5.."}[5m]) / rate(http_requests_total{job="php-app"}[5m])
延迟 (P95) <= 200ms <= 500ms histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{job="php-app"}[5m])) by (le))
吞吐量 >= 1000 RPS >= 500 RPS rate(http_requests_total{job="php-app"}[5m])

六、告警规则配置

Prometheus 使用 Alertmanager 来处理告警规则并发送告警通知。 告警规则定义了在什么情况下触发告警。

告警规则配置示例 (prometheus.yml):

rule_files:
  - "alert.rules.yml"

告警规则文件示例 (alert.rules.yml):

groups:
  - name: php-app-alerts
    rules:
      - alert: PhpAppHighLatency
        expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{job="php-app"}[5m])) by (le)) > 0.2
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "PHP app latency is high"
          description: "PHP app latency (95th percentile) is above 200ms for 1 minute."

      - alert: PhpAppHighErrorRate
        expr: rate(http_request_status_codes{job="php-app", code=~"5.."}[5m]) / rate(http_requests_total{job="php-app"}[5m]) > 0.01
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "PHP app error rate is high"
          description: "PHP app error rate is above 1% for 1 minute."

      - alert: PhpAppDown
        expr: up{job="php-app"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "PHP app is down"
          description: "PHP app is down for 1 minute."

告警规则解释:

  • alert: 告警的名称。
  • expr: PromQL 查询表达式,用于判断是否触发告警。
  • for: 告警持续时间,只有当表达式持续满足条件达到指定时间后才会触发告警。
  • labels: 告警的标签,用于分类和路由告警。
  • annotations: 告警的注释,提供告警的描述信息。

Alertmanager 配置:

Alertmanager 负责接收 Prometheus 发送的告警,并根据配置的路由规则发送告警通知。

Alertmanager 配置示例 (alertmanager.yml):

route:
  receiver: 'email-notifications'
  repeat_interval: 5m #重复发送间隔
  group_wait: 30s #等待多久将告警进行分组
  group_interval: 5m #分组后多久再发送告警

receivers:
  - name: 'email-notifications'
    email_configs:
      - to: '[email protected]'
        from: '[email protected]'
        smarthost: 'smtp.example.com:587'
        auth_username: '[email protected]'
        auth_password: 'your_password'
        tls_config:
          insecure_skip_verify: true

配置解释:

  • route: 定义了告警的路由规则。 所有告警都会路由到 email-notifications 这个 receiver。
  • receivers: 定义了告警接收器。 email-notifications 这个 receiver 使用 email 发送告警通知。

七、阈值配置的最佳实践

阈值的配置需要根据应用的特点和业务需求进行调整。 以下是一些最佳实践:

  • 从历史数据中学习: 分析历史监控数据,了解应用的正常运行范围,并基于此设置阈值。
  • 设置多级阈值: 可以设置 warning 和 critical 两个级别的阈值,分别对应不同的告警级别。
  • 使用动态阈值: 可以使用算法来动态调整阈值,例如基于历史数据的平均值和标准差。
  • 定期评估和调整: 定期评估告警规则的有效性,并根据实际情况进行调整。
  • 考虑业务影响: 在设置阈值时,需要考虑对业务的影响,避免误报。

八、监控仪表盘

监控仪表盘可以帮助我们更直观地了解应用的健康状况。 可以使用 Grafana 等工具来创建监控仪表盘。

Grafana 仪表盘示例:

  • PHP 应用整体概览: 显示应用的可用性、错误率、延迟和吞吐量等关键指标。
  • 请求监控: 显示请求总数、请求状态码分布、请求延迟分布等指标。
  • 资源使用监控: 显示 CPU 使用率、内存使用量、磁盘 I/O 等指标。
  • PHP 内部监控: 显示错误日志数量、异常数量、Opcache 命中率等指标。
  • 数据库监控: 显示数据库查询时间、连接数等指标。
  • 业务监控: 显示用户注册数量、订单数量、支付成功率等指标。

九、实际案例:电商平台的 PHP 应用监控

假设我们有一个电商平台的 PHP 应用,需要监控以下几个方面:

  • 用户访问: 监控用户访问量、页面加载时间。
  • 商品浏览: 监控商品浏览量、商品详情页加载时间。
  • 订单处理: 监控订单创建数量、支付成功率。
  • 数据库性能: 监控数据库查询时间、连接数。

指标选择:

  • http_requests_total: 记录用户访问量和商品浏览量。
  • http_request_duration_seconds: 记录页面加载时间和商品详情页加载时间。
  • orders_total: 记录订单创建数量。
  • payment_success_rate: 记录支付成功率。
  • db_query_duration_seconds: 记录数据库查询时间。
  • db_connections_total: 记录数据库连接数。

告警规则:

  • 当页面加载时间超过 2 秒时,发送 warning 告警。
  • 当商品详情页加载时间超过 5 秒时,发送 critical 告警。
  • 当支付成功率低于 99% 时,发送 warning 告警。
  • 当数据库查询时间超过 1 秒时,发送 warning 告警。
  • 当数据库连接数超过 100 时,发送 warning 告警。

监控仪表盘:

  • 创建一个 Grafana 仪表盘,显示用户访问量、页面加载时间、商品浏览量、商品详情页加载时间、订单创建数量、支付成功率、数据库查询时间和连接数等指标。

十、总结

理解了监控的重要性,Prometheus 的基本架构和工作方式,并深入探讨了如何设计 PHP 应用的监控指标,选择合适的 Exporter,以及如何基于 Prometheus 计算 SLO/SLA 指标,配置告警规则。此外,还探讨了阈值配置的最佳实践,并提供了一个电商平台的实际案例。希望这些内容能帮助你更好地保障 PHP 应用的稳定性和性能。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注