Спостережуваність Spring Boot у 2026: OpenTelemetry, розподілене трасування та питання на співбесідах
Повний посібник зі спостережуваності Spring Boot з OpenTelemetry та Micrometer Tracing. Налаштування розподіленого трасування, Observation API, експорт OTLP та підготовка до технічних співбесід.

Спостережуваність Spring Boot поєднує логування, метрики та розподілене трасування в єдину систему, що показує потік запитів через мікросервіси. Починаючи з Spring Boot 3, фреймворк прийняв Micrometer Tracing (замінивши Spring Cloud Sleuth) та представив Observation API, що забезпечує єдину точку інструментації, яка генерує як метрики, так і трейси.
Spring Boot рекомендує використовувати Observation.observe() замість прямого виклику OpenTelemetry. Один виклик інструментації створює метрики через Micrometer та трейси через міст OpenTelemetry, зменшуючи дублювання коду та забезпечуючи узгоджене іменування тегів між сигналами.
Як Observation API поєднує Micrometer та OpenTelemetry
Observation API діє як фасад над метриками та трасуванням. Коли код викликає Observation.createNotStarted(), Spring Boot направляє спостереження до зареєстрованих обробників: MeterObservationHandler для метрик Micrometer та TracingObservationHandler для розподіленого трасування. Ця архітектура означає, що одноразова інструментація експортує дані всюди.
Залежність-міст micrometer-tracing-bridge-otel з'єднує Micrometer Tracing з SDK OpenTelemetry. Трейси проходять через SdkTracerProvider OpenTelemetry та експортуються через OTLP до бекендів, таких як Jaeger, Tempo або будь-який колектор, сумісний з OpenTelemetry.
@Configuration
public class ObservabilityConfig {
@Bean
public ObservationRegistryCustomizer<ObservationRegistry> addLowCardinalityTags() {
return registry -> registry.observationConfig()
.observationHandler(new ObservationTextPublisher()); // Логує спостереження в консоль
}
}Наведена конфігурація реєструє ObservationHandler, який логує кожне спостереження. У продакшені автоматично налаштовані обробники надсилають дані до реєстрів Micrometer та експортерів OpenTelemetry без додаткового коду.
Необхідні залежності для Spring Boot 3.4 Tracing
Spring Boot 3.4 вимагає явних залежностей для розподіленого трасування. spring-boot-starter-actuator надає Observation API, але трасування потребує моста OpenTelemetry та експортера.
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>Артефакт micrometer-tracing-bridge-otel з'єднує Micrometer Tracing з API OpenTelemetry. opentelemetry-exporter-otlp надсилає спани до колекторів, використовуючи протокол OTLP через HTTP або gRPC. Spring Boot керує вирівнюванням версій через своє управління залежностями.
Налаштування експорту OTLP до Jaeger або Tempo
Spring Boot автоматично налаштовує OtlpHttpSpanExporter, коли присутня залежність OTLP. Експортер надсилає трейси до ендпоінта, вказаного в application.yml.
# application.yml
management:
tracing:
sampling:
probability: 1.0 # 100% семплювання для розробки, зменште у продакшені
otlp:
tracing:
endpoint: http://localhost:4318/v1/traces
opentelemetry:
resource-attributes:
service.name: order-service
deployment.environment: stagingresource-attributes додають метадані до кожного спана. Бекенди, такі як Grafana Tempo та Jaeger, використовують ці атрибути для групування трейсів за сервісом та середовищем. Встановлення sampling.probability на 1.0 захоплює всі запити під час розробки, але продакшен-системи зазвичай семплюють від 1% до 10% для контролю витрат на зберігання.
Створення власних спостережень з тегами низької та високої кардинальності
Спостереження підтримують два типи тегів: низької кардинальності для метрик (обмежені значення, як HTTP-методи або коди статусу) та високої кардинальності для трейсів (необмежені значення, як ID користувача або ID запиту).
@Service
public class PaymentService {
private final ObservationRegistry observationRegistry;
public PaymentService(ObservationRegistry observationRegistry) {
this.observationRegistry = observationRegistry;
}
public PaymentResult processPayment(PaymentRequest request) {
return Observation.createNotStarted("payment.process", observationRegistry)
.lowCardinalityKeyValue("payment.method", request.getMethod().name()) // enum: CARD, BANK_TRANSFER
.lowCardinalityKeyValue("currency", request.getCurrency()) // обмежено: USD, EUR, GBP
.highCardinalityKeyValue("payment.id", request.getPaymentId()) // унікальний для запиту
.highCardinalityKeyValue("customer.id", request.getCustomerId()) // висока кардинальність
.observe(() -> executePayment(request));
}
private PaymentResult executePayment(PaymentRequest request) {
// Виклик платіжного шлюзу
return new PaymentResult(true, "TXN-" + UUID.randomUUID());
}
}Теги низької кардинальності з'являються як у метриках, так і в трейсах. Теги високої кардинальності з'являються лише в трейсах, оскільки метрики з необмеженими вимірами вибухають сховище. Це розрізнення запобігає бомбам кардинальності в Prometheus, зберігаючи багаті деталі трейсів.
Інтерв'юери часто запитують, чому деякі теги слід виключати з метрик. Відповідь стосується кардинальності: тег ID користувача на метриці створює один часовий ряд на користувача, потенційно мільйони рядів. Бекенди моніторингу мають проблеми з високою кардинальністю, що призводить до вичерпання пам'яті та повільних запитів. Трейси обробляють високу кардинальність через семплювання, що робить їх правильним місцем для ідентифікаторів, специфічних для запиту.
Готовий до співбесід з Spring Boot?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Поширення контексту трейса через асинхронні межі
Розподілене трасування вимагає поширення контексту. HTTP-заголовки переносять ID трейсів між сервісами, але асинхронні операції, такі як методи @Async або ланцюжки CompletableFuture, можуть втратити контекст, якщо не налаштовані.
Spring Boot 3.4 забезпечує автоматичне поширення для реактивних потоків та методів @Async при відповідному налаштуванні:
# application.yml
spring:
reactor:
context-propagation: auto
task:
execution:
propagate-context: trueДля власних бінів TaskExecutor їх слід обгорнути в ContextPropagatingTaskDecorator:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
executor.initialize();
return executor;
}
}Декоратор копіює поточну Observation та контекст трейса в асинхронний потік. Без нього спани, розпочаті в асинхронних завданнях, не мають батьківського спана, що порушує дерево трейсів.
Використання анотацій @Observed та @NewSpan
Spring Boot 3.4 підтримує декларативну спостережуваність через анотації. Увімкніть обробку анотацій, додавши AspectJ weaver:
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency># application.yml
management:
observations:
annotations:
enabled: true@Service
public class InventoryService {
@Observed(name = "inventory.check", contextualName = "checkStock")
public StockLevel checkStock(String productId) {
// Запит до бази даних
return new StockLevel(productId, 42);
}
@NewSpan("inventory.reserve") // Створює дочірній спан під поточним трейсом
public ReservationResult reserveStock(String productId, int quantity) {
// Оновлення інвентарю
return new ReservationResult(true, "RES-" + System.currentTimeMillis());
}
}@Observed створює як метрику (таймер), так і спан. @NewSpan створює лише спан, корисно коли операція вже має метрики в іншому місці. Обидві анотації автоматично обробляють запис винятків та статус спана.
Автоматично інструментовані компоненти в Spring Boot 3.4
Spring Boot 3.4 автоматично інструментує кілька компонентів без змін у коді:
| Компонент | Назва спостереження | Що захоплює |
|---|---|---|
| Spring MVC | http.server.requests | Шлях запиту, метод, статус, виняток |
| WebClient | http.client.requests | Вихідні HTTP-виклики |
| RestClient | http.client.requests | Вихідні HTTP-виклики (Spring 6.1+) |
| Spring Kafka | spring.kafka.listener | Група споживачів, топік, партиція |
| Spring Data JPA | spring.data.repository | Метод репозиторію, час запиту |
| Scheduled Tasks | spring.scheduling | Назва завдання, час виконання |
Документація Spring Boot Actuator перелічує всі автоматично інструментовані компоненти. Сторонні бібліотеки, такі як Datasource Micrometer, додають трасування JDBC-запитів.
Фільтрація спостережень для зменшення шуму
Перевірки здоров'я, readiness probes та статичні ресурси генерують шум у трейсах. Їх можна відфільтрувати за допомогою предикатів:
@Configuration
public class ObservationFilterConfig {
@Bean
public ObservationPredicate noHealthChecks() {
return (name, context) -> !name.equals("http.server.requests")
|| !isHealthEndpoint(context);
}
private boolean isHealthEndpoint(Observation.Context context) {
if (context instanceof ServerRequestObservationContext http) {
String path = http.getCarrier().getRequestURI();
return path.startsWith("/actuator/health") || path.startsWith("/actuator/ready");
}
return false;
}
}Альтернативно можна вимкнути спостереження за назвою в конфігурації:
# application.yml
management:
observations:
enable:
spring.security: false # Вимкнути спостереження Spring Security
http.server.requests.actuator: false # Власна назва предикатаСемплювання зменшує відсоток трейсів, що збираються з усіх ендпоінтів. Фільтрація повністю видаляє певні ендпоінти. Використовуйте фільтрацію для ендпоінтів, що ніколи не надають діагностичної цінності (перевірки здоров'я, скрапінг метрик). Використовуйте семплювання для контролю витрат при збереженні репрезентативних даних.
Кореляція логів з ID трейсів
Spring Boot 3.4 автоматично додає ID трейса та спана до MDC (Mapped Diagnostic Context), коли активний Micrometer Tracing. Logback та Log4j2 можуть включати ці ID у вивід логів:
<!-- logback-spring.xml -->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - traceId=%X{traceId} spanId=%X{spanId} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>З цим патерном кожен рядок логу містить ID трейса. Пошук логів за ID трейса повертає всі повідомлення з одного запиту з усіх сервісів, корелюючи логи зі спанами в Jaeger або Tempo.
Поширені питання на співбесідах щодо спостережуваності Spring Boot
Інтерв'юери оцінюють як концептуальне розуміння, так і практичний досвід зі спостережуваністю. Ці питання часто з'являються на позиціях senior backend.
П: Яка різниця між Micrometer Tracing та OpenTelemetry?
Micrometer Tracing - це vendor-neutral API для розподіленого трасування, подібно до того, як Micrometer абстрагує метрики. OpenTelemetry - це конкретна реалізація та протокол. Spring Boot використовує Micrometer Tracing як API та з'єднує з OpenTelemetry для експорту через micrometer-tracing-bridge-otel. Це розшарування дозволяє застосункам змінювати бекенди без змін у коді.
П: Чому Spring рекомендує Observation API замість прямої інструментації OpenTelemetry?
Observation API надає єдину точку інструментації, що генерує як метрики, так і трейси. Прямі виклики OpenTelemetry створюють лише трейси. Використання Observation.observe() генерує метрику таймера та спан з одного коду, зменшуючи дублювання та забезпечуючи узгоджене іменування.
П: Як налагодити трейс, що показує розрив між спанами?
Розриви вказують на відсутню інструментацію або порушене поширення контексту. Перевірте, чи код використовує асинхронні операції без ContextPropagatingTaskDecorator. Переконайтеся, що HTTP-клієнти інструментовані (WebClient, RestClient або вручну обгорнутий RestTemplate). Для черг повідомлень підтвердіть, що заголовки трейсів поширюються через властивості повідомлень.
П: Що відбувається, якщо додати тег високої кардинальності до метрики?
Кожне унікальне значення тега створює новий часовий ряд. Тег ID користувача з мільйонами користувачів створює мільйони рядів, вичерпуючи пам'ять у Prometheus або інших TSDB-бекендах. Рішення - використовувати highCardinalityKeyValue() замість lowCardinalityKeyValue(), що додає тег лише до трейсів, де очікується висока кардинальність.
Побудова пайплайна розподіленого трасування з Docker Compose
Локальний стек спостережуваності допомагає валідувати інструментацію перед деплоєм у продакшен. Цей приклад використовує OpenTelemetry Collector та Jaeger:
# docker-compose.yml
services:
otel-collector:
image: otel/opentelemetry-collector-contrib:0.102.0
command: ["--config", "/etc/otel-collector-config.yml"]
volumes:
- ./otel-collector-config.yml:/etc/otel-collector-config.yml
ports:
- "4318:4318" # OTLP HTTP
- "4317:4317" # OTLP gRPC
jaeger:
image: jaegertracing/jaeger:2.3
ports:
- "16686:16686" # UI
environment:
- COLLECTOR_OTLP_ENABLED=true
app:
build: .
environment:
- MANAGEMENT_OTLP_TRACING_ENDPOINT=http://otel-collector:4318/v1/traces
depends_on:
- otel-collector# otel-collector-config.yml
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 1024
exporters:
otlp/jaeger:
endpoint: jaeger:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp/jaeger]Колектор отримує спани від застосунку Spring Boot та пересилає їх до Jaeger. Ця архітектура дозволяє додавати експортери (Tempo, Zipkin, хмарні бекенди) без зміни коду застосунку.
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Ключові висновки щодо спостережуваності Spring Boot
- Observation API об'єднує метрики та трасування: один виклик
Observation.observe()створює як метрику таймера, так і спан, усуваючи подвійну інструментацію. - Додавання
micrometer-tracing-bridge-otelтаopentelemetry-exporter-otlpвмикає експорт OTLP. Spring Boot 3.4 автоматично налаштовує HTTP-експортер з ендпоінтом зmanagement.otlp.tracing.endpoint. - Використовуйте
lowCardinalityKeyValue()для вимірів, що з'являються в метриках (обмежені значення). ВикористовуйтеhighCardinalityKeyValue()для даних лише в трейсах (ID користувачів, ID запитів). - Увімкніть поширення контексту для асинхронного коду за допомогою
spring.task.execution.propagate-context=trueта обгортайте власні executor'и вContextPropagatingTaskDecorator. - Фільтрація шумних ендпоінтів, таких як
/actuator/health, за допомогою бінівObservationPredicateзберігає трейси зосередженими на бізнес-операціях. - Патерни логів повинні включати
%X{traceId}для кореляції рядків логів з розподіленими трейсами у вашому бекенді спостережуваності. - Питання на співбесідах щодо спостережуваності зосереджуються на кардинальності, помилках поширення контексту та різниці між Observation API та прямим використанням OpenTelemetry.
Чи знайдеш ти помилку в Spring Boot?
Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Автор:
Anthony Fillion-MailletЗасновник SharpSkill
Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.
Оновлено 19 вересня 2026 р.
Теги
Поділитися
Пов'язані статті

Spring Boot Actuator: Продакшн-Моніторинг із Micrometer та Prometheus
Повний посібник зі Spring Boot Actuator для продакшн-моніторингу. Налаштування Micrometer, метрики Prometheus, кастомні ендпоінти й алерти.

Spring Boot YAML vs Properties: Порівняння Конфігурації та Питання для Співбесіди 2026
Детальне порівняння форматів конфігурації YAML та Properties у Spring Boot. Аналіз синтаксису, керування профілями, структур даних та найпоширеніших питань на співбесідах.

Структуроване логування Spring Boot 2026: JSON-логи для production з Logback та OpenTelemetry
Повний посібник зі структурованого логування Spring Boot 4.x. Нативна підтримка JSON, starter OpenTelemetry, MDC tracing та інтеграція з ELK Stack для спостережуваності у production.