1. Introducción
En este codelab, usarás gRPC para crear un cliente y un servidor que formen la base de una aplicación de asignación de rutas escrita en Java.
Al final del instructivo, tendrás una aplicación simple de gRPC HelloWorld instrumentada con el complemento de OpenTelemetry de gRPC y podrás ver las métricas de observabilidad exportadas en Prometheus.
Qué aprenderás
- Cómo configurar el complemento de OpenTelemetry para una aplicación de gRPC Java existente
- Cómo ejecutar una instancia local de Prometheus
- Cómo exportar métricas a Prometheus
- Cómo ver métricas desde el panel de Prometheus
2. Antes de comenzar
Requisitos
gitcurlJDKv8 o versiones posteriores
Instala los requisitos previos:
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl
Obtén el código
Para optimizar tu aprendizaje, este codelab ofrece un código fuente precompilado para ayudarte a comenzar. En los siguientes pasos, se te guiará para instrumentar el complemento de OpenTelemetry de gRPC en una aplicación.
El código fuente de este codelab está disponible en este directorio de GitHub . Si prefieres no implementar el código por tu cuenta, el código fuente completo está disponible en el completed directorio.
Primero, clona el repositorio del codelab de gRPC y cambia el directorio a grpc-java-opentelemetry:
git clone -b v1 https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-java-opentelemetry/
Como alternativa, puedes descargar el archivo .zip que contiene solo el directorio del codelab y descomprimirlo de forma manual.
3. Registra el complemento de OpenTelemetry
Necesitamos una aplicación de gRPC para agregar el complemento de OpenTelemetry de gRPC. En este codelab, usaremos un cliente y un servidor simples de gRPC HelloWorld que instrumentaremos con el complemento de OpenTelemetry de gRPC.
El primer paso es registrar el complemento de OpenTelemetry configurado con un exportador de Prometheus en el cliente. Abre codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryClient.java con tu editor favorito y, luego, modifica main para agregar código para configurar la API de OpenTelemetry de gRPC Java.
Configura la instrumentación en el cliente
Crea el exportador de Prometheus
Crea un PrometheusHttpServer para convertir las métricas de OpenTelemetry al formato de Prometheus y exponerlas a través de un HttpServer. El siguiente fragmento de código crea un nuevo exportador de Prometheus.
// Default prometheus port i.e `prometheusPort` has been initialized to 9465
PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
.setPort(prometheusPort)
.build();
Crea una instancia del SDK de OpenTelemetry
Registra el prometheusExporter creado anteriormente como MetricReader para leer métricas de un SdkMeterProvider. SdkMeterProvider se usa para configurar los parámetros de configuración de las métricas.
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(prometheusExporter)
.build();
Crea una instancia de OpenTelemetrySdk con el sdkMeterProvider creado anteriormente para la implementación del SDK de OpenTelemetry.
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
Crea una instancia de GrpcOpenTelemetry
Con la API de GrpcOpenTelemetry, configura el SDK de OpenTelemetry que usa el exportador de métricas de Prometheus.
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
Una vez que se registra una instancia de GrpcOpenTelemetry de forma global con registerGlobal, todos los clientes y servidores de gRPC creados posteriormente se instrumentarán con OpenTelemetry.
Cierra el SDK de OpenTelemetry
El cierre debe ocurrir dentro de ShutDownHook. openTelemetrySdk.close() cierra el SDK y también llama al cierre en SdkMeterProvider.
Configura la instrumentación en el servidor
Del mismo modo, agreguemos GrpcOpenTelemetry al servidor. Abre codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryServer.java y agrega código para inicializar GrpcOpenTelemetry.
Crea el exportador de Prometheus
Como este codelab se puede ejecutar desde la misma máquina, usamos un puerto diferente para alojar las métricas del servidor de gRPC para evitar conflictos de puertos mientras creamos PrometheusHttpServer.
// Default prometheus port i.e `prometheusPort` has been set to 9464
PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
.setPort(prometheusPort)
.build();
Crea una instancia del SDK de OpenTelemetry
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(prometheusExporter)
.build();
Inicializa GrpcOpenTelemetry con el SDK de OpenTelemetry
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
Crea una instancia de GrpcOpenTelemetry
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
Cierra el SDK de OpenTelemetry
Después de que se cierra el canal de gRPC. Llamar a openTelemetrySdk.close() cierra el SDK y también llama al cierre en SdkMeterProvider.
4. Ejecuta el ejemplo y visualiza las métricas
Para ejecutar el servidor, ejecuta lo siguiente:
cd start_here
../gradlew installDist
./build/install/start_here/bin/opentelemetry-server
Con una configuración correcta, verás el siguiente resultado para el servidor:
[date and time] io.grpc.codelabs.opentelemetry.OpenTelemetryServer start
INFO: Server started, listening on 50051
Mientras se ejecuta el servidor, en otra terminal, ejecuta el cliente:
./build/install/start_here/bin/opentelemetry-client world
Una ejecución correcta se verá de la siguiente manera:
[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
Como configuramos el complemento de OpenTelemetry de gRPC para exportar métricas con Prometheus, esas métricas estarán disponibles en localhost:9464 para el servidor y localhost:9465 para el cliente.
Para ver las métricas del cliente, haz lo siguiente:
curl localhost:9465/metrics
El resultado sería de la siguiente forma:
# 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
Del mismo modo, para las métricas del servidor, haz lo siguiente:
curl localhost:9464/metrics
5. Visualiza métricas en Prometheus
Aquí, configuraremos una instancia de Prometheus que recopilará nuestro cliente y servidor de ejemplo de gRPC que exportan métricas con Prometheus.
Descarga la versión más reciente de Prometheus para tu plataforma, luego extráela y ejecútala:
tar xvfz prometheus-*.tar.gz
cd prometheus-*
Crea un archivo de configuración de Prometheus con lo siguiente:
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
Inicia Prometheus con la nueva configuración:
./prometheus --config.file=grpc_otel_java_prometheus.yml
Esto configurará las métricas de los procesos del codelab del cliente y del servidor para que se recopilen cada 5 segundos.
Ve a http://localhost:9090/graph para ver las métricas. Por ejemplo, la consulta
histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))
mostrará un gráfico con la latencia de intento mediana con 1 minuto como el período para el cálculo de cuantiles.
Tasa de consultas:
increase(grpc_client_attempt_duration_seconds_bucket[1m])
6. Ejercicio (opcional) para el usuario
En los paneles de Prometheus, notarás que las QPS son bajas. Comprueba si puedes identificar algún código sospechoso en el ejemplo que limite las QPS.
Para los entusiastas, el código del cliente se limita a tener una sola RPC pendiente en un momento determinado. Esto se puede modificar para que el cliente envíe más RPC sin esperar a que se completen las anteriores. (No se proporcionó la solución para esto).