🏗️ Розділ 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-запити для сповіщень (Alerting)

Розрахунок відсотка помилок сервісу за останні 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):

  • Кожна унікальна комбінація назви метрики та її міток (labels / 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\%$ від усіх запитів за місяць.
  • Якщо система вкладається в бюджет помилок — продуктові команди мають право швидко викатувати нові ризиковані фічі.
  • Якщо бюджет помилок вичерпано за перший тиждень місяця — релізи блокуються (Code Freeze), а всі інженерні ресурси спрямовуються на стабілізацію архітектури та усунення технічного боргу.

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 та ігнорування справжніх аварій).

Пов’язані теми: