Настройка базового плагина OpenTelemetry в gRPC Java

1. Введение

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

К концу руководства у вас будет простое приложение gRPC HelloWorld, оснащенное плагином gRPC OpenTelemetry, и вы сможете увидеть экспортированные метрики наблюдаемости в Prometheus.

Чему вы научитесь

  • Как настроить плагин OpenTelemetry для существующего приложения gRPC Java
  • Запуск локального экземпляра Prometheus
  • Экспорт метрик в Prometheus
  • Просмотр показателей на панели инструментов Prometheus

2. Прежде чем начать

Что вам понадобится

  • git
  • curl
  • JDK v8 или выше

Установите необходимые компоненты:

sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl

Получить код

Для упрощения обучения эта практическая работа предлагает готовый исходный код, который поможет вам начать работу. Следующие шаги помогут вам настроить плагин gRPC OpenTelemetry в приложении.

grpc-codelabs

Исходный код scaffold для этой лабораторной работы доступен в этом каталоге GitHub. Если вы предпочитаете не реализовывать код самостоятельно, готовый исходный код доступен в каталоге Completed .

Сначала клонируйте репозиторий grpc codelab и перейдите в папку grpc-java-opentelemetry:

git clone https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-java-opentelemetry/

Кроме того, вы можете загрузить .zip-файл, содержащий только каталог codelab, и вручную распаковать его.

3. Зарегистрируйте плагин OpenTelemetry.

Для добавления плагина gRPC OpenTelemetry нам понадобится приложение gRPC. В этой лабораторной работе мы будем использовать простой клиент и сервер gRPC HelloWorld, которые будем оснащать плагином gRPC OpenTelemetry.

Первый шаг — зарегистрировать плагин OpenTelemetry, настроенный с помощью экспортера Prometheus, в клиенте. Откройте codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryClient.java в вашем любимом редакторе. Затем измените файл main, добавив код для настройки API gRPC Java OpenTelemetry.

Настройка инструментария на клиенте

Создать экспортер Prometheus

Создайте PrometheusHttpServer для преобразования метрик OpenTelemetry в формат Prometheus и предоставления их через HttpServer. Следующий фрагмент кода создаёт новый Prometheus Exporter .

// Default prometheus port i.e `prometheusPort` has been initialized to 9465
 
PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
        .setPort(prometheusPort)         
        .build();

Создать экземпляр OpenTelemetry SDK

Зарегистрируйте выше созданный prometheusExporter как MetricReader для чтения метрик из SdkMeterProvider . SdkMeterProvider используется для настройки параметров метрик.

SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
        .registerMetricReader(prometheusExporter)
        .build();

Создайте экземпляр OpenTelemetrySdk с созданным выше sdkMeterProvider для реализации SDK OpenTelemetry .

OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
        .setMeterProvider(sdkMeterProvider)
        .build();

Создать экземпляр GrpcOpenTelemetry

Используя API GrpcOpenTelemetry, настройте OpenTelemetry SDK, который использует экспортер Prometheus Metric.

GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
        .sdk(openTelemetrySdk)
        .build();

// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();

После глобальной регистрации экземпляра GrpcOpenTelemetry с помощью registerGlobal все впоследствии созданные клиенты и серверы gRPC будут оснащены OpenTelemetry.

Выключение OpenTelemetry SDK

Завершение работы должно происходить внутри ShutDownHook. openTelemetrySdk.close() завершает работу SDK, а также вызывает метод shutdown в SdkMeterProvider.

Настройка инструментария на сервере

Аналогично добавим GrpcOpenTelemetry на сервер. Откройте codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryServer.java и добавьте код для инициализации GrpcOpenTelemetry.

Создать экспортер Prometheus

Поскольку эта лабораторная работа может запускаться на той же машине, мы используем другой порт для размещения метрик на стороне сервера gRPC, чтобы избежать конфликтов портов при создании PrometheusHttpServer.

// Default prometheus port i.e `prometheusPort` has been set to 9464

PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
        .setPort(prometheusPort)
        .build();

Создать экземпляр OpenTelemetry SDK

SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
        .registerMetricReader(prometheusExporter)
        .build();

Инициализируйте GrpcOpenTelemetry с помощью OpenTelemetry SDK

OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
        .setMeterProvider(sdkMeterProvider)
        .build();

Создать экземпляр GrpcOpenTelemetry

GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
        .sdk(openTelemetrySdk)
        .build();
    // Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();

Выключение OpenTelemetry SDK

После завершения работы канала gRPC вызов openTelemetrySdk.close() завершает работу SDK, а также вызывает метод shutdown в SdkMeterProvider.

4. Запуск примера и просмотр показателей

Чтобы запустить сервер, выполните -

cd start_here
../gradlew installDist
./build/install/start_here/bin/opentelemetry-server

При успешной настройке вы увидите следующий вывод для сервера:

[date and time] io.grpc.codelabs.opentelemetry.OpenTelemetryServer start
INFO: Server started, listening on 50051

Пока сервер работает, на другом терминале запустите клиент -

./build/install/start_here/bin/opentelemetry-client world

Успешный запуск будет выглядеть так:

[date and time]io.grpc.codelabs.opentelemetry.OpenTelemetryClient greet
INFO: Greeting: Hello world 
[date and time] io.grpc.codelabs.opentelemetry.OpenTelemetryClient greet
INFO: Will try to greet world ...
[date and time]io.grpc.codelabs.opentelemetry.OpenTelemetryClient greet
INFO: Greeting: Hello world

Поскольку мы настроили плагин gRPC OpenTelemetry для экспорта метрик через Prometheus, эти метрики будут доступны по адресу localhost:9464 для сервера и localhost:9465 для клиента.

Чтобы увидеть показатели клиента -

curl localhost:9465/metrics

Результат будет иметь вид -

# HELP grpc_client_attempt_duration_seconds Time taken to complete a client call attempt
# TYPE grpc_client_attempt_duration_seconds histogram
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.002"} 0
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.003"} 2
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.004"} 14
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.005"} 29
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.1"} 33
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="+Inf"} 34
grpc_client_attempt_duration_seconds_count{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 34
grpc_client_attempt_duration_seconds_sum{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 0.46512665300000006
# HELP grpc_client_attempt_rcvd_total_compressed_message_size_bytes Compressed message bytes received per call attempt
# TYPE grpc_client_attempt_rcvd_total_compressed_message_size_bytes histogram
grpc_client_attempt_rcvd_total_compressed_message_size_bytes_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.0"} 0
grpc_client_attempt_rcvd_total_compressed_message_size_bytes_sum{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 442.0
# HELP grpc_client_attempt_sent_total_compressed_message_size_bytes Compressed message bytes sent per client call attempt
# TYPE grpc_client_attempt_sent_total_compressed_message_size_bytes histogram
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.0"} 0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="1024.0"} 34
grpc_client_attempt_sent_total_compressed_message_size_bytes_sum{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 238.0
# HELP grpc_client_attempt_started_total Number of client call attempts started
# TYPE grpc_client_attempt_started_total counter
grpc_client_attempt_started_total{grpc_method="helloworld.Greeter/SayHello",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 34.0
# HELP grpc_client_call_duration_seconds Time taken by gRPC to complete an RPC from application's perspective
# TYPE grpc_client_call_duration_seconds histogram
grpc_client_call_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.0"} 0
grpc_client_call_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.003"} 2
grpc_client_call_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="+Inf"} 34
grpc_client_call_duration_seconds_count{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 34
grpc_client_call_duration_seconds_sum{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 0.512708707
# TYPE target_info gauge
target_info{service_name="unknown_service:java",telemetry_sdk_language="java",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="1.40.0"} 1

Аналогично для показателей на стороне сервера -

curl localhost:9464/metrics

5. Просмотр метрик на Prometheus

Здесь мы настроим экземпляр Prometheus, который будет собирать данные с нашего клиента и сервера gRPC, которые экспортируют метрики с помощью Prometheus.

Загрузите последнюю версию Prometheus для вашей платформы, затем извлеките и запустите ее:

tar xvfz prometheus-*.tar.gz
cd prometheus-*

Создайте файл конфигурации Prometheus со следующим содержимым:

cat > grpc_otel_java_prometheus.yml <<EOF
scrape_configs:
  - job_name: "prometheus"
    scrape_interval: 5s
    static_configs:
      - targets: ["localhost:9090"]
  - job_name: "grpc-otel-java"
    scrape_interval: 5s
    static_configs:
      - targets: ["localhost:9464", "localhost:9465"]
EOF

Запустите Prometheus с новой конфигурацией -

./prometheus --config.file=grpc_otel_java_prometheus.yml

Это позволит настроить считывание показателей из клиентских и серверных процессов кодовой лаборатории каждые 5 секунд.

Чтобы просмотреть метрики, перейдите по адресу http://localhost:9090/graph . Например, запрос:

histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))

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

Скорость запросов -

increase(grpc_client_attempt_duration_seconds_bucket[1m])

6. (Необязательно) Упражнение для пользователя

На панелях мониторинга Prometheus вы заметите низкий показатель QPS. Попробуйте найти в примере какой-нибудь подозрительный код, который ограничивает QPS.

Для энтузиастов: клиентский код ограничивается только одним ожидающим RPC-запросом в любой момент времени. Это можно изменить, чтобы клиент отправлял больше RPC-запросов, не дожидаясь завершения предыдущих. (Решение этой проблемы пока не предоставлено.)