paint-brush
Трассировка OpenTelemetry в Spring Boot: выбор между Java Agent и Micrometer дляк@nfrankel
193 чтения

Трассировка OpenTelemetry в Spring Boot: выбор между Java Agent и Micrometer для

к Nicolas Fränkel8m2024/08/11
Read on Terminal Reader

Слишком долго; Читать

В этой статье сравниваются решения трассировки OpenTelemetry в приложении Spring Boot с использованием Java Agent v1, Java Agent v2 и Micrometer Tracing. В ней подчеркиваются различия в конфигурации, функциональности и возможностях трассировки, а также предлагаются сведения об эффективности и применении каждого подхода для обеспечения наблюдаемости.
featured image - Трассировка OpenTelemetry в Spring Boot: выбор между Java Agent и Micrometer для
Nicolas Fränkel HackerNoon profile picture

В моей демонстрации OpenTelemetry Tracing есть два компонента Spring Boot. Один использует агент Java, и я заметил другое поведение, когда недавно обновил его с v1.x до v2.x. В другом я использую Micrometer Tracing, потому что я компилирую в GraalVM native, а он не может обрабатывать агенты Java.



В этой статье я хочу сравнить эти три подхода: Java agent v1, Java agent v2 и Micrometer Tracing.

Базовое приложение и его инфраструктура

Я буду использовать то же самое базовое приложение: простое приложение Spring Boot, написанное на Kotlin. Оно предлагает одну конечную точку.


  • Функция за пределами конечной точки называется entry()
  • Он вызывает другую функцию с именем intermediate()
  • Последний использует экземпляр WebClient , замену RestTemplate , для вызова указанной выше конечной точки.
  • Чтобы избежать бесконечного цикла, я передаю пользовательский заголовок запроса: если функция entry() находит его, она не продолжает работу.


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


Это преобразуется в следующий код:


 @SpringBootApplication class Agent1xApplication @RestController class MicrometerController { private val logger = LoggerFactory.getLogger(MicrometerController::class.java) @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") if (done == null) intermediate() } fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() } }


Для каждой настройки я проверю два этапа: основной этап с включенным OpenTelemetry и этап настройки для создания дополнительных внутренних диапазонов.

Микрометрическая трассировка

Micrometer Tracing происходит от Micrometer , «независимого от поставщика фасада наблюдения за приложениями».


Micrometer Tracing предоставляет простой фасад для самых популярных библиотек трассировки, позволяя вам инструментировать код вашего приложения на основе JVM без привязки к поставщику. Он разработан так, чтобы добавлять мало или вообще не добавлять накладных расходов к вашей деятельности по сбору трассировки, при этом максимально увеличивая переносимость ваших усилий по трассировке.


-- Сайт трассировки микрометра


Чтобы начать работу с Micrometer Tracing, необходимо добавить несколько зависимостей:


  • Привод пружинного ботинка, org.springframework.boot:spring-boot-starter-actuator
  • Микрометрическая трассировка, io.micrometer:micrometer-tracing
  • "Мост" к API бэкэнда трассировки цели. В моем случае это OpenTelemetry, отсюда io.micrometer:micrometer-tracing-bridge-otel
  • Конкретный экспортер в бэкэнд, io.opentelemetry:opentelemetry-exporter-otlp


Нам не нужен BOM, поскольку версии уже определены в родительском элементе Spring Boot.


Но нам нужны два параметра конфигурации времени выполнения: куда следует отправлять трассировки и каково имя компонента. Они управляются переменными MANAGEMENT_OTLP_TRACING_ENDPOINT и SPRING_APPLICATION_NAME .


 services: jaeger: image: jaegertracing/all-in-one:1.55 environment: - COLLECTOR_OTLP_ENABLED=true #1 ports: - "16686:16686" micrometer-tracing: build: dockerfile: Dockerfile-micrometer environment: MANAGEMENT_OTLP_TRACING_ENDPOINT: http://jaeger:4318/v1/traces #2 SPRING_APPLICATION_NAME: micrometer-tracing #3
  1. Включить сборщик OpenTelemetry для Jaeger
  2. Полный URL-адрес конечной точки Jaeger OpenTelemetry gRPC
  3. Установите имя службы OpenTelemetry


Вот результат:

Микрометрические следы на Jaeger без настройки


Без какой-либо настройки Micrometer создает интервалы при получении и отправке HTTP-запросов.


Фреймворк должен внедрить магию в RestClient для отправки. Для этого мы должны позволить первому инстанцировать второй:


 @SpringBootApplication class MicrometerTracingApplication { @Bean fun restClient(builder: RestClient.Builder) = builder.baseUrl("http://localhost:8080/done").build() }


Мы можем создавать ручные интервалы несколькими способами, один из которых — через сам API OpenTelemetry. Однако для настройки требуется много шаблонного кода. Самый простой способ — это API наблюдения Micrometer. Его главное преимущество — использование единого API, который управляет как метриками , так и трассировками .


Диаграмма классов API наблюдения

Вот обновленный код:


 class MicrometerController( private val restClient: RestClient, private val registry: ObservationRegistry ) { @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") val observation = Observation.start("entry", registry) if (done == null) intermediate(observation) observation.stop() } fun intermediate(parent: Observation) { logger.info("intermediate") val observation = Observation.createNotStarted("intermediate", registry) .parentObservation(parent) .start() restClient.get() .header("X-done", "true") .retrieve() .toBodilessEntity() observation.stop() } }


Добавленные вызовы наблюдения отражаются на сгенерированных трассах:


Микрометрические следы на Jaeger с API наблюдения

Агент OpenTelemetry v1

Альтернативой Micrometer Tracing является универсальный OpenTelemetry Java Agent . Его главное преимущество в том, что он не влияет ни на код, ни на разработчиков; агент — это чисто runtime-область.


 java -javaagent:opentelemetry-javaagent.jar agent-one-1.0-SNAPSHOT.jar


Агент придерживается конфигурации OpenTelemetry с переменными среды:


 services: agent-1x: build: dockerfile: Dockerfile-agent1 environment: OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1 OTEL_RESOURCE_ATTRIBUTES: service.name=agent-1x #2 OTEL_METRICS_EXPORTER: none #3 OTEL_LOGS_EXPORTER: none #4 ports: - "8081:8080"
  1. Установите протокол, домен и порт. Библиотека добавляет /v1/traces
  2. Установите имя службы OpenTelemetry
  3. Не экспортировать ни метрики, ни журналы


Без дополнительной настройки получаем следующие трассировки:


Agent v1 трассирует на Jaeger без настройки


Агент автоматически отслеживает запросы, как полученные, так и отправленные, а также функции, отмеченные аннотациями, связанными со Spring . Трассировки правильно вложены друг в друга в соответствии со стеком вызовов. Чтобы трассировать дополнительные функции, нам нужно добавить зависимость в нашу кодовую базу, io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations . Теперь мы можем аннотировать ранее неотслеживаемые функции с помощью аннотации @WithSpan .

Диаграмма классов @WithSpan


Часть value() управляет меткой трассировки, а kind транслируется как атрибут span.kind . Если значение установлено в пустую строку, что является значением по умолчанию, оно выводит имя функции. Для моих целей значения по умолчанию вполне подходят.


 @WithSpan fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() }


Это дает ожидаемый новый intermediate() след:

Следы Agent v1 на Jaeger с аннотациями

Агент OpenTelemetry v2

OpenTelemetry выпустила новую основную версию агента в январе этого года. Я обновил свою демоверсию с ее помощью; теперь трассировки создаются только тогда, когда приложение получает и отправляет запросы.

Agent v2 трассирует на Jaeger без настройки


Как и в предыдущей версии, мы можем добавлять трассировки с помощью аннотации @WithSpan . Единственное отличие в том, что мы также должны аннотировать функцию entry() . По умолчанию она не трассируется.

Следы Agent v2 на Jaeger с аннотациями


Обсуждение

Spring стал успешным по двум причинам: он упростил сложные решения, т. е . EJBs 2, и предоставил уровень абстракции по сравнению с конкурирующими библиотеками. Micrometer Tracing начинался как уровень абстракции по сравнению с Zipkin и Jaeger, и это имело смысл. Этот аргумент становится спорным, поскольку OpenTelemetry поддерживается большинством библиотек на всех языках программирования и сборщиками трассировок. API наблюдения по-прежнему является значительным преимуществом Micrometer Tracing, поскольку он использует единый API по сравнению с метриками и трассировками.


На стороне Java Agent конфигурация OpenTelemetry одинакова для всех технологических стеков и библиотек - переменные окружения. Я был немного разочарован, когда обновился с v1 до v2, так как новый агент не поддерживает Spring: функции, аннотированные Spring, по умолчанию не трассируются.


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


Спасибо Джонатану Иванову за его помощь и отзыв .


Полный исходный код этой статьи можно найти на GitHub:

Чтобы пойти дальше:


Первоначально опубликовано в A Java Geek 3 августа 2024 г.