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 -b v1 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 エクスポータを作成します。
// 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();
OpenTelemetry の SDK 実装用に、上記で作成した sdkMeterProvider を使用して OpenTelemetrySdk のインスタンスを作成します。
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
GrpcOpenTelemetry インスタンスを作成する
GrpcOpenTelemetry API を使用して、Prometheus Metric エクスポータを使用する OpenTelemetry SDK を設定します。
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
registerGlobal を使用して GrpcOpenTelemetry インスタンスがグローバルに登録されると、以降に作成されるすべての 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
Prometheus を使用して指標をエクスポートするように gRPC OpenTelemetry プラグインを設定しました。これらの指標は、サーバーの場合は 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 を送信できます。(このソリューションは提供されていません)。