Современные веб-приложения всё чаще строятся по микросервисной архитектуре. Это даёт гибкость, масштабируемость и изоляцию компонент, но одновременно усложняет отладку, мониторинг и понимание работы системы в целом. Что, если один из сервисов начинает работать медленнее? Как понять, где в цепочке запросов «узкое место»? Как быстро определить причину сбоя или деградации производительности?
Здесь на сцену выходит концепция наблюдаемости (observability). Идея заключается в том, чтобы собрать метрики, логи и трассировки из всех компонентов системы, связать их воедино, и получить чёткую картину того, что происходит внутри распределённого приложения. Для этого существуют современные инструменты вроде:
OpenTelemetry — открытая спецификация и набор SDK/агентов для сбора телеметрии (метрик, логов, трассировок).
Jaeger — платформа для распределённого трейсинга (прослеживания запросов сквозь множество сервисов).
Prometheus — система мониторинга и сбора метрик, ставшая де-факто стандартом в мире Kubernetes и облачных сред.
В этой статье мы шаг за шагом рассмотрим, как объединить эти инструменты, чтобы вы могли получить наглядное представление о поведении вашего микросервисного приложения, улучшить диагностику проблем и сократить время реагирования на инциденты.
Что такое наблюдаемость и зачем она нужна
Наблюдаемость — это способность системы предоставлять достаточно информации, чтобы понять её внутреннее состояние, не внося дополнительных изменений в код в момент исследования проблемы. Если раньше для отладки хватало логов, то в современных распределённых системах логи нужно дополнять метриками (измерениями производительности), трассировками (путями прохода запросов) и событиями.
Три столпа наблюдаемости:
Логи: Человеко-читаемые записи событий. Они дают локальную информацию о том, что произошло внутри конкретного сервиса.
Метрики: Числовые показатели (например, время ответа, количество запросов, использование памяти) по которым можно судить о производительности и состоянии системы.
Трассировки: Подробный путь запроса через систему, включая длительность отдельных этапов и вызовов. Это ключ к пониманию того, где именно «застревает» запрос.
Комбинация этих данных позволяет быстро локализовать проблемный узел, понять причину деградации или сбоя, а затем оперативно всё исправить.
Краткий обзор инструментов
OpenTelemetry (OTel):
OpenTelemetry — это открытой стандарт, цель которого — единообразно собирать телеметрию из приложений. OTel поддерживает множество языков и фреймворков, позволяя вам использовать единый подход к сбору данных. Когда вы интегрируете OTel SDK в свой код, приложение начинает экспортировать метрики, логи и трассировки.
Jaeger:
Jaeger — это система для распределённого трейсинга от CNCF. Она отлично интегрируется с OpenTelemetry. Трассировки, собранные OTel SDK, можно пересылать в Jaeger для визуализации и анализа. Вы сможете видеть цепочку вызовов микросервисов и измерять время выполнения каждой операции.
Prometheus:
Prometheus — это система мониторинга и сбора метрик с собственным форматом экспозиции данных (Pull-модель). Многие библиотеки OpenTelemetry умеют экспортировать метрики в формат, удобный для Prometheus. Собрав метрики с ваших микросервисов, вы сможете строить графики, настраивать алерты и отслеживать тенденции.
Архитектура решения
Допустим, у вас есть несколько микросервисов (на Go, Java или Node.js — не важно), каждый из которых:
Интегрирован с OpenTelemetry SDK.
Экспортирует трассировки в OpenTelemetry Collector, который затем передаёт их в Jaeger для визуализации.
Экспортирует метрики в формате, понятном Prometheus, который их периодически «забирает» (scrape).
Поток данных выглядит примерно так:
Микросервис -> OTel SDK -> OTel Collector -> Jaeger (для трассировок)
\
-> Prometheus (для метрик)
Практический пример на Node.js
Рассмотрим простой пример на Node.js. Предположим, у нас есть микросервис orders-service
, обрабатывающий запросы заказов. Мы хотим собирать трассировки и метрики при помощи OpenTelemetry, визуализировать трассировки в Jaeger и метрики в Prometheus.
Установка зависимостей
npm install @opentelemetry/api @opentelemetry/sdk-node \
@opentelemetry/sdk-trace-node @opentelemetry/sdk-metrics \
@opentelemetry/exporter-trace-otlp-grpc @opentelemetry/exporter-metrics-prometheus \
@opentelemetry/auto-instrumentations-node
Инициализация OpenTelemetry в коде
Создадим файл tracing.js
:
// tracing.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { PrometheusExporter } = require('@opentelemetry/exporter-metrics-prometheus');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
// Настраиваем экспортер трассировок в OTLP формате (коллектор)
const traceExporter = new OTLPTraceExporter({
url: 'http://localhost:4317', // адрес OTel Collector
});
// Настраиваем экспортер метрик для Prometheus
const metricsExporter = new PrometheusExporter({
port: 9464, // порт на котором будет доступен endpoint /metrics
}, () => {
console.log('Prometheus scrape endpoint: http://localhost:9464/metrics');
});
// Ресурс - информация о сервисе
const resource = new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'orders-service',
});
// Создаём и запускаем SDK
const sdk = new NodeSDK({
traceExporter,
metricExporter: metricsExporter,
instrumentations: [getNodeAutoInstrumentations()],
resource
});
sdk.start()
.then(() => console.log('OpenTelemetry started'))
.catch((error) => console.log('Error starting OpenTelemetry', error));
process.on('SIGTERM', () => {
sdk.shutdown()
.then(() => console.log('OpenTelemetry shutdown'))
.catch((error) => console.log('Error shutting down OTel', error));
});
Использование в основном приложении
Создадим файл app.js
:
// app.js
require('./tracing'); // Инициализируем сбор телеметрии
const express = require('express');
const app = express();
app.get('/order', (req, res) => {
// Симулируем обработку заказа
setTimeout(() => {
res.json({ status: 'ok', orderId: 12345 });
}, 200); // задержка 200мс
});
app.listen(3000, () => {
console.log('Order service running on http://localhost:3000');
});
Запуская node app.js
, вы получите сервис на порте 3000, метрики на :9464/metrics
и трассировки, отправляемые в OTLP Collector.
Настройка OpenTelemetry Collector
OTel Collector — отдельный бинарник, который вы можете скачать с GitHub или использовать в Docker-контейнере. Его конфигурация YAML определяет, куда отправлять трассировки. Например:
receivers:
otlp:
protocols:
grpc:
exporters:
jaeger:
endpoint: "http://jaeger:14250" # адрес Jaeger (например, в Docker-сети)
tls:
insecure: true
processors:
batch:
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [jaeger]
При запуске Jaeger (через Docker, например docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p 16686:16686 jaegertracing/all-in-one:latest
), вы сможете открыть интерфейс Jaeger по адресу http://localhost:16686
и искать трассировки от вашего orders-service
.
Настройка Prometheus
Prometheus можно запустить также в Docker:
docker run -d --name prometheus -p 9090:9090 \
-v $PWD/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus
А в файле prometheus.yml
добавить таргет на ваш сервис:
scrape_configs:
- job_name: 'orders-service'
static_configs:
- targets: ['host.docker.internal:9464'] # если запускается локально на хосте
Теперь метрики будут доступны Prometheus, и вы сможете видеть графики, строить запросы и настраивать алерты.
Практические советы
Локальное окружение: Начните с запуска Jaeger, Prometheus и OTel Collector локально в Docker, тестируйте приложение у себя.
Инструментация кода: Используйте автоинструментацию OTel и дополнительные плагины для вашего фреймворка (Express, gRPC и т.п.).
Метрики производительности: Обращайте внимание на такие метрики как latency запросов, количество успешных/неуспешных ответов, использование CPU и памяти.
Алертинг: Добавьте Alertmanager (компонент из экосистемы Prometheus) для отправки уведомлений при достижении критических значений метрик.
Продакшен и безопасность: В продакшене настройте доступ к метрикам и трассировкам, используйте аутентификацию и шифрование, если необходимо.
Заключение
Внедрение наблюдаемости в микросервисное приложение — важный шаг к повышению его надёжности и управляемости. Используя OpenTelemetry в качестве единого слоя сбора телеметрии, Jaeger для распределённого трейсинга и Prometheus для метрик, вы получите всесторонний взгляд на состояние вашей системы.
Наблюдаемость не только упрощает отладку проблем, но и помогает принимать обоснованные решения: где оптимизировать код, какие сервисы масштабировать, какие запросы кешировать. Итог — более стабильный, предсказуемый и удобный в сопровождении продукт.
Попробуйте сами настроить данный стек инструментов и посмотрите, насколько проще станет диагностика проблем в вашей микросервисной архитектуре.