Мониторинг PHP приложений: метрики и алерты продвинутого уровня

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: от базового healthcheck к глубокой observability

Базовый мониторинг PHP-приложений, включающий проверку доступности (healthcheck) и загрузку CPU, — это минимум, который необходимо настроить в первую очередь. Однако для продакшн-систем с высокой нагрузкой и сложной бизнес-логикой этого недостаточно. Продвинутый мониторинг переводит фокус с «живо/мертво» на observability (наблюдаемость) и позволяет ответить на вопросы: «Почему упала конверсия?», «Какой именно эндпоинт замедлил работу?», «Сколько пользователей не смогли завершить оплату?».

В этой статье мы рассмотрим архитектуру продвинутого мониторинга PHP-приложений, научимся собирать кастомные метрики (включая бизнес-метрики), настраивать алерты на основе аномалий и интегрировать всё в единую панель Grafana. Все примеры кода написаны на PHP и готовы к внедрению.

1. Архитектура сбора метрик: Prometheus и кастомные экспортеры

Современный стандарт де-факто для сбора метрик — Prometheus с моделью pull. PHP-приложение не обязано напрямую отдавать метрики на порт /metrics. Вместо этого мы используем кастомный экспортер — отдельный скрипт, который опрашивает приложение (через Redis, БД или файл) и формирует ответ в формате Prometheus.

1.1. Установка Prometheus клиента для PHP

Рекомендуемая библиотека — promphp/prometheus_client_php. Установка через Composer:

composer require promphp/prometheus_client_php

1.2. Пример экспортера метрик (metrics.php)

Создадим скрипт, который возвращает метрики в формате Prometheus. Для хранения используем Redis (флаг PERSISTENT для продакшна).

<?php
require 'vendor/autoload.php';

use Prometheus\CollectorRegistry;
use Prometheus\Storage\Redis;
use Prometheus\RenderTextFormat;

// Подключение к Redis
Redis::setDefaultOptions(['host' => '127.0.0.1', 'port' => 6379]);
$registry = new CollectorRegistry(new Redis());

// Регистрируем гистограмму для времени ответа
$histogram = $registry->getOrRegisterHistogram(
    'app_http_request_duration_seconds',
    'HTTP request duration in seconds',
    ['method', 'endpoint', 'status']
);

// Регистрируем счётчик бизнес-метрики
$counter = $registry->getOrRegisterCounter(
    'app_orders_total',
    'Total number of orders processed',
    ['status'] // success, failed
);

// Симуляция данных (в реальности считываем из БД или логов)
$histogram->observe(0.12, ['GET', '/api/orders', '200']);
$counter->incBy(1, ['success']);

// Отдаём метрики
$renderer = new RenderTextFormat();
header('Content-Type: text/plain');
echo $renderer->render($registry->getMetricFamilySamples());

Затем настраиваем Nginx или Apache, чтобы этот скрипт был доступен по пути /metrics, и добавляем target в Prometheus.

2. Бизнес-метрики: мониторинг того, что действительно важно

Технические метрики (latency, error rate) — основа, но бизнес-метрики дают понимание здоровья продукта. Примеры таких метрик:

  • Количество успешных заказов в минуту — падение сигнализирует о проблемах с платёжным шлюзом.
  • Среднее время выполнения корзины — рост может указывать на регрессию в коде.
  • Процент отказов от регистрации — если резко вырос, возможно, сломалась форма.

2.1. Интеграция бизнес-метрик в код приложения

Используем тот же prometheus_client_php, но оборачиваем вызовы в middleware или сервисный слой. Пример для Laravel:

<?php
namespace App\Http\Middleware;

use Closure;
use Prometheus\CollectorRegistry;

class MetricsMiddleware
{
    protected $registry;

    public function __construct(CollectorRegistry $registry)
    {
        $this->registry = $registry;
    }

    public function handle($request, Closure $next)
    {
        $start = microtime(true);
        $response = $next($request);
        $duration = microtime(true) - $start;

        // Метрика времени ответа
        $histogram = $this->registry->getOrRegisterHistogram(
            'app_http_request_duration_seconds',
            'HTTP request duration',
            ['method', 'endpoint', 'status']
        );
        $histogram->observe($duration, [
            $request->method(),
            $request->path(),
            $response->status()
        ]);

        // Бизнес-метрика: количество заказов
        if ($request->path() === 'api/orders' && $response->status() === 201) {
            $counter = $this->registry->getOrRegisterCounter(
                'app_orders_created_total',
                'Total orders created',
                ['source'] // web, api, mobile
            );
            $counter->incBy(1, [$request->header('X-Source', 'web')]);
        }

        return $response;
    }
}

Важно: все операции с метриками должны быть асинхронными или буферизированными, чтобы не замедлять запрос пользователя. Для этого используйте Redis Adapter с флагом PERSISTENT — запись в Redis занимает <1 мс.

3. Продвинутые алерты: от порогов к аномалиям

Простые алерты на превышение порога (например, latency > 1s) приводят к ложным срабатываниям. Продвинутый подход включает:

  • Базовые линии (baselines) — алерт срабатывает, если метрика отклоняется от исторической нормы на 3 сигмы.
  • Мульти-условные алерты — комбинация нескольких метрик (например, высокий error rate + низкая throughput).
  • Алерты на отсутствие данных — если метрика перестала поступать, это может быть хуже, чем высокое значение.

Блоги

Рекомендаций по книгам