🏗️ Раздел 17 · Вопрос #21

Как мониторить распределённую систему микросервисов

4. Saturation (Насыщение): Насколько загружен самый узкий ресурс системы (память JVM, ядра CPU, свободные коннекты в HikariCP, заполненность диска).


🟢 Junior Level

Мониторинг и наблюдаемость (Observability) в микросервисной архитектуре — это комплекс практик и инструментов, позволяющий в реальном времени понимать внутреннее состояние системы на основе её внешних данных: метрик, логов и трассировок.

                  ┌──────────────────────────────────────────────┐
                  │    Три кита Observability (The Three Pillars) │
                  └──────┬───────────────┬───────────────┬───────┘
                         │               │               │
                         ▼               ▼               ▼
                   [ МЕТРИКИ ]       [ ЛОГИ ]      [ ТРАССИРОВКИ ]
                  (Prometheus)        (Loki / ELK)     (Jaeger / OTel)
                  «Что и когда       «Почему это       «Где именно
                   сломалось?»        произошло?»       возникла задержка?»

Четыре золотых сигнала (Google SRE Golden Signals):

  1. Latency (Задержка): Время, необходимое для обработки запроса (отдельно для успешных запросов и запросов с ошибками).
  2. Traffic (Трафик): Мера входящего спроса на систему (запросов в секунду — RPS, транзакций в секунду — TPS).
  3. Errors (Ошибки): Частота запросов, завершившихся неудачей (HTTP 5xx, тайм-ауты, выброшенные исключения).
  4. Saturation (Насыщение): Насколько загружен самый узкий ресурс системы (память JVM, ядра CPU, свободные коннекты в HikariCP, заполненность диска).

🟡 Middle Level

1. Методологии мониторинга: RED vs USE

В микросервисах применяются две взаимодополняющие методологии:

  • RED Method (для сервисов и API):
    • Rate: Количество запросов в секунду.
    • Errors: Количество ошибок в секунду.
    • Duration: Распределение времени выполнения запросов (перцентили).
  • USE Method (для инфраструктуры и ресурсов — CPU, RAM, диски):
    • Utilization: Процент времени, когда ресурс был занят полезной работой.
    • Saturation: Очередь задач к ресурсу (глубина очереди потоков, Load Average).
    • Errors: Физические ошибки оборудования или сбои интерфейсов.

2. Сбор метрик в Java: Spring Boot Actuator + Micrometer

Micrometer — это фасад для сбора метрик в Java-приложениях (аналог SLF4J для логирования), транслирующий данные в Prometheus:

@RestController
@RequiredArgsConstructor
public class CheckoutController {

    private final MeterRegistry registry;
    private final OrderService orderService;

    private Counter checkoutSuccessCounter;
    private Counter checkoutFailCounter;
    private Timer checkoutTimer;

    @PostConstruct
    void initMetrics() {
        this.checkoutSuccessCounter = Counter.builder("checkout_orders_total")
            .description("Количество успешно оформленных заказов")
            .tag("status", "success")
            .register(registry);

        this.checkoutFailCounter = Counter.builder("checkout_orders_total")
            .description("Количество неудачных оформлений")
            .tag("status", "failure")
            .register(registry);

        this.checkoutTimer = Timer.builder("checkout_duration_seconds")
            .description("Время оформления заказа")
            .publishPercentiles(0.5, 0.95, 0.99)
            .register(registry);
    }

    @PostMapping("/checkout")
    public OrderResponse checkout(@RequestBody OrderRequest req) {
        return checkoutTimer.record(() -> {
            try {
                OrderResponse response = orderService.process(req);
                checkoutSuccessCounter.increment();
                return response;
            } catch (Exception ex) {
                checkoutFailCounter.increment();
                throw ex;
            }
        });
    }
}

3. Базовые PromQL-запросы для алертинга

Расчет процента ошибок сервиса за последние 5 минут:

sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m]))
/
sum(rate(http_server_requests_seconds_count[5m])) * 100 > 5

Расчет 99-го перцентиля задержки (p99 latency):

histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[5m])) by (le))

🔴 Senior Level

1. Взрыв кардинальности (Metrics Cardinality Explosion)

Самая опасная ошибка при работе с TSDB (Time Series Database — Prometheus / VictoriaMetrics):

  • Каждая уникальная комбинация имени метрики и её лейблов (tags) создаёт отдельный временной ряд (Time Series), хранящийся в оперативной памяти Prometheus.
  • АНТИПАТТЕРН:
    // КАТАСТРОФА! Поле userId или orderId имеет миллионную кардинальность!
    registry.counter("order_created", "user_id", req.getUserId()).increment();
    
  • Результат: 1 000 000 пользователей $\to$ 1 000 000 новых time series в Prometheus $\to$ сервер мониторинга падает с OutOfMemoryError, а вся наблюдаемость компании исчезает.
  • Правило: Лейблы должны быть низкокардинальными (Low Cardinality): код статуса (status=SUCCESS), тип операции (payment_type=CARD), имя сервиса. Любые динамические ID (userId, orderId) передаются только в логи и трейсы.

2. SLI, SLO, SLA и концепция Error Budget (Бюджет ошибок)

SLA (Юридический договор):       99.0% доступности (штраф при нарушении)
             ▲
             │ (Запас безопасности)
SLO (Внутренняя цель инженеров): 99.9% доступности
             ▲
             │ (Фактическое измерение по метрикам)
SLI (Индикатор):                (Успешные запросы / Всего запросов) за 30 дней
  • Error Budget (Бюджет ошибок): Допустимый объем брака. При SLO 99.9% бюджет ошибок составляет $100\% - 99.9\% = 0.1\%$ от всех запросов в месяц.
  • Если система укладывается в бюджет ошибок — продуктовые команды имеют право быстро деплоить новые рискованные фичи.
  • Если бюджет ошибок исчерпан за первую неделю месяца — релизы замораживаются, и все силы направляются на стабилизацию архитектуры и устранение техдолга.

3. Multi-Window Multi-Burn-Rate Alerts (Google SRE)

Классические алерты «Если ошибка > 1% за 5 минут» страдают двумя крайностями:

  1. Либо они спамят ложными тревогами при кратковременном всплеске (Alert Fatigue).
  2. Либо не замечают медленное выедание месячного бюджета ошибок при деградации в 0.2%.

Промышленный стандарт Google SRE: Мониторинг скорости расходования бюджета ошибок (Burn Rate) на перекрывающихся окнах:

  • Если сжигается 14.4x бюджета за 1 час (2% месячного бюджета сгорит за час) $\to$ Критический алерт (Page / Звонок дежурному в PagerDuty).
  • Если сжигается 3x бюджета за 6 часов (5% бюджета сгорит за 6 часов) $\to$ Тикет / Уведомление в Slack в рабочее время.

4 Tricky Questions

1. Почему среднее время ответа (Average Latency) категорически непригодно для оценки качества сервиса?

Ответ: Среднее арифметическое математически скрывает катастрофические проблемы у меньшинства пользователей (эффект средней температуры по больнице):

  • Если 99 пользователей получили ответ за 10 мс, а 1 VIP-пользователь с гигантской корзиной завис на 10 000 мс: \(\text{Average} = \frac{99 \times 10 + 10\,000}{100} = 109.9\text{ мс}\) Инженеры видят на графике «отличные» 110 мс и считают, что всё в порядке. При этом самый платежеспособный клиент бросил корзину из-за десятисекундного зависания. Только перцентили (p95, p99, p99.9) показывают реальный худший пользовательский опыт (Tail Latency).

2. Почему нельзя усреднять значения перцентилей между разными серверами (Average of p99)?

Ответ: Перцентили не аддитивны. Нельзя вычислить $\frac{p99{node1} + p99{node2}}{2}$ и получить общий p99 кластера: Если Сервер 1 обработал 10 000 запросов с $p99 = 100\text{ мс}$, а Сервер 2 обработал 10 запросов с $p99 = 5000\text{ мс}$, математическое среднее $(100 + 5000) / 2 = 2550\text{ мс}$ даст абсолютно искаженную картину. Правило: В Prometheus для корректного вычисления квантилей агрегируются гистограммы (Histogram Buckets) по всем узлам кластера через sum(...) by (le), и только затем применяется функция histogram_quantile(0.99, ...).

3. В чем разница между Pull-моделью (Prometheus) и Push-моделью (StatsD / Datadog)?

Ответ:

  • Pull-модель (Prometheus): Сервер мониторинга сам периодически (каждые 15 сек) опрашивает микросервисы по HTTP (GET /actuator/prometheus). Плюсы: Легко обнаружить смерть сервиса (если под не отвечает на скрейп — он упал); защита сервера мониторинга от перегрузки (он сам регулирует частоту опроса).
  • Push-модель (StatsD / Telegraf): Микросервис сам шлет UDP/TCP пакеты на сервер мониторинга при каждом событии. Плюсы: Идеально для короткоживущих задач (Serverless / AWS Lambda / Batch Jobs), которые могут завершиться до прихода скрейпера Prometheus.

4. Что такое «Alert Fatigue» (Усталость от алертов) и по каким критериям алерт считается качественным (Actionable Alert)?

Ответ: Alert Fatigue возникает, когда дежурные инженеры получают десятки нерелевантных уведомлений в день. Со временем инженеры перестают реагировать на оповещения и игнорируют критическую аварию. Критерии качественного алерта (Actionable):

  1. Срабатывает только при нарушении пользовательского опыта (симптоматический алерт: упал SLO, растут 5xx ошибки), а не по внутренним причинам (например, «CPU > 80%» — не алерт, если сервис отвечает за 5 мс).
  2. Требует немедленного вмешательства человека.
  3. Имеет понятную инструкцию (Runbook / Playbook), где описаны первые три шага диагностики и локализации проблемы.

🎯 Шпаргалка для интервью

Главное:

  • Три кита Observability: Метрики (Prometheus), Логи (Loki / OpenSearch), Трейсы (Jaeger / OpenTelemetry).
  • 4 Golden Signals (Google): Latency, Traffic, Errors, Saturation.
  • RED-метод для сервисов: Rate, Errors, Duration.
  • USE-метод для серверов/ресурсов: Utilization, Saturation, Errors.
  • Оценивайте скорость по перцентилям (p95, p99), а не по среднему арифметическому.
  • Опасность кардинальности (Cardinality Explosion): Никогда не передавайте динамические ID (userId, orderId) в теги метрик Prometheus!
  • Стандарт в Java — Spring Boot Actuator + Micrometer.
  • Управление надежностью строится вокруг SLI / SLO и скорости выгорания Error Budget (Burn Rate).

Красные флаги (Чего говорить НЕЛЬЗЯ):

  • ❌ «Мы измеряем скорость работы микросервисов по Average Latency» (Среднее скрывает катастрофические задержки хвоста распределения).
  • ❌ «Мы пишем userId в теги метрик Prometheus для детальной аналитики» (Убьет память Prometheus за счет взрыва кардинальности).
  • ❌ «Чем больше алертов настроено в Grafana — тем надежнее система» (Приведет к Alert Fatigue и пропуску реальных инцидентов).

Связанные темы: