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

Оглавление

  1. Введение
  2. Наблюдаемость (observability)
  3. Ключевые компоненты стека наблюдаемости
  4. Дополнительная информация и лучшие практики
  5. Часто задаваемые вопросы (FAQ)
  6. Заключение

Введение

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

Наблюдаемость (Observability) – это ключ к прозрачности работы системы в продакшене. Это не просто графики и алерты, а способность ответить на главный вопрос: почему система ведет себя так, как ведет?

Эта статья даст понимание того:

  • Что такое наблюдаемость и чем она отличается от мониторинга.
  • Какие данные действительно важны для анализа (метрики, логи, трассировки).
  • Какие инструменты использовать в Java/Spring-приложениях (Micrometer, Prometheus, Grafana, Tempo).
  • Как внедрять наблюдаемость с учетом производительности, гибкости и масштаба.

Наблюдаемость

Наблюдаемость (observability) – это процесс повышения прозрачности внутреннего состояния системы. Другими словами, по собираемым данным можно понять, здоров ли сервис и почему он работает так или иначе. В отличие от классического мониторинга, который показывает только заранее заданные метрики и алерты, наблюдаемость дает возможность исследовать систему “изнутри” и находить неожиданные причины проблем. Для современных распределённых систем (микросервисы, контейнеры, serverless) наблюдаемость особенно важна, так как она помогает понять, как взаимодействуют сотни компонентов.

Существует три основных вида телеметрии (столпа наблюдаемости):

  • Метрики – числовые показатели, привязанные ко времени. Примеры: загрузка CPU/памяти, число запросов в секунду, время ответа сервиса. Метрики хранятся как временные ряды и хорошо подходят для быстрого ответа на вопросы типа “сколько ресурсов сейчас используется” или “как изменилась нагрузка”.
  • Логи – упорядоченные по времени записи событий, например строки из лог-файлов. Логи дают подробный хронологический контекст работы сервисов и часто содержат причину ошибок. С их помощью можно ответить, что происходило в момент сбоя (например, исключения или traceback-и). Обычно логи агрегируются и индексируются для удобного поиска.
  • Трассировки (distributed traces) – данные о прохождении запроса через систему (сеть вызовов между сервисами). Один запрос разбивается на цепочку операций (спанов), каждый из которых замеряет время выполнения части работы. На графике трассировки можно увидеть весь путь запроса и “узкие места” (длинные спаны) при обращении к нескольким микросервисам. Трассировки позволяют быстро понять, какой именно сервис или шаг вызова тормозит или выдаёт ошибку.

Эти три вида данных дополняют друг друга: метрики показывают общее состояние и производительность, логи содержат детальную информацию о событиях, а трассировки связывают всё вместе, показывая энд-то-энд выполнение запросов. В совокупности они дают полный обзор системы.

Рис. 1. Контейнерная (C4) диаграмма типового приложения.

Архитектурная C4-диаграмма типового приложения

На рисунке 1 приведена контейнерная диаграмма (Container Diagram) типового приложения. Каждый прямоугольник (“контейнер”) – это отдельный компонент системы: веб-клиент (или фронтенд), микросервис A (с API и БД), микросервис B, база данных и т.д. Диаграмма показывает, как они взаимодействуют: например, фронтенд отправляет HTTP-запросы в сервисы A и B, а сервис A может запрашивать данные из своей БД.

Схема также включает компоненты наблюдаемости: Exporter (агент, собирающий метрики из хоста или сервиса), Prometheus (система сбора и хранения метрик), Grafana (визуализация и дашборды) и Tempo (бэкенд для трассировок). Стрелки между ними показывают поток данных (например, Prometheus скрапит /metrics у Exporter, а Grafana опрашивает Prometheus). Такая диаграмма даёт общее представление о составах системы и о том, какие части могут быть источниками телеметрии.

Диаграммы последовательности

Для наглядности приведем две диаграммы последовательности для основных процессов сбора телеметрии.

Сбор метрик (Exporter –> Prometheus –> Grafana)

Рис. 2. Диаграмма последовательности сбора метрик.

На этой диаграмме Prometheus (P) регулярно опрашивает (scrape) указанный экспортер (E) по HTTP и получает от него метрики. Затем Grafana (G) выполняет запрос (PromQL) к Prometheus и получает данные для построения графиков и отправки алертов. Таким образом, Exporter собирает необработанные метрики из системы, Prometheus хранит их, а Grafana запрашивает их для визуализации.

Сбор трассировок (Alloy –> Tempo)

Рис. 3. Диаграмма последовательности сбора спанов.

В этом примере сервис S посылает собранные трассировки (спаны) через Grafana Alloy (ранее – Grafana Agent, A), который служит сборщиком и маршрутизатором телеметрии. Alloy пересылает полученные спаны в систему хранения Tempo (T). Затем Grafana (G) запрашивает у Tempo данные по конкретному запросу и получает полную цепочку спанов этой трассировки. Такая цепочка позволяет увидеть путь запроса через сервисы (затраты времени на каждый спан) и сопоставить их с метриками и логами.

Ключевые компоненты стека наблюдаемости

  • Prometheus – открытая система мониторинга и хранилище временных рядов. Prometheus регулярно опрашивает (scrape) указанные цели (экспортеры) по HTTP и сохраняет метрики с метками (labels). Модель сбора – pull-over-HTTP: Prometheus сам забирает данные с /metrics у сервисов. Такая схема упрощает обнаружение сервисов и повышает надежность (при падении клиента данные просто не собираются до его восстановления). Отдельно поддерживается Pushgateway для сценариев batch/одноразовых задач: в этом случае сервис сам отправляет (push) метрики через промежуточный шлюз. Prometheus имеет собственную TSDB и мощный язык запросов PromQL, а для визуализации обычно используется Grafana.
  • Exporter – это небольшое приложение/агент, которое собирает метрики из какого-то источника (ОС, БД, веб-сервиса и т.д.) и предоставляет их в формате Prometheus по HTTP. Экспортеры незаменимы, когда невозможно встроить Prometheus-клиент напрямую в приложение. Примеры: node_exporter (метрики хоста: CPU, память, диски), blackbox_exporter (проверяет доступность HTTP/DNS/ICMP), mysqld_exporter, postgres_exporter (метрики баз данных), jmx_exporter (метрики Java), а также кастомные экспортеры под конкретные сервисы. Экспортеры запускаются рядом с сервисами (на хостах или в контейнерах) и делают внутренние показатели доступными для Prometheus.
  • Grafana – система построения графиков, дашбордов и настройки алертов. Grafana подключается к Prometheus (и другим источникам данных) и визуализирует метрики в виде графиков, таблиц, диаграмм и т.д. Для каждого показателя можно установить пороговые значения и алерты (уведомления) при их превышении. Grafana предоставляет готовые шаблоны дашбордов и панели для различных источников данных. Например, после того как Prometheus накопил метрики, Grafana (или встроенная в Prometheus Expression Browser) позволяет наглядно построить график метрики и настроить оповещение. Grafana часто является “единым окном” SRE-инженера: на ее дашбордах собираются ключевые показатели (нагрузка, задержка, ошибки и т.д.) со всей системы.
  • Grafana Alloy (ранее Grafana Agent или просто Agent) – универсальный агент/коллектор от Grafana Labs. Это по сути дистрибутив OpenTelemetry Collector, заточенный для работы со стеком Grafana. Alloy способен собирать метрики, логи, трассировки и передавать их дальше в выбранные хранилища (например, в Prometheus/Mimir для метрик, Loki для логов, Tempo для трассировок). “Alloy – это дистрибутив OTel-коллектора с нативными пайплайнами для OpenTelemetry и Prometheus форматов, поддерживающий метрики, логи, трассировки и профили”. Он внедряется на серверах или в контейнерах и упрощает агрегацию телеметрии перед отправкой в Grafana Cloud или самописные бэкенды. Ранее Grafana Agent имел специфическую конфигурацию, сейчас его заменяет Alloy с новой конфигурационной моделью.
  • Grafana Tempo – бэкенд для хранения и поиска распределенных трассировок. Tempo – это открытая, высокомасштабируемая система для работы с трейсами. Для хранения он использует недорогое object storage (S3/GCS), поэтому масштабируется практически без больших затрат. Tempo глубоко интегрирован с Grafana, Prometheus и Loki: в интерфейсе Grafana можно связать трассировки с метриками и логами. В Tempo можно выполнять поиск по идентификатору трассировки или по полям спана, а также строить агрегированные метрики на основе спанов (Span metrics).

Дополнительная информация и лучшие практики

  • OpenTelemetry – современный стандарт инструментирования приложений для наблюдаемости. С помощью OpenTelemetry-прослойки (библиотеки) в коде автоматически собираются метрики и спаны трассировок, которые передаются в коллектор (например, Grafana Alloy). Instrumentation (инструментирование) – ключевой момент: приложение должно быть “подготовлено” к сбору телеметрии (прописаны точки сбора, контексты, ID запросов). Тогда при возникновении проблемы не придётся добавлять логи или метрики “на лету” – все необходимое уже собирается.
  • Push vs Pull (pushgateway): По умолчанию Prometheus использует pull-модель (сам опрашивает цели). Это делает систему более предсказуемой и безопасной (Prometheus контролирует, когда скрапить). Push-модель применяется редко – в основном через Pushgateway для партийных (одноразовых) задач, когда сервис кратковременно появляется и исчезает. Best practice: старайтесь избегать множественных временных series с очень высоким cardinality (множество уникальных лейблов), это сильно нагружает систему мониторинга.
  • Метрики и алерты: Следует выбирать ключевые индикаторы (например, загрузка CPU, задержки, уровень ошибок – “four golden signals” из SRE: latency, traffic, errors, saturation). Устанавливайте SLI/SLO и старайтесь настраивать алерты именно на самые важные метрики, которые влияют на пользовательский опыт. Избегайте заполнять Prometheus тысячами малозначимых метрик: каждая метрика с лейблами должна иметь чёткую цель.
  • Логи: Рекомендуется собирать структурированные логи (JSON), агрегировать их в систему типа Grafana Loki или ELK. Логи должны быть по возможности информативны, с указанием request_id/spans, чтобы можно было связать их с трассировкой.
  • Трассировки: отслеживайте весь путь запроса через сервисы, “прокидывая” уникальный trace_id в заголовках. Стоит использовать эндпоинты поддерживающие OpenTelemetry (например OTLP HTTP/gRPC) и собирать данные через Alloy/Tempo. Не забывайте о сэмплинге, чтобы не перегружать систему избыточными спанами.
  • Корреляция данных: стоит использовать возможности Grafana (exemplars) и лейблов Prometheus для связывания метрик с trace_id из трассировок и с событиями в логах. Это облегчает поиск “root cause”.

Часто задаваемые вопросы (FAQ)

1. Чем Observability отличается от Monitoring?

Ответ:
Monitoring отвечает на вопрос: “что пошло не так?” – он показывает заранее определенные метрики и срабатывает по алертам.
Observability – это возможность понять “почему” система ведет себя так, а не иначе. Она предоставляет контекст, необходимый для диагностики новых, неизвестных проблем на основе трёх типов телеметрии: метрик, логов и трассировок. Monitoring – часть observability, но не наоборот.

2. Какие три типа данных нужны для полной наблюдаемости?

Ответ:

  • Метрики – числовые значения, привязанные ко времени (RPS, CPU usage, latency);
  • Логи – текстовые сообщения о событиях (ошибки, статусы, входящие параметры);
  • Трассировки – информация о цепочке вызовов между сервисами с деталями времени выполнения и ошибок.

Все три типа важны: метрики для мониторинга общего состояния, логи для детализации, трассировки для анализа поведения запросов между компонентами.

3. Почему Prometheus использует pull-модель (а не push)?

Ответ:
Prometheus сам опрашивает экспортёры и сервисы по HTTP /metrics. Это упрощает:

  • контроль частоты запросов;
  • безопасность (push часто требует открытых портов);
  • отказоустойчивость (при падении target метрики просто не приходят, но Prometheus работает дальше).

Push используется только в особых случаях (batch-джобы) через PushGateway.

4. Что такое Exporter в контексте Prometheus?

Ответ:
Exporter – это агент, который преобразует данные из системы (ОС, базы, приложения) в метрики Prometheus-формата. Он открывает endpoint /metrics, куда приходит Prometheus и забирает данные.
Exporter может быть отдельным процессом или частью приложения.

5. Примеры популярных Exporter’ов:

Ответ:

  • node_exporter – метрики ОС (CPU, память, диски);
  • blackbox_exporter – проверка доступности по ICMP, TCP, HTTP;
  • postgres_exporter – метрики PostgreSQL (кол-во соединений, время запросов);
  • jmx_exporter – для Java-приложений, использующих JMX.

6. Сильно ли нагружает Prometheus систему?

Ответ:
Prometheus делает легкие HTTP GET-запросы по /metrics. Он не нагружает систему, если:

  • не использовать динамические метки (userId, requestId);
  • ограничивать label cardinality (не создавать миллионы уникальных label-комбинаций);
  • не scrape’ить метрики слишком часто.

Главный риск – взрывной рост числа временных рядов, а не частота запросов.

7. Является ли Grafana Alloy заменой Prometheus?

Ответ: Нет.

  • Prometheus – это TSDB (timestamp database) и сборщик метрик.
  • Alloy – агент маршрутизации и сбора телеметрии: метрик, логов, трассировок.

Обычно Alloy передает метрики в Prometheus или Grafana Mimir. Он полезен, когда нужно унифицировать сбор данных в одной точке.

8. Можно ли использовать Prometheus без Grafana?

Ответ: Да, Prometheus включает веб-интерфейс с PromQL-браузером и Alertmanager для алертов.
Но:

  • Grafana предоставляет мощные дашборды, drill-down, визуальные шаблоны;
  • Alertmanager без Grafana хуже визуализирует контекст алертов.

Итог: можно использовать Prometheus отдельно, но удобнее – с Grafana.

9. Как связать метрики и трассировки?

Ответ:
Prometheus поддерживает exemplars – это специальные значения метрик, содержащие trace_id.
Если Micrometer/OTel в приложении прокидывает trace_id, то Prometheus может сохранить его в метке к метрике. Grafana позволяет кликнуть на точку графика –> перейти к трассировке в Tempo.
Также можно добавить trace_id в MDC логов, чтобы связать все: метрика –> трассировка –> лог.

10. Какие метрики есть в Spring Boot Actuator?

Ответ:
Spring Boot Actuator + Micrometer из коробки предоставляет обширный набор метрик, доступных по эндпоинту /actuator/prometheus при подключённом Prometheus-регистраторе. Включены:

  • HTTP-запросы: http.server.requests – время ответа, статус-коды, количество запросов;
  • JVM:
  • jvm.memory.used, jvm.memory.max – использование памяти по областям (heap, non-heap);
  • jvm.gc.pause – паузы сборщика мусора;
  • jvm.threads.live, jvm.threads.daemon – потоки;
  • Система: system.cpu.usage, process.uptime, process.files.open;
  • Datasource: db.connections.active, db.connections.max, db.connections.pending;
  • Кэш (если используется Spring Cache): cache.gets, cache.puts, cache.misses;
  • Логгеры: logback.events по уровням логирования;
  • Собственные метрики приложения – можно добавить через Micrometer.

Эти метрики автоматически включаются при подключении spring-boot-starter-actuator и зависимости micrometer-registry-prometheus.

11. Как добавить кастомные метрики в Spring Boot?

Ответ:
Для добавления своих метрик используется MeterRegistry, доступный как Spring-бин:

@Autowired
MeterRegistry registry;

public void process() {
    registry.counter("custom.process.count").increment();
}

Можно создавать:

  • Counter – счетчик событий;
  • Timer – измерение продолжительности операций;
  • Gauge – текущее значение (например, размер очереди);
  • DistributionSummary – статистика по числовым значениям (min/max/avg/percentile).

Также можно использовать аннотации:

@Timed("my.service.timer")
public void handleRequest() { ... }

Если вы используете MDC, то через MeterFilter можно обогащать метки динамическими значениями (tenant_id, region, и т.д.). Это особенно полезно в мультиарендных системах.

12. Как связать логи и трассировки в Spring-приложении?

Ответ:
Для связывания логов и трассировок необходимо, чтобы trace_id и span_id попадали в каждый лог. Это реализуется через MDC (Mapped Diagnostic Context) и настройку шаблона логирования. Пример конфигурации Logback:

<pattern>%d{yyyy-MM-dd HH:mm:ss} [%X{traceId}] [%X{spanId}] %-5level %logger{36} - %msg%n</pattern>

Библиотеки Micrometer Tracing или Spring Cloud Sleuth автоматически помещают эти значения в MDC. В результате каждый лог содержит traceId, по которому можно найти трассировку в Tempo. Это позволяет делать переход от алерта или строки лога к полной цепочке вызова.

13. Как включить трассировки в Spring Boot 3+?

Ответ:
С версии Spring Boot 3+ используется Micrometer Tracing. Для настройки трассировок:

  1. Подключаем зависимости:
implementation("io.micrometer:micrometer-tracing-bridge-otel")
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
  1. Настраиваем OTLP-экспорт в application.yml:
management:
  tracing:
    sampling:
      probability: 1.0
otel:
  exporter:
    otlp:
      endpoint: http://alloy:4317
  1. Используем аннотации:
@Observed(name = "my.custom.span")
public void process() { ... }
  1. Включаем propagation через заголовки traceparent.

Результат: все HTTP-запросы и аннотированные методы будут автоматически трассироваться, а данные попадут в Alloy –> Tempo –> Grafana.

14. Стоит ли использовать SaaS-решения (Datadog, NewRelic)?

Ответ:
Да, если:

  • Вам нужно быстрое время запуска (MVP/PoC).
  • Вы не хотите тратить ресурсы на поддержку собственного observability-стека.
  • У вас небольшой кластер или приложение.

Нет, если:

  • У вас десятки/сотни микросервисов –> расходы резко возрастают.
  • Важны требования по безопасности (on-prem необходим).
  • Нужна глубокая интеграция с Kubernetes, кастомные метки/дашборды.
  • Вы хотите избежать vendor lock-in и дорогих лицензий.

Вывод: SaaS – это удобно, но дорого и ограничено. Grafana + Prometheus – это гибко, расширяемо, но требует DevOps-инфраструктуры.

15. Зачем нужен Micrometer в Spring, если есть Prometheus?

Ответ:
Micrometer – это абстракция над системой метрик. Он встроен в Spring Boot Actuator и позволяет разработчику собирать метрики в независимом от конкретной системы формате.

    Prometheus – это бэкенд-хранилище и система сбора метрик, а Micrometer – способ их генерации в приложении. Micrometer может экспортировать данные не только в Prometheus, но и в другие системы: Graphite, Datadog, New Relic, InfluxDB и т.д.

    Почему это важно:

    Вы не привязываете код к Prometheus напрямую.

    Micrometer автоматически собирает множество полезных метрик Spring Boot (http.server.requests, jvm.memory.used, process.cpu.usage, logback.events, db.connections.active и т.д.).

    Через Micrometer можно добавлять свои метрики (counter, gauge, timer) одной строчкой.

    Prometheus в этом случае – просто один из адаптеров Micrometer, подключаемый через зависимость micrometer-registry-prometheus.

    Пример:

    
    @Autowired
    private MeterRegistry meterRegistry;
    public void process() {
    meterRegistry.counter("custom.process.count").increment();
    }


    Вывод:
    Prometheus отвечает за сбор и хранение метрик,
    а Micrometer – за генерацию и форматирование метрик в коде Spring Boot. Они не конкуренты, а дополняющие части observability-стека.

    16. Как включить метрики для JDBC-запросов в Spring Boot?

    Ответ:
    Spring Boot Actuator автоматически включает метрики подключения к базе данных (db.connections.active, db.connections.max, db.connections.pending) при использовании встроенного DataSource.
    Если используется пул HikariCP (по умолчанию в Spring Boot), метрики автоматически интегрируются с Micrometer.
    Для мониторинга SQL-запросов по времени выполнения и количеству следует использовать DataSourceProxy или AOP-инструментирование.

    17. Как ограничить объём собираемых метрик от Micrometer?

    Ответ:
    Рекомендуется использовать MeterFilter:

    @Bean
    public MeterFilter denyJvmGcPause() {
        return MeterFilter.denyNameStartsWith("jvm.gc.pause");
    }

    Также можно настраивать include/exclude через application.yml:

    management.metrics.enable.jvm.gc.pause: false

    Это снижает количество временных рядов и уменьшает нагрузку на Prometheus.

    18. Можно ли связать трассировку с конкретным HTTP-запросом?

    Ответ:
    Да. В Micrometer Tracing автоматически генерируются trace_id и span_id и прокидываются через HTTP-заголовки (traceparent, baggage, X-B3-TraceId и др.).
    Эти значения:

    • фиксируются в логах (через MDC);
    • видны в трассировках (Tempo);
    • могут быть добавлены в метки (labels) кастомных метрик, чтобы сделать переход от метрики –> лог –> трассировка.

    19. Как настроить алерты по метрикам в Spring-приложении?

    Ответ:
    В Spring Boot сам по себе алертинг не встроен, но Prometheus + Alertmanager позволяют писать правила на любые метрики:

    - alert: HighErrorRate
      expr: rate(http_server_requests_seconds_count{status=~"5.."}[1m]) > 0.05
      for: 1m
      labels:
        severity: warning
      annotations:
        summary: "Высокий уровень 5xx-ошибок"

    Grafana может визуализировать эти алерты и отправлять нотификации (Slack, Telegram, email и др.).

    20. Как избежать high cardinality в метриках Spring Boot?

    Ответ:
    High cardinality возникает, когда метка (label) принимает слишком много уникальных значений (например, user_id, session_id, uri). Это приводит к взрыву числа временных рядов (time series) в Prometheus и перегрузке хранилища.

    Чтобы избежать этого:

    • Не рекомендуется использовать uri целиком в метках: вместо /orders/123 лучше /orders/{id}.
    • Стоит избегать Exception классов в виде лейблов – рекомендуется использовать группировку по типам или статусам.
    • Стоит использовать .tag("status", "success"), но не .tag("userId", userId) без необходимости.
    • Рекомендуется применять MeterFilter для фильтрации ненужных меток:
    @Bean
    public MeterFilter limitCardinality() {
        return MeterFilter.maximumAllowableTags("http.server.requests", "uri", 100);
    }

    Также не забудьте, что Prometheus не очищает старые метки мгновенно – они остаются до ротации данных.

    Заключение

    В современном мире распределенных систем, микросервисов и облачных сред наблюдаемость – не опция, а необходимость. Разработчику уже недостаточно знать, как работает бизнес-логика, он должен понимать, как и почему работает (или не работает) вся система.

    Три источника телеметрии: метрики, логи и трассировки – позволяют отвечать на вопросы:

    • Что происходит в системе прямо сейчас?
    • Почему запросы замедлились?
    • Где именно происходит сбой?
    • Что привело к аномалии в поведении?

    Инструменты вроде Prometheus, Grafana, Tempo, Alloy и Micrometer помогают не просто собирать эти данные, а делать их доступными, взаимосвязанными и полезными.

    Внедряя практики наблюдаемости в свои проекты, вы повышаете:

    • устойчивость систем к сбоям;
    • скорость диагностики и восстановления;
    • прозрачность взаимодействия между компонентами;
    • доверие со стороны DevOps/SRE-команд и бизнеса.

    Наблюдаемость – это основа зрелой инженерной культуры.

    Loading