1. Wprowadzenie
W tym module nauczysz się tworzyć za pomocą gRPC klienta i serwer, które będą stanowić podstawę aplikacji do wyznaczania tras napisanej w języku Java.
Po ukończeniu tego samouczka będziesz mieć prostą aplikację gRPC HelloWorld z instrumentacją za pomocą wtyczki gRPC OpenTelemetry i będziesz w stanie wyświetlać wyeksportowane wskaźniki obserwacji w usłudze Prometheus.
Czego się nauczysz
- Jak skonfigurować wtyczkę OpenTelemetry dla istniejącej aplikacji gRPC w Javie
- Uruchamianie lokalnej instancji Prometheus
- Eksportowanie wskaźników do usługi Prometheus
- Wyświetlanie danych z panelu Prometheus
2. Zanim zaczniesz
Czego potrzebujesz
gitcurlJDKw wersji 8 lub nowszej
Zainstaluj wymagania wstępne:
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl
Pobierz kod
Aby ułatwić Ci naukę, w tym ćwiczeniu z programowania znajdziesz gotowy szkielet kodu źródłowego, który pomoże Ci zacząć. Z podanych niżej instrukcji dowiesz się, jak zintegrować wtyczkę gRPC OpenTelemetry z aplikacją.
Kod źródłowy szkieletu tego ćwiczenia z programowania 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 z ćwiczeniami z grpc i przejdź do folderu grpc-java-opentelemetry:
git clone 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 codelabem i rozpakować go ręcznie.
3. Rejestrowanie wtyczki OpenTelemetry
Aby dodać wtyczkę gRPC OpenTelemetry, potrzebujemy aplikacji gRPC. W tych ćwiczeniach z programowania użyjemy prostego klienta i serwera gRPC HelloWorld, które wyposażymy w wtyczkę gRPC OpenTelemetry.
Najpierw zarejestruj w kliencie wtyczkę OpenTelemetry skonfigurowaną z eksporterem Prometheus. Otwórz plik codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryClient.java w ulubionym edytorze, a następnie zmodyfikuj funkcję main, aby dodać kod do skonfigurowania interfejsu gRPC Java OpenTelemetry API.
Konfigurowanie instrumentacji po stronie klienta
Tworzenie eksportera Prometheus
Utwórz serwer PrometheusHttpServer, aby przekonwertować wskaźniki OpenTelemetry na format Prometheus i udostępnić je za pomocą serwera HttpServer. Poniższy fragment kodu tworzy nowy eksport Prometheus.
// 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 obiekt prometheusExporter jako MetricReader, aby odczytywać dane z obiektu SdkMeterProvider. Do konfigurowania ustawień danych służy klasa SdkMeterProvider.
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(prometheusExporter)
.build();
Utwórz instancję OpenTelemetrySdk z utworzonym powyżej elementem sdkMeterProvider na potrzeby implementacji pakietu SDK OpenTelemetry.
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
Tworzenie instancji GrpcOpenTelemetry
Za pomocą interfejsu API GrpcOpenTelemetry ustaw pakiet OpenTelemetry SDK, który korzysta z eksportu danych Prometheus Metric.
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.
Wyłączanie pakietu OpenTelemetry SDK
Zamykanie musi odbywać się w ramach ShutDownHook. openTelemetrySdk.close() zamyka pakiet SDK i wywołuje też zamknięcie w przypadku 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, aby zainicjować GrpcOpenTelemetry.
Tworzenie eksportera Prometheus
Ten moduł może być uruchamiany na tym samym komputerze, dlatego używamy innego portu do hostowania danych po stronie serwera gRPC, aby uniknąć konfliktów portów podczas tworzenia serwera 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();
Wyłączanie pakietu OpenTelemetry SDK
Po zamknięciu kanału gRPC. Wywołanie openTelemetrySdk.close() zamyka pakiet SDK i wywołuje też zamknięcie w przypadku 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 na serwerze zobaczysz 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
Prawidłowe 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ą Prometheus. 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 miał 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
Skonfigurujemy tu instancję usługi Prometheus, która będzie pobierać dane z przykładowego klienta i serwera gRPC eksportujących dane za pomocą usługi Prometheus.
Pobierz najnowszą wersję Prometheusa na swoją platformę, a następnie ją rozpakuj i uruchom:
tar xvfz prometheus-*.tar.gz
cd prometheus-*
Utwórz plik konfiguracji usługi Prometheus o tej treści:
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 z procesów po stronie klienta i serwera w samouczku, aby były pobierane co 5 sekund.
Aby wyświetlić dane, otwórz adres 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ą opóźnienia próby z 1-minutowym oknem czasowym do obliczania kwantyla.
Częstotliwość zapytań –
increase(grpc_client_attempt_duration_seconds_bucket[1m])
6. (Opcjonalnie) Ćwiczenie dla użytkownika
Na panelach Prometheusa zauważysz, że liczba zapytań na sekundę jest niska. Sprawdź, czy w przykładzie kodu możesz znaleźć podejrzany kod, który ogranicza liczbę zapytań na sekundę.
W przypadku entuzjastów kod klienta ogranicza się do posiadania tylko 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).