Помните, когда мониторинг распределённой системы казался попыткой найти определённую песчинку на пляже с завязанными глазами? Да, были такие времена. А теперь представьте, что вы делаете это с тысячами узлов, микросервисами, общающимися друг с другом, как соседи, сплетничающие о происходящем, и задержками в сети, которые создают вам проблемы каждые пять секунд. Добро пожаловать в прекрасный хаос мониторинга производительности распределённых систем.
Правда в том, что без надлежащего мониторинга ваша распределённая система — это, по сути, чёрный ящик — и не тот, который является информативным самописцем. Это тот, который заставляет вас лихорадочно обновлять информационные панели в 3 часа ночи, пока ваша система оповещения молча не срабатывает, потому что, ну, у кого было время настроить её должным образом?
Эта статья поможет вам создать комплексную систему мониторинга производительности, которая превратит вашу распределённую инфраструктуру из загадки, завёрнутой в головоломку, во что-то понятное, отлаживаемое и оптимизируемое.
Понимание ландшафта мониторинга
Прежде чем мы начнём забрасывать проблему инструментами и кодом, давайте определимся, что мы на самом деле пытаемся решить. В распределённых системах производительность не существует в вакууме. Ваша задержка зависит не только от циклов процессора; на неё влияют операции ввода-вывода в сети, постановка сообщений в очередь, попадание в кэш, обратные пути к базе данных и десятки других факторов, которые действуют против вас слаженно.
Эффективный мониторинг производительности требует одновременного измерения нескольких параметров. Вам нужно понимать не только то, что работает медленно, но и где оно работает медленно и почему. Вот разница между интуитивным ощущением («система вялая») и оперативной информацией («запросы к пользовательскому сервису занимают 2,3 секунды, причём 1,8 секунды уходит на ожидание ответов от базы данных из-за исчерпания памяти на узле-7»).
Золотые сигналы: ваша полярная звезда
Прежде чем внедрять всё под солнцем, начните с четырёх золотых сигналов мониторинга от Google. Если вы не измеряете ничего другого, измерьте их:
Задержка измеряет, сколько времени требуется для обработки запроса. В распределённых системах необходимо отслеживать как сквозную задержку, так и задержки отдельных сервисов. Запрос может казаться быстрым для ваших пользователей, но быть мучительно медленным внутри вашей инфраструктуры.
Трафик представляет собой нагрузку на вашу систему — думайте о количестве запросов в секунду, обработанных транзакциях или потреблённой пропускной способности. Этот показатель помогает понять, имеете ли вы дело с постепенным ухудшением или внезапным всплеском.
Ошибки показывают, когда что-то идёт катастрофически неправильно. Частота ошибок важнее, чем вы думаете; даже частота ошибок в 0,1% становится серьёзной проблемой, когда вы обрабатываете миллион запросов в секунду.
Нагрузка указывает на то, насколько заполнены ваши ресурсы. Процессор с загрузкой 85% выглядит нормально, пока вы не поймёте, что это ведущий индикатор того, что всплеск вызовет перегрузку. Нагрузка говорит вам, сколько запаса у вас есть до того, как всё сломается.
Эти четыре показателя дают замечательное представление о состоянии системы, не перегружая вас данными.
Создание архитектуры мониторинга
Давайте визуализируем, как складывается надёжная система мониторинга:
Микросервисы, API
Базы данных, Кэш"] B["Инструментарий
Экспортеры метрик
Пользовательские сборщики"] C["База данных временных рядов
Prometheus"] D["Визуализация
Grafana"] E["Система оповещения
AlertManager"] F["Агрегация журналов
ELK/Loki"] G["Отслеживание APM
Jaeger/Zipkin"] A -->|Экспортировать метрики| B B -->|Push/Scrape| C C -->|Query| D C -->|Rules| E A -->|Отправить журналы| F A -->|Отслеживать запросы| G D -->|Визуализировать| H["Оперативные инженеры"] E -->|Оповещение| H F -->|Поиск/Анализ| H G -->|Расследование проблем| H
Эта архитектура прекрасно разделяет проблемы. Ваши сервисы экспортируют метрики, журналы и трассировки. Системы сбора собирают эти данные телеметрии. Системы хранения организуют их. Наконец, системы визуализации и оповещения делают их актуальными.
Ключевые показатели для отслеживания
Помимо золотых сигналов, вы захотите отслеживать многоуровневые показатели в области инфраструктуры, приложений и бизнеса.
Показатели инфраструктуры отслеживают необработанные ресурсы:
- Использование ЦП и переключение контекста
- Потребление памяти и события сборки мусора
- Задержка и пропускная способность дискового ввода-вывода
- Пропускная способность сети и потеря пакетов
- Ограничения ресурсов и фактическое использование контейнеров/подов
Показатели приложений сосредоточены на том, как ведёт себя ваше программное обеспечение:
- Задержка запросов (и процентили — p50, p95, p99, p99.9)
- Пропускная способность (запросы в секунду)
- Частота и типы ошибок
- Глубина очереди для асинхронной работы
- Процент попаданий в кэш
- Исчерпание пула соединений с базой данных
- Задержка вызовов API сторонних разработчиков
Бизнес-показатели соответствуют организационным целям:
- Транзакции, обработанные в минуту
- Коэффициент конверсии (для систем электронной коммерции)
- Влияние простоев на выручку
- Доступность функций, видимых пользователям
Магия происходит, когда вы сопоставляете эти показатели. Всплеск задержки запросов к базе данных коррелирует с увеличением использования памяти, что вызывает больше сборки мусора, что вызывает конкуренцию потоков, что вызывает тайм-ауты запросов. Без полной картины вы отлаживаете вслепую.
Реализация Prometheus для сбора метрик
Prometheus стал стандартом де-факто для сбора метрик в облачных системах, и не без причины. Он прост, мощен и хорошо интегрируется со всем.
Сначала настроим конфигурацию Prometheus:
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets:
- localhost:9093
rule_files:
- 'alert_rules.yml'
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'api-service'
static_configs:
- targets: ['api-1:8080', 'api-2:8080', 'api-3:8080']
metrics_path: '/metrics'
scrape_interval: 10s
relabel_configs:
- source_labels: [__address__]
target_label: instance
- source_labels: [__scheme__]
target_label: scheme
- job_name: 'database'
static_configs:
- targets: ['db-primary:5432']
metrics_path: '/metrics'
scrape_interval: 30s
- job_name: 'node-exporter'
static_configs:
- targets:
- 'node-1:9100'
- 'node-2:9100'
- 'node-3:9100'
Теперь создадим правила оповещения, которые действительно имеют значение:
# alert_rules.yml
groups:
- name: performance_alerts
interval: 30s
rules:
- alert: HighLatency
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.5
for: 2m
labels:
severity: warning
annotations:
summary: "Обнаружена высокая задержка запроса"
description: "95-й процентиль задержки составляет {{ $value }} с для {{ $labels.service }}"
- alert: ErrorRateElevated
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.01
for: 1m
labels:
severity: critical
annotations:
summary: "Частота ошибок выше 1%"
description: "{{ $labels.service }} имеет {{ $value }} ошибок в секунду"
- alert: HighCPUUsage
expr: node_cpu_usage > 85
for: 3m
labels:
severity: warning
annotations:
summary: "Высокое использование ЦП на {{ $labels.instance }}"
description: "ЦП на {{ $value }}%"
- alert: MemoryPressure
expr: (node_memory_used / node_memory_total) > 0.85
for: 2m
labels:
severity: warning
annotations:
summary: "Критическое использование памяти на {{ $labels.instance }}"
description: "Память на {{ $value | humanizePercentage }}"
- alert: QueueDepthBuildup
expr: queue_depth > 10000
for: 5m
labels:
severity: warning
annotations:
summary: "Накопление невыполненной работы в очереди"
description: "В очереди {{ $labels.queue_name }} накопилось {{ $value }} элементов"
- alert: DatabaseConnectionPoolExhaustion
expr: (
