Konfigurowanie podstawowej wtyczki OpenTelemetry w gRPC Java

1. Wprowadzenie

W tym ćwiczeniu dowiesz się, jak za pomocą gRPC utworzyć klienta i serwer, które będą stanowić podstawę aplikacji do mapowania tras napisanej w Javie.

Po ukończeniu tego samouczka będziesz mieć prostą aplikację gRPC HelloWorld wyposażoną we wtyczkę gRPC OpenTelemetry i będziesz w stanie wyświetlać wyeksportowane dane dostrzegalności w Prometheusie.

Czego się nauczysz

  • Jak skonfigurować wtyczkę OpenTelemetry w istniejącej aplikacji gRPC Java
  • Uruchamianie lokalnej instancji Prometheusa
  • Eksportowanie danych do Prometheusa
  • Wyświetlanie danych z panelu Prometheusa

2. Zanim zaczniesz

Czego potrzebujesz

  • git
  • curl
  • JDK w wersji 8 lub nowszej

Zainstaluj wstępnie wymagane usługi:

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

Pobierz kod

W tym ćwiczeniu znajdziesz gotowy szkielet kodu źródłowego, który pomoże Ci zacząć i w ten sposób ułatwi Ci naukę. Z podanych niżej instrukcji dowiesz się, jak zintegrować wtyczkę gRPC OpenTelemetry z aplikacją.

grpc-codelabs

Kod źródłowy szkieletu tego ćwiczenia jest dostępny w tym katalogu na GitHubie. Jeśli nie chcesz samodzielnie implementować kodu, gotowy kod źródłowy znajdziesz w katalogu completed.

Najpierw sklonuj repozytorium ćwiczeń gRPC i przejdź do folderu grpc-java-opentelemetry:

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

Możesz też pobrać plik ZIP zawierający tylko katalog z ćwiczeniem i rozpakować go ręcznie.

3. Zarejestruj wtyczkę OpenTelemetry

Aby dodać wtyczkę gRPC OpenTelemetry, potrzebujemy aplikacji gRPC. W tym ćwiczeniu użyjemy prostego klienta i serwera gRPC HelloWorld, które wyposażymy we wtyczkę gRPC OpenTelemetry.

Najpierw zarejestruj w kliencie wtyczkę OpenTelemetry skonfigurowaną z eksporterem Prometheusa. Otwórz codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryClient.java w ulubionym edytorze, a następnie zmodyfikuj główny kod, aby dodać kod do skonfigurowania interfejsu gRPC Java OpenTelemetry API.

Konfigurowanie instrumentacji na kliencie

Tworzenie eksportera Prometheusa

Utwórz PrometheusHttpServer, aby przekonwertować dane OpenTelemetry na format Prometheus i udostępnić je za pomocą serwera HTTP. Poniższy fragment kodu tworzy nowy eksporter Prometheusa.

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

Tworzenie instancji pakietu OpenTelemetry SDK

Zarejestruj powyższy utworzony prometheusExporter jako MetricReader, aby odczytywać dane z SdkMeterProvider. SdkMeterProvider służy do konfigurowania ustawień danych.

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

Utwórz instancję OpenTelemetrySdk z utworzonym powyżej sdkMeterProvider na potrzeby implementacji pakietu SDK OpenTelemetry.

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

Tworzenie instancji GrpcOpenTelemetry

Za pomocą interfejsu GrpcOpenTelemetry API ustaw pakiet OpenTelemetry SDK, który używa eksportera danych Prometheus.

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

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

Gdy instancja GrpcOpenTelemetry zostanie zarejestrowana globalnie za pomocą registerGlobal, wszystkie utworzone później klienty i serwery gRPC będą instrumentowane za pomocą OpenTelemetry.

Zamykanie pakietu OpenTelemetry SDK

Wyłączenie musi nastąpić wewnątrz ShutDownHook. openTelemetrySdk.close() zamyka pakiet SDK i wywołuje też zamknięcie w SdkMeterProvider.

Konfigurowanie instrumentacji na serwerze

Podobnie dodajmy GrpcOpenTelemetry do serwera. Otwórz codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryServer.java i dodaj kod do zainicjowania GrpcOpenTelemetry.

Tworzenie eksportera Prometheusa

Ponieważ to ćwiczenie może być wykonywane na tym samym komputerze, używamy innego portu do hostowania danych po stronie serwera gRPC, aby uniknąć konfliktów portów podczas tworzenia PrometheusHttpServer.

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

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

Tworzenie instancji pakietu OpenTelemetry SDK

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

Inicjowanie GrpcOpenTelemetry za pomocą pakietu OpenTelemetry SDK

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

Tworzenie instancji GrpcOpenTelemetry

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

Zamykanie pakietu OpenTelemetry SDK

Po zamknięciu kanału gRPC. Wywołanie openTelemetrySdk.close() zamyka pakiet SDK i wywołuje też zamknięcie w SdkMeterProvider.

4. Uruchamianie przykładu i wyświetlanie danych

Aby uruchomić serwer, wpisz:

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

Po pomyślnej konfiguracji zobaczysz na serwerze te dane wyjściowe:

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

Gdy serwer działa, w innym terminalu uruchom klienta:

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

Pomyślne uruchomienie będzie wyglądać tak:

[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

Skonfigurowaliśmy wtyczkę gRPC OpenTelemetry do eksportowania wskaźników za pomocą Prometheusa. Te dane będą dostępne na serwerze localhost:9464 i na kliencie localhost:9465.

Aby wyświetlić dane klienta:

curl localhost:9465/metrics

Wynik będzie mieć postać:

# 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

Podobnie w przypadku danych po stronie serwera:

curl localhost:9464/metrics

5. Wyświetlanie danych w Prometheusie

W tym ćwiczeniu skonfigurujemy instancję Prometheusa, która będzie pobierać dane z naszego przykładowego klienta i serwera gRPC eksportujących dane za pomocą Prometheusa.

Pobierz najnowszą wersję Prometheusa na swoją platformę, a następnie rozpakuj ją i uruchom:

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

Utwórz plik konfiguracyjny Prometheusa z tymi ustawieniami:

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

Uruchom Prometheusa z nową konfiguracją:

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

Spowoduje to skonfigurowanie wskaźników klienta i serwera z procesów zainicjowanych w ćwiczeniu tak, aby były pobierane co 5 sekund.

Aby wyświetlić wartości wskaźników, otwórz stronę http://localhost:9090/graph. Na przykład zapytanie

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

wyświetli wykres z medianą czasu oczekiwania na próby z 1-minutowym oknem czasowym do obliczania kwantyla.

Częstotliwość zapytań:

increase(grpc_client_attempt_duration_seconds_bucket[1m])

6. (Opcjonalne) Ćwiczenie dla użytkownika

W panelach Prometheusa zauważysz, że ilość zapytań/s jest niska. Sprawdź, czy w przykładzie możesz znaleźć podejrzany kod, który ogranicza liczbę zapytań na sekundę.

Uwaga dla entuzjastów: kod klienta ogranicza się do jednego oczekującego wywołania RPC w danym momencie. Można to zmodyfikować tak, aby klient wysyłał więcej wywołań RPC bez czekania na zakończenie poprzednich. (Rozwiązanie tego problemu nie zostało podane).