Как внедрить наблюдаемость в микросервисное приложение с помощью OpenTelemetry, Jaeger и Prometheus

в 8:15, , рубрики: devops, node.js, prometheus, метрики, микросервисы, телеметрия, трассировки

Современные веб-приложения всё чаще строятся по микросервисной архитектуре. Это даёт гибкость, масштабируемость и изоляцию компонент, но одновременно усложняет отладку, мониторинг и понимание работы системы в целом. Что, если один из сервисов начинает работать медленнее? Как понять, где в цепочке запросов «узкое место»? Как быстро определить причину сбоя или деградации производительности?

Здесь на сцену выходит концепция наблюдаемости (observability). Идея заключается в том, чтобы собрать метрики, логи и трассировки из всех компонентов системы, связать их воедино, и получить чёткую картину того, что происходит внутри распределённого приложения. Для этого существуют современные инструменты вроде:

  • OpenTelemetry — открытая спецификация и набор SDK/агентов для сбора телеметрии (метрик, логов, трассировок).

  • Jaeger — платформа для распределённого трейсинга (прослеживания запросов сквозь множество сервисов).

  • Prometheus — система мониторинга и сбора метрик, ставшая де-факто стандартом в мире Kubernetes и облачных сред.

В этой статье мы шаг за шагом рассмотрим, как объединить эти инструменты, чтобы вы могли получить наглядное представление о поведении вашего микросервисного приложения, улучшить диагностику проблем и сократить время реагирования на инциденты.

Что такое наблюдаемость и зачем она нужна

Наблюдаемость — это способность системы предоставлять достаточно информации, чтобы понять её внутреннее состояние, не внося дополнительных изменений в код в момент исследования проблемы. Если раньше для отладки хватало логов, то в современных распределённых системах логи нужно дополнять метриками (измерениями производительности), трассировками (путями прохода запросов) и событиями.

Три столпа наблюдаемости:

  1. Логи: Человеко-читаемые записи событий. Они дают локальную информацию о том, что произошло внутри конкретного сервиса.

  2. Метрики: Числовые показатели (например, время ответа, количество запросов, использование памяти) по которым можно судить о производительности и состоянии системы.

  3. Трассировки: Подробный путь запроса через систему, включая длительность отдельных этапов и вызовов. Это ключ к пониманию того, где именно «застревает» запрос.

Комбинация этих данных позволяет быстро локализовать проблемный узел, понять причину деградации или сбоя, а затем оперативно всё исправить.

Краткий обзор инструментов

OpenTelemetry (OTel):
OpenTelemetry — это открытой стандарт, цель которого — единообразно собирать телеметрию из приложений. OTel поддерживает множество языков и фреймворков, позволяя вам использовать единый подход к сбору данных. Когда вы интегрируете OTel SDK в свой код, приложение начинает экспортировать метрики, логи и трассировки.

Jaeger:
Jaeger — это система для распределённого трейсинга от CNCF. Она отлично интегрируется с OpenTelemetry. Трассировки, собранные OTel SDK, можно пересылать в Jaeger для визуализации и анализа. Вы сможете видеть цепочку вызовов микросервисов и измерять время выполнения каждой операции.

Prometheus:
Prometheus — это система мониторинга и сбора метрик с собственным форматом экспозиции данных (Pull-модель). Многие библиотеки OpenTelemetry умеют экспортировать метрики в формат, удобный для Prometheus. Собрав метрики с ваших микросервисов, вы сможете строить графики, настраивать алерты и отслеживать тенденции.

Архитектура решения

Допустим, у вас есть несколько микросервисов (на Go, Java или Node.js — не важно), каждый из которых:

  1. Интегрирован с OpenTelemetry SDK.

  2. Экспортирует трассировки в OpenTelemetry Collector, который затем передаёт их в Jaeger для визуализации.

  3. Экспортирует метрики в формате, понятном 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, и вы сможете видеть графики, строить запросы и настраивать алерты.

Практические советы

  1. Локальное окружение: Начните с запуска Jaeger, Prometheus и OTel Collector локально в Docker, тестируйте приложение у себя.

  2. Инструментация кода: Используйте автоинструментацию OTel и дополнительные плагины для вашего фреймворка (Express, gRPC и т.п.).

  3. Метрики производительности: Обращайте внимание на такие метрики как latency запросов, количество успешных/неуспешных ответов, использование CPU и памяти.

  4. Алертинг: Добавьте Alertmanager (компонент из экосистемы Prometheus) для отправки уведомлений при достижении критических значений метрик.

  5. Продакшен и безопасность: В продакшене настройте доступ к метрикам и трассировкам, используйте аутентификацию и шифрование, если необходимо.

Заключение

Внедрение наблюдаемости в микросервисное приложение — важный шаг к повышению его надёжности и управляемости. Используя OpenTelemetry в качестве единого слоя сбора телеметрии, Jaeger для распределённого трейсинга и Prometheus для метрик, вы получите всесторонний взгляд на состояние вашей системы.

Наблюдаемость не только упрощает отладку проблем, но и помогает принимать обоснованные решения: где оптимизировать код, какие сервисы масштабировать, какие запросы кешировать. Итог — более стабильный, предсказуемый и удобный в сопровождении продукт.

Попробуйте сами настроить данный стек инструментов и посмотрите, насколько проще станет диагностика проблем в вашей микросервисной архитектуре.

Автор: DTGP

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js