1. はじめに
この Codelab では、gRPC を使用して、Java で記述されたルート マッピング アプリケーションの基盤となるクライアントとサーバーを作成します。
このチュートリアルを完了すると、gRPC OpenTelemetry プラグインで計測されたシンプルな gRPC HelloWorld アプリケーションが作成され、エクスポートされたオブザーバビリティ指標を Prometheus で確認できるようになります。
学習内容
- 既存の gRPC Java アプリケーションに OpenTelemetry プラグインを設定する方法
- ローカル Prometheus インスタンスの実行
- Prometheus への指標のエクスポート
- Prometheus ダッシュボードから指標を表示する
2. 始める前に
必要なもの
gitcurlJDKv8 以降
次コマンドで前提条件をインストールします。
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl
コードを取得する
学習を効率化するため、この Codelab では、すぐに始められるように、あらかじめ作成されたソースコード スキャフォールドが用意されています。次の手順では、アプリケーションで gRPC OpenTelemetry プラグインを計測する方法について説明します。
この Codelab のスキャフォールディングのソースコードは、こちらの GitHub のディレクトリにあります。コードを自分で実装しない場合は、completed ディレクトリで完成したソースコードを利用できます。
まず、grpc codelab リポジトリのクローンを作成し、grpc-java-opentelemetry フォルダに移動します。
git clone https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-java-opentelemetry/
または、Codelab ディレクトリのみを含む .zip ファイルをダウンロードして、手動で解凍することもできます。
3. OpenTelemetry プラグインを登録する
gRPC OpenTelemetry プラグインを追加するには、gRPC アプリケーションが必要です。この Codelab では、gRPC OpenTelemetry プラグインでインストルメンテーションするシンプルな gRPC HelloWorld クライアントとサーバーを使用します。
まず、クライアントで Prometheus エクスポータで構成された OpenTelemetry プラグインを登録します。任意のエディタで codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryClient.java を開き、main を変更して gRPC Java OpenTelemetry API を設定するコードを追加します。
クライアントで計測を設定する
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();
上記で作成した sdkMeterProvider を使用して、OpenTelemetry の SDK 実装用の OpenTelemetrySdk のインスタンスを作成します。
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
GrpcOpenTelemetry インスタンスを作成する
GrpcOpenTelemetry API を使用して、Prometheus 指標エクスポータを使用する OpenTelemetry SDK を設定します。
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
GrpcOpenTelemetry インスタンスが registerGlobal を使用してグローバルに登録されると、その後作成されるすべての gRPC クライアントとサーバーが OpenTelemetry で計測されます。
OpenTelemetry Sdk をシャットダウンする
シャットダウンは ShutDownHook 内で行う必要があります。openTelemetrySdk.close() は SDK をシャットダウンし、SdkMeterProvider でシャットダウンも呼び出します。
サーバーで計測を設定する
同様に、GrpcOpenTelemetry をサーバーにも追加しましょう。codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryServer.java を開き、GrpcOpenTelemetry を初期化するコードを追加します。
Prometheus エクスポータを作成する
この Codelab は同じマシンから実行される可能性があるため、PrometheusHttpServer の作成時にポートの競合を回避するために、gRPC サーバーサイド指標をホストする別のポートを使用しています。
// 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();
OpenTelemetry SDK を使用して GrpcOpenTelemetry を初期化する
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 がシャットダウンされ、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
これにより、クライアントとサーバーの Codelab プロセスから 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 を 1 つだけにするように制限されています。これを変更して、クライアントが前の RPC の完了を待たずに、より多くの RPC を送信するようにできます。(この解決策は提供されていません)。