1. はじめに
最終更新日: 2022 年 7 月 15 日
アプリケーションのオブザーバビリティ
オブザーバビリティと OpenTelemetry
オブザーバビリティは、システムの属性を記述するために使用される用語です。オブザーバビリティのあるシステムでは、チームがシステムのデバッグを積極的に行えます。このコンテキストでは、オブザーバビリティの 3 つの柱であるログ、指標、トレースは、システムがオブザーバビリティを獲得するための基本的な計測ツールです。
OpenTelemetry は、オブザーバビリティに必要なテレメトリー データ(ログ、指標、トレース)のインストルメンテーションとエクスポートを高速化する一連の仕様、ライブラリ、エージェントです。OpenTelemetry は、CNCF 傘下のオープン標準であり、コミュニティ主導のプロジェクトです。プロジェクトとそのエコシステムが提供するライブラリを利用することで、デベロッパーはベンダーに依存しない方法で、複数のアーキテクチャに対してアプリケーションを計測できます。
また、オブザーバビリティの 3 つの柱に加えて、継続的プロファイリングはオブザーバビリティのもう 1 つの重要なコンポーネントであり、業界でユーザーベースを拡大しています。Cloud Profiler は、その先駆けであり、アプリケーションのコールスタック内のパフォーマンス指標をドリルダウンするための簡単なインターフェースを提供します。
この Codelab はシリーズのパート 1 で、OpenTelemetry と Cloud Trace を使用してマイクロサービス内の分散トレースを計測可能にする方法について説明します。パート 2 では、Cloud Profiler による継続的なプロファイリングについて説明します。
分散トレース
ログ、指標、トレースのなかで、トレースはシステム内のプロセスの特定部分のレイテンシを示すテレメトリーです。特にマイクロサービスの時代において、分散トレースは分散システム全体のレイテンシのボトルネックを特定するための強力な手段です。
分散トレース分析では、トレースデータの可視化が、システム全体のレイテンシをひと目で把握するための鍵となります。分散トレースでは、複数の Span を含む Trace の形式で、システム エントリポイントへの単一のリクエストを処理する一連の呼び出しを処理します。
スパンは、分散システムで実行される個々の作業単位を表し、開始時間と終了時間を記録します。スパンは多くの場合、相互に階層関係があります。下の図では、小さなスパンはすべて大きな /messages スパンの子スパンで、1 つのトレースとして組み合わされ、システム内における作業のパスを示すことができます。
Google Cloud Trace は、分散トレース バックエンドのオプションの一つで、Google Cloud の他のプロダクトと適切に統合されています。
作成するアプリの概要
この Codelab では、Google Kubernetes Engine クラスタで実行される「Shakespeare アプリケーション」(Shakesapp)というサービスでトレース情報を計測します。Shakesapp のアーキテクチャは次のとおりです。
- Loadgen が HTTP でクライアントにクエリ文字列を送信する
- クライアントが gRPC でロードジェネレータからサーバーにクエリを渡す
- サーバーはクライアントからのクエリを受け取り、Google Cloud Storage からテキスト形式ですべてのシェイクスピア作品を取得し、クエリを含む行を検索して、クライアントに一致した行番号を返します。
リクエスト全体にトレース情報を計測します。その後、プロファイラ エージェントをサーバーに埋め込んで、ボトルネックを調査します。
学習内容
- Go プロジェクトで OpenTelemetry Trace ライブラリを使用する方法
- ライブラリを使用してスパンを作成する方法
- アプリ コンポーネント間でワイヤーを介してスパンコテキストを伝播する方法
- トレースデータを Cloud Trace に送信する方法
- Cloud Trace でトレースを分析する方法
この Codelab では、マイクロサービスを計測する方法について説明します。わかりやすくするために、この例では 3 つのコンポーネント(負荷生成ツール、クライアント、サーバー)のみを使用していますが、この Codelab で説明するプロセスは、より複雑で大規模なシステムにも適用できます。
必要なもの
- Go の基本的な知識
- Kubernetes の基礎知識
2. 設定と要件
セルフペース型の環境設定
Google アカウント(Gmail または Google Apps)をお持ちでない場合は、1 つ作成する必要があります。Google Cloud Platform のコンソール(console.cloud.google.com)にログインし、新しいプロジェクトを作成します。
すでにプロジェクトが存在する場合は、コンソールの左上にあるプロジェクト選択プルダウン メニューをクリックします。
表示されたダイアログで [NEW PROJECT] ボタンをクリックして、新しいプロジェクトを作成します。
まだプロジェクトが存在しない場合は、次のような最初のプロジェクトを作成するためのダイアログが表示されます。
続いて表示されるプロジェクト作成ダイアログでは、新しいプロジェクトの詳細を入力できます。
プロジェクト ID を忘れないようにしてください。プロジェクト ID は、すべての Google Cloud プロジェクトを通じて一意の名前にする必要があります(上記の名前はすでに使用されているため使用できません)。以降、この Codelab では PROJECT_ID と呼びます。
次に、Google Cloud リソースを使用し、Cloud Trace API を有効にするために、Developers Console で課金を有効にする必要があります。
この Codelab の操作をすべて行って、費用が生じたとしても、少額です。Google Cloud Trace、Google Kubernetes Engine、Google Artifact Registry の料金については、公式ドキュメントをご覧ください。
- Google Cloud のオペレーション スイートの料金 | オペレーション スイート
- 料金 | Kubernetes Engine ドキュメント
- Artifact Registry の料金 | Artifact Registry のドキュメント
Google Cloud Platform の新規ユーザーの皆さんには、$300 の無料トライアルをご利用いただけます。その場合は、この Codelab を完全に無料でご利用いただけます。
Google Cloud Shell の設定
Google Cloud と Google Cloud Trace はノートパソコンからリモートで操作できますが、この Codelab では、Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。
この Debian ベースの仮想マシンには、必要な開発ツールがすべて用意されています。仮想マシンは Google Cloud で稼働し、永続的なホーム ディレクトリが 5 GB 用意されているため、ネットワークのパフォーマンスと認証が大幅に向上しています。つまり、この Codelab で必要になるのはブラウザのみです(したがって Chromebook でも利用できます)。
Cloud Console から Cloud Shell を有効にするには、[Cloud Shell をアクティブにする] をクリックします(環境のプロビジョニングと接続に若干時間を要します)。
Cloud Shell に接続すると、すでに認証は完了しており、プロジェクトに各自の PROJECT_ID
が設定されていることがわかります。
gcloud auth list
コマンド出力
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
コマンド出力
[core] project = <PROJECT_ID>
なんらかの理由でプロジェクトが設定されていない場合は、次のコマンドを実行します。
gcloud config set project <PROJECT_ID>
PROJECT_ID
が見つからない場合は、設定手順で使用した ID を確認するか、Cloud コンソール ダッシュボードで確認します。
Cloud Shell では、デフォルトで環境変数もいくつか設定されます。これらの変数は、以降のコマンドを実行する際に有用なものです。
echo $GOOGLE_CLOUD_PROJECT
コマンド出力
<PROJECT_ID>
最後に、デフォルトのゾーンとプロジェクト構成を設定します。
gcloud config set compute/zone us-central1-f
さまざまなゾーンを選択できます。詳細については、リージョンとゾーンをご覧ください。
Go の言語設定
この Codelab では、すべてのソースコードに Go を使用します。Cloud Shell で次のコマンドを実行し、Go のバージョンが 1.17 以降であることを確認します。
go version
コマンド出力
go version go1.18.3 linux/amd64
Google Kubernetes クラスタを設定する
この Codelab では、Google Kubernetes Engine(GKE)でマイクロサービスのクラスタを実行します。この Codelab のプロセスは次のとおりです。
- ベースライン プロジェクトを Cloud Shell にダウンロードする
- コンテナにマイクロサービスをビルドする
- コンテナを Google Artifact Registry(GAR)にアップロードする
- コンテナを GKE にデプロイする
- トレース計測用にサービスのソースコードを変更する
- ステップ 2 に進みます
Kubernetes Engine を有効にする
まず、GKE で Shakesapp を実行する Kubernetes クラスタを設定するため、GKE を有効にする必要があります。[Kubernetes Engine] メニューに移動し、[有効にする] ボタンを押します。
これで、Kubernetes クラスタを作成する準備が整いました。
Kubernetes クラスタを作成する
Cloud Shell で次のコマンドを実行して、Kubernetes クラスタを作成します。Artifact Registry リポジトリの作成に使用するゾーン値がリージョン内にあることを確認してください。リポジトリ リージョンがゾーンをカバーしていない場合は、ゾーン値 us-central1-f
を変更します。
gcloud container clusters create otel-trace-codelab2 \ --zone us-central1-f \ --release-channel rapid \ --preemptible \ --enable-autoscaling \ --max-nodes 8 \ --no-enable-ip-alias \ --scopes cloud-platform
コマンド出力
Note: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s). Creating cluster otel-trace-codelab2 in us-central1-f... Cluster is being health-checked (master is healthy)...done. Created [https://container.googleapis.com/v1/projects/development-215403/zones/us-central1-f/clusters/otel-trace-codelab2]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab2?project=development-215403 kubeconfig entry generated for otel-trace-codelab2. NAME: otel-trace-codelab2 LOCATION: us-central1-f MASTER_VERSION: 1.23.6-gke.1501 MASTER_IP: 104.154.76.89 MACHINE_TYPE: e2-medium NODE_VERSION: 1.23.6-gke.1501 NUM_NODES: 3 STATUS: RUNNING
Artifact Registry と skaffold の設定
これで、デプロイする Kubernetes クラスタの準備が整いました。次に、コンテナを push してデプロイするための Container Registry を準備します。これらの手順では、Artifact Registry(GAR)を設定し、それを使用するために skaffold を設定する必要があります。
Artifact Registry の設定
[Artifact Registry] のメニューに移動し、[ENABLE] ボタンを押します。
しばらくすると、GAR のリポジトリ ブラウザが表示されます。[リポジトリを作成] ボタンをクリックし、リポジトリの名前を入力します。
この Codelab では、新しいリポジトリの名前を trace-codelab
にします。アーティファクトの形式は「Docker」で、ロケーション タイプは「リージョン」です。Google Compute Engine のデフォルト ゾーンに設定したリージョンに近いリージョンを選択します。たとえば、この例では上記の「us-central1-f」を選択したので、ここでは「us-central1(アイオワ)」を選択します。次に、[作成] ボタンをクリックします。
リポジトリ ブラウザに「trace-codelab」と表示されます。
後でこの画面に戻ってレジストリ パスを確認します。
Skaffold の設定
Skaffold は、Kubernetes で実行されるマイクロサービスの構築に便利なツールです。少数のコマンドを使用して、アプリケーションのコンテナのビルド、push、デプロイのワークフローを処理します。Skaffold はデフォルトで Docker Registry をコンテナ レジストリとして使用するため、コンテナを push するときに GAR を認識するように skaffold を構成する必要があります。
Cloud Shell をもう一度開き、skaffold がインストールされていることを確認します。(Cloud Shell はデフォルトで skaffold を環境にインストールします)。次のコマンドを実行して、skaffold のバージョンを確認します。
skaffold version
コマンド出力
v1.38.0
これで、skaffold が使用するデフォルトのリポジトリを登録できます。レジストリパスを取得するには、Artifact Registry ダッシュボードに移動し、前の手順で設定したリポジトリの名前をクリックします。
ページ上部にパンくずリストが表示されます。 アイコンをクリックして、レジストリ パスをクリップボードにコピーします。
コピーボタンをクリックすると、次のようなメッセージを含むダイアログがブラウザの下部に表示されます。
「us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab」をコピーしました
Cloud Shell に戻ります。ダッシュボードからコピーした値を指定して skaffold config set default-repo
コマンドを実行します。
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
コマンド出力
set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox
また、レジストリを Docker 構成に構成する必要があります。次のコマンドを実行します。
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
コマンド出力
{ "credHelpers": { "gcr.io": "gcloud", "us.gcr.io": "gcloud", "eu.gcr.io": "gcloud", "asia.gcr.io": "gcloud", "staging-k8s.gcr.io": "gcloud", "marketplace.gcr.io": "gcloud", "us-central1-docker.pkg.dev": "gcloud" } } Adding credentials for: us-central1-docker.pkg.dev
これで、次のステップに進んで GKE に Kubernetes コンテナを設定できます。
概要
この手順では、Codelab 環境を設定します。
- Cloud Shell を設定する
- コンテナ レジストリ用の Artifact Registry リポジトリを作成した
- コンテナ レジストリを使用するように Skaffold を設定する
- Codelab マイクロサービスが実行される Kubernetes クラスタを作成した
次のステップ
次のステップでは、マイクロサービスをビルドしてクラスタにプッシュしてデプロイします。
3. マイクロサービスをビルド、push、デプロイする
Codelab の資料をダウンロードする
前の手順で、この Codelab の前提条件をすべて設定しました。これで、これらの上にマイクロサービスの全体を実行する準備が整いました。Codelab の資料は GitHub でホストされているため、次の git コマンドを使用して Cloud Shell 環境にダウンロードします。
cd ~ git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git cd opentelemetry-trace-codelab-go
プロジェクトのディレクトリ構造は次のとおりです。
. ├── README.md ├── step0 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step1 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step2 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step3 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step4 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step5 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src └── step6 ├── manifests ├── proto ├── skaffold.yaml └── src
- manifests: Kubernetes マニフェスト ファイル
- proto: クライアントとサーバー間の通信用の proto 定義
- src: 各サービスのソースコードのディレクトリ
- skaffold.yaml: skaffold の構成ファイル
この Codelab では、step0
フォルダにあるソースコードを更新します。次の手順の答えについては、step[1-6]
フォルダのソースコードも参照してください。(パート 1 はステップ 0 ~ 4、パート 2 はステップ 5 ~ 6 を対象としています)。
skaffold コマンドを実行する
これで、作成した Kubernetes クラスタにコンテンツ全体をビルド、push、デプロイする準備が整いました。複数の手順が含まれているように思えますが、実際には skaffold がすべてを処理します。次のコマンドで試してみましょう。
cd step0 skaffold dev
コマンドを実行するとすぐに、docker build
のログ出力が表示され、レジストリに正常に push されたことを確認できます。
コマンド出力
... ---> Running in c39b3ea8692b ---> 90932a583ab6 Successfully built 90932a583ab6 Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1 The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice] cc8f5a05df4a: Preparing 5bf719419ee2: Preparing 2901929ad341: Preparing 88d9943798ba: Preparing b0fdf826a39a: Preparing 3c9c1e0b1647: Preparing f3427ce9393d: Preparing 14a1ca976738: Preparing f3427ce9393d: Waiting 14a1ca976738: Waiting 3c9c1e0b1647: Waiting b0fdf826a39a: Layer already exists 88d9943798ba: Layer already exists f3427ce9393d: Layer already exists 3c9c1e0b1647: Layer already exists 14a1ca976738: Layer already exists 2901929ad341: Pushed 5bf719419ee2: Pushed cc8f5a05df4a: Pushed step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001
すべてのサービス コンテナが push されると、Kubernetes Deployment が自動的に開始されます。
コマンド出力
sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997 Tags used in deployment: - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a Starting deploy... - deployment.apps/clientservice created - service/clientservice created - deployment.apps/loadgen created - deployment.apps/serverservice created - service/serverservice created
デプロイ後、各コンテナの stdout に実際のアプリケーション ログが出力されます。
コマンド出力
[client] 2022/07/14 06:33:15 {"match_count":3040} [loadgen] 2022/07/14 06:33:15 query 'love': matched 3040 [client] 2022/07/14 06:33:15 {"match_count":3040} [loadgen] 2022/07/14 06:33:15 query 'love': matched 3040 [client] 2022/07/14 06:33:16 {"match_count":3040} [loadgen] 2022/07/14 06:33:16 query 'love': matched 3040 [client] 2022/07/14 06:33:19 {"match_count":463} [loadgen] 2022/07/14 06:33:19 query 'tear': matched 463 [loadgen] 2022/07/14 06:33:20 query 'world': matched 728 [client] 2022/07/14 06:33:20 {"match_count":728} [client] 2022/07/14 06:33:22 {"match_count":463} [loadgen] 2022/07/14 06:33:22 query 'tear': matched 463
この時点では、サーバーからのメッセージを確認します。これで、OpenTelemetry を使用してアプリケーションを計測し、サービスの分散トレースを開始する準備が整いました。
サービスの計測を開始する前に、Ctrl+C でクラスタをシャットダウンしてください。
コマンド出力
... [client] 2022/07/14 06:34:57 {"match_count":1} [loadgen] 2022/07/14 06:34:57 query 'what's past is prologue': matched 1 ^CCleaning up... - W0714 06:34:58.464305 28078 gcp.go:120] WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead. - To learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
概要
このステップでは、環境に Codelab の資料を準備し、skaffold が想定どおりに実行されることを確認しました。
次のステップ
次のステップでは、トレース情報を計測するように loadgen サービスのソースコードを変更します。
4. HTTP の計測
トレース計測と伝播のコンセプト
ソースコードを編集する前に、分散トレースの仕組みを簡単な図で説明します。
この例では、コードをインストルメント化して、トレース情報とスパンを Cloud Trace にエクスポートし、リクエスト全体でトレース コンテキストを loadgen サービスからサーバー サービスに伝播します。
Cloud Trace が同じトレース ID を持つすべてのスパンを 1 つのトレースとしてアセンブルするには、アプリケーションがトレース ID やスパン ID などのトレース メタデータを送信する必要があります。また、アプリケーションは、リクエストするダウンストリーム サービスにトレース コンテキスト(トレース ID と親スパンのスパンの ID の組み合わせ)を伝播して、処理しているトレース コンテキストを認識できるようにする必要があります。
OpenTelemetry を使用すると、次のようなことができます。
- 一意のトレース ID とスパン ID を生成します。
- トレース ID とスパン ID をバックエンドにエクスポートする
- トレース コンテキストを他のサービスに伝播する
- トレース分析に役立つ追加のメタデータを埋め込む
OpenTelemetry Trace のコンポーネント
OpenTelemetry でアプリケーション トレースを計測するプロセスは次のとおりです。
- エクスポータを作成する
- 1 でエクスポータをバインドする TracerProvider を作成し、グローバルに設定します。
- TextMapPropagaror を設定して伝播方法を設定する
- TracerProvider から Tracer を取得する
- Tracer から Span を生成する
現時点では、各コンポーネントの詳細なプロパティを理解する必要はありませんが、最も重要なことは次のとおりです。
- このエクスポータは TracerProvider にプラグインできます。
- TracerProvider は、トレース サンプリングとエクスポートに関するすべての構成を保持します。
- すべてのトレースが Tracer オブジェクトにバンドルされている
これを理解したうえで、実際のコード作成作業に移りましょう。
最初のスパンを計測する
負荷生成ツール サービスを計測する
Cloud Shell の右上にある ボタンを押して、Cloud Shell エディタを開きます。左側のペインにあるエクスプローラから
step0/src/loadgen/main.go
を開き、メイン関数を見つけます。
step0/src/loadgen/main.go
func main() { ... for range t.C { log.Printf("simulating client requests, round %d", i) if err := run(numWorkers, numConcurrency); err != nil { log.Printf("aborted round with error: %v", err) } log.Printf("simulated %d requests", numWorkers) if numRounds != 0 && i > numRounds { break } i++ } }
メイン関数には、関数 run
を呼び出すループがあります。現在の実装では、このセクションには関数呼び出しの開始と終了を記録する 2 つのログ行があります。次に、Span 情報を計測して、関数呼び出しのレイテンシを追跡します。
まず、前のセクションで説明したように、OpenTelemetry の構成全体を設定します。OpenTelemetry パッケージを次のように追加します。
step0/src/loadgen/main.go
import ( "context" // step1. add packages "encoding/json" "fmt" "io" "log" "math/rand" "net/http" "net/url" "time" // step1. add packages "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "go.opentelemetry.io/otel/trace" // step1. end add packages )
読みやすくするため、initTracer
というセットアップ関数を作成し、main
関数で呼び出します。
step0/src/loadgen/main.go
// step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
OpenTelemetry の設定手順は、前のセクションで説明した手順と同じです。この実装では、すべてのトレース情報を構造化形式で stdout にエクスポートする stdout
エクスポータを使用します。
次に、メイン関数から呼び出します。initTracer()
を呼び出し、アプリを閉じるときに TracerProvider.Shutdown()
を呼び出すようにします。
step0/src/loadgen/main.go
func main() { // step1. setup OpenTelemetry tp, err := initTracer() if err != nil { log.Fatalf("failed to initialize TracerProvider: %v", err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Fatalf("error shutting down TracerProvider: %v", err) } }() // step1. end setup log.Printf("starting worder with %d workers in %d concurrency", numWorkers, numConcurrency) log.Printf("number of rounds: %d (0 is inifinite)", numRounds) ...
設定が完了したら、一意の Trace ID と Span ID を持つ Span を作成する必要があります。OpenTelemetry には、そのための便利なライブラリが用意されています。計測対象の HTTP クライアントに新しいパッケージを追加します。
step0/src/loadgen/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "math/rand" "net/http" "net/http/httptrace" // step1. add packages "net/url" "time" // step1. add packages "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" // step1. end add packages "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "go.opentelemetry.io/otel/trace" )
ロードジェネレータは、runQuery
関数の net/http
を使用して HTTP でクライアント サービスを呼び出すため、net/http
に contrib パッケージを使用し、httptrace
パッケージと otelhttp
パッケージの拡張機能を使用して計測を有効にします。
まず、インストルメンテーションされたクライアントを介して HTTP リクエストを呼び出すパッケージ グローバル変数 httpClient を追加します。
step0/src/loadgen/main.go
var httpClient = http.Client{ Transport: otelhttp.NewTransport(http.DefaultTransport) }
次に、runQuery
関数に計測を追加して、OpenTelemetry とカスタム HTTP クライアントから自動生成されたスパンを使用してカスタムスパンを作成します。手順は次のとおりです。
otel.Tracer()
を使用してグローバルTracerProvider
から Tracer を取得するTracer.Start()
メソッドでルートスパンを作成する- 任意のタイミングでルートスパンを終了します(この場合は、
runQuery
関数の終了時)。
step0/src/loadgen/main.go
reqURL.RawQuery = v.Encode() // step1. replace http.Get() with custom client call // resp, err := http.Get(reqURL.String()) // step1. instrument trace ctx := context.Background() tr := otel.Tracer("loadgen") ctx, span := tr.Start(ctx, "query.request", trace.WithAttributes( semconv.TelemetrySDKLanguageGo, semconv.ServiceNameKey.String("loadgen.runQuery"), attribute.Key("query").String(s), )) defer span.End() ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx)) req, err := http.NewRequestWithContext(ctx, "GET", reqURL.String(), nil) if err != nil { return -1, fmt.Errorf("error creating HTTP request object: %v", err) } resp, err := httpClient.Do(req) // step1. end instrumentation if err != nil { return -1, fmt.Errorf("error sending request to %v: %v", reqURL.String(), err) }
これで、loadgen(HTTP クライアント アプリケーション)での計測が完了しました。go mod
コマンドで go.mod
と go.sum
を更新してください。
go mod tidy
インストルメントのクライアント サービス
前のセクションでは、下の図の赤い四角で囲まれた部分を計測しました。負荷生成ツールのサービスにスパンの情報を計測しました。負荷生成ツールサービスと同様に、クライアント サービスを計測する必要があります。ロード ジェネレータ サービスとの違いは、クライアント サービスは HTTP ヘッダーでロード ジェネレータ サービスから伝播された Trace ID 情報を抽出し、その ID を使用してスパンを生成する必要がある点です。
Cloud Shell エディタを開き、負荷生成ツールサービスの場合と同様に必要なパッケージを追加します。
step0/src/client/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "net/url" "os" "time" "opentelemetry-trace-codelab-go/client/shakesapp" // step1. add new import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" // step1. end new import )
ここでも、OpenTelemtry を設定する必要があります。loadgen から initTracer
関数をコピーして貼り付け、クライアント サービスの main
関数でも呼び出します。
step0/src/client/main.go
// step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
次に、スパンを計測します。クライアント サービスは loadgen サービスからの HTTP リクエストを受け入れる必要があるため、ハンドラを計測する必要があります。クライアント サービスの HTTP サーバーは net/http で実装されており、loadgen で行ったように otelhttp
パッケージを使用できます。
まず、ハンドラ登録を otelhttp
ハンドラに置き換えます。main
関数で、HTTP ハンドラが http.HandleFunc()
に登録されている行を見つけます。
step0/src/client/main.go
// step1. change handler to intercept OpenTelemetry related headers // http.HandleFunc("/", svc.handler) otelHandler := otelhttp.NewHandler(http.HandlerFunc(svc.handler), "client.handler") http.Handle("/", otelHandler) // step1. end intercepter setting http.HandleFunc("/_genki", svc.health)
次に、ハンドラ内の実際のスパンを計測します。func (*clientService) handler() を見つけて、trace.SpanFromContext()
を使用してスパンの計測を追加します。
step0/src/client/main.go
func (cs *clientService) handler(w http.ResponseWriter, r *http.Request) { ... ctx := r.Context() ctx, cancel := context.WithCancel(ctx) defer cancel() // step1. instrument trace span := trace.SpanFromContext(ctx) defer span.End() // step1. end instrument ...
この計測では、handler
メソッドの先頭から末尾までのスパンが取得されます。スパンを簡単に分析できるように、一致した数を格納する追加の属性をクエリに追加します。ログ行の直前に、次のコードを追加します。
func (cs *clientService) handler(w http.ResponseWriter, r *http.Request) { ... // step1. add span specific attribute span.SetAttributes(attribute.Key("matched").Int64(resp.MatchCount)) // step1. end adding attribute log.Println(string(ret)) ...
上記のすべての計測により、loadgen とクライアント間のトレース計測が完了しました。では、その仕組みを見てみましょう。skaffold を使用してコードをもう一度実行します。
skaffold dev
GKE クラスタでサービスを実行すると、次のような大量のログ メッセージが表示されます。
コマンド出力
[loadgen] { [loadgen] "Name": "query.request", [loadgen] "SpanContext": { [loadgen] "TraceID": "cfa22247a542beeb55a3434392d46b89", [loadgen] "SpanID": "18b06404b10c418b", [loadgen] "TraceFlags": "01", [loadgen] "TraceState": "", [loadgen] "Remote": false [loadgen] }, [loadgen] "Parent": { [loadgen] "TraceID": "00000000000000000000000000000000", [loadgen] "SpanID": "0000000000000000", [loadgen] "TraceFlags": "00", [loadgen] "TraceState": "", [loadgen] "Remote": false [loadgen] }, [loadgen] "SpanKind": 1, [loadgen] "StartTime": "2022-07-14T13:13:36.686751087Z", [loadgen] "EndTime": "2022-07-14T13:14:31.849601964Z", [loadgen] "Attributes": [ [loadgen] { [loadgen] "Key": "telemetry.sdk.language", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "go" [loadgen] } [loadgen] }, [loadgen] { [loadgen] "Key": "service.name", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "loadgen.runQuery" [loadgen] } [loadgen] }, [loadgen] { [loadgen] "Key": "query", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "faith" [loadgen] } [loadgen] } [loadgen] ], [loadgen] "Events": null, [loadgen] "Links": null, [loadgen] "Status": { [loadgen] "Code": "Unset", [loadgen] "Description": "" [loadgen] }, [loadgen] "DroppedAttributes": 0, [loadgen] "DroppedEvents": 0, [loadgen] "DroppedLinks": 0, [loadgen] "ChildSpanCount": 5, [loadgen] "Resource": [ [loadgen] { [loadgen] "Key": "service.name", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "unknown_service:loadgen" ...
stdout
エクスポータはこれらのメッセージを出力します。loadgen によるすべてのスパンの親には TraceID: 00000000000000000000000000000000
が含まれています。これは、ルートスパンで、トレース内の最初のスパンであるためです。また、埋め込み属性 "query"
には、クライアント サービスに渡されるクエリ文字列があります。
概要
このステップでは、HTTP で通信する負荷生成ツール サービスとクライアント サービスを計測し、サービス間でトレース コンテキストを正常に伝播し、両方のサービスから stdout に Span 情報をエクスポートできることを確認しました。
次のステップ
次のステップでは、クライアント サービスとサーバー サービスを計測して、gRPC を介してトレース コンテキストを伝播する方法を確認します。
5. gRPC のインストルメンテーション
前のステップでは、このマイクロサービスでリクエストの前半を計測しました。このステップでは、クライアント サービスとサーバー サービス間の gRPC 通信を計測します。(下の画像の緑色と紫色の長方形)。
gRPC クライアントのビルド前計測
OpenTelemetry のエコシステムには、デベロッパーがアプリケーションを計測するのに役立つ便利なライブラリが多数用意されています。前の手順では、net/http
パッケージにビルド前の計測を使用しました。このステップでは、gRPC を介してトレース コンテキストを伝播するため、ライブラリを使用します。
まず、otelgrpc
というビルド済みの gRPC パッケージをインポートします。
step0/src/client/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "net/url" "os" "time" "opentelemetry-trace-codelab-go/client/shakesapp" // step2. add prebuilt gRPC package (otelgrpc) "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" )
今回は、クライアント サービスがサーバー サービスに対する gRPC クライアントであるため、gRPC クライアントを計測する必要があります。mustConnGRPC
関数を見つけて、クライアントがサーバーにリクエストするたびに新しいスパンを計測する gRPC インターセプタを追加します。
step0/src/client/main.go
// Helper function for gRPC connections: Dial and create client once, reuse. func mustConnGRPC(ctx context.Context, conn **grpc.ClientConn, addr string) { var err error // step2. add gRPC interceptor interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider()) *conn, err = grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor(interceptorOpt)), grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor(interceptorOpt)), grpc.WithTimeout(time.Second*3), ) // step2: end adding interceptor if err != nil { panic(fmt.Sprintf("Error %s grpc: failed to connect %s", err, addr)) } }
前のセクションで OpenTelemetry をすでに設定しているため、この手順は必要ありません。
gRPC サーバー用に事前ビルドされた計測機能
gRPC クライアントの場合と同様に、gRPC サーバー用に事前ビルドされた計測ツールを呼び出します。インポート セクションに新しいパッケージを追加します。
step0/src/server/main.go
import ( "context" "fmt" "io/ioutil" "log" "net" "os" "regexp" "strings" "opentelemetry-trace-codelab-go/server/shakesapp" "cloud.google.com/go/storage" // step2. add OpenTelemetry packages including otelgrpc "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/otel" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/grpc" healthpb "google.golang.org/grpc/health/grpc_health_v1" )
サーバーをインストルメント化するのは初めてであるため、loadgen サービスとクライアント サービスで行ったように、まず OpenTelemetry を設定する必要があります。
step0/src/server/main.go
// step2. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil } func main() { ... // step2. setup OpenTelemetry tp, err := initTracer() if err != nil { log.Fatalf("failed to initialize TracerProvider: %v", err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Fatalf("error shutting down TracerProvider: %v", err) } }() // step2. end setup ...
次に、サーバー インターセプタを追加する必要があります。main
関数で、grpc.NewServer()
が呼び出される場所を見つけて、関数にインターセプタを追加します。
step0/src/server/main.go
func main() { ... svc := NewServerService() // step2: add interceptor interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider()) srv := grpc.NewServer( grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(interceptorOpt)), grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor(interceptorOpt)), ) // step2: end adding interceptor shakesapp.RegisterShakespeareServiceServer(srv, svc) ...
マイクロサービスを実行してトレースを確認する
次に、変更したコードを skaffold コマンドで実行します。
skaffold dev
再度、stdout に多くのスパンの情報が表示されます。
コマンド出力
... [server] { [server] "Name": "shakesapp.ShakespeareService/GetMatchCount", [server] "SpanContext": { [server] "TraceID": "89b472f213a400cf975e0a0041649667", [server] "SpanID": "96030dbad0061b3f", [server] "TraceFlags": "01", [server] "TraceState": "", [server] "Remote": false [server] }, [server] "Parent": { [server] "TraceID": "89b472f213a400cf975e0a0041649667", [server] "SpanID": "cd90cc3859b73890", [server] "TraceFlags": "01", [server] "TraceState": "", [server] "Remote": true [server] }, [server] "SpanKind": 2, [server] "StartTime": "2022-07-14T14:05:55.74822525Z", [server] "EndTime": "2022-07-14T14:06:03.449258891Z", [server] "Attributes": [ ... [server] ], [server] "Events": [ [server] { [server] "Name": "message", [server] "Attributes": [ ... [server] ], [server] "DroppedAttributeCount": 0, [server] "Time": "2022-07-14T14:05:55.748235489Z" [server] }, [server] { [server] "Name": "message", [server] "Attributes": [ ... [server] ], [server] "DroppedAttributeCount": 0, [server] "Time": "2022-07-14T14:06:03.449255889Z" [server] } [server] ], [server] "Links": null, [server] "Status": { [server] "Code": "Unset", [server] "Description": "" [server] }, [server] "DroppedAttributes": 0, [server] "DroppedEvents": 0, [server] "DroppedLinks": 0, [server] "ChildSpanCount": 0, [server] "Resource": [ [server] { ... [server] ], [server] "InstrumentationLibrary": { [server] "Name": "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc", [server] "Version": "semver:0.33.0", [server] "SchemaURL": "" [server] } [server] } ...
スパンの名を埋め込んでおらず、trace.Start()
または span.SpanFromContext()
で手動でスパンを作成していることがわかります。それでも、gRPC インターセプタによってスパンが生成されるため、スパンが大量に生成されます。
概要
このステップでは、OpenTelemetry エコシステム ライブラリのサポートを使用して、gRPC ベースの通信を計測しました。
次のステップ
次のステップでは、Cloud Trace でトレースを可視化し、収集されたスパンを分析する方法を学習します。
6. Cloud Trace でトレースを可視化する
OpenTelemetry を使用してシステム全体のトレースを計測可能にしました。ここまでは、HTTP サービスと gRPC サービスを計測する方法について学習しました。計測方法は学びましたが、分析方法はまだ学んでいません。このセクションでは、stdout エクスポータを Cloud Trace エクスポータに置き換え、トレースを分析する方法を学習します。
Cloud Trace エクスポータを使用する
OpenTelemetry の強力な特徴の 1 つがプラグイン機能です。計測によって収集されたすべてのスパンを可視化するには、stdout エクスポータを Cloud Trace エクスポータに置き換えるだけです。
各サービスの main.go
ファイルを開き、initTracer()
関数を見つけます。stdout エクスポータを生成する行を削除し、代わりに Cloud Trace エクスポータを作成します。
step0/src/loadgen/main.go
import ( ... // step3. add OpenTelemetry for Cloud Trace package cloudtrace "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace" ) // step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // step3. replace stdout exporter with Cloud Trace exporter // cloudtrace.New() finds the credentials to Cloud Trace automatically following the // rules defined by golang.org/x/oauth2/google.findDefaultCredentailsWithParams. // https://pkg.go.dev/golang.org/x/oauth2/google#FindDefaultCredentialsWithParams exporter, err := cloudtrace.New() // step3. end replacing exporter if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
クライアント サービスとサーバー サービスでも同じ関数を編集する必要があります。
マイクロサービスを実行してトレースを確認する
編集したら、skaffold コマンドで通常どおりクラスタを実行します。
skaffold dev
エクスポータを Cloud Trace エクスポータに置き換えたため、stdout の構造化ログ形式でスパンの情報がほとんど表示されなくなりました。
コマンド出力
[loadgen] 2022/07/14 15:01:07 simulated 20 requests [loadgen] 2022/07/14 15:01:07 simulating client requests, round 37 [loadgen] 2022/07/14 15:01:14 query 'sweet': matched 958 [client] 2022/07/14 15:01:14 {"match_count":958} [client] 2022/07/14 15:01:14 {"match_count":3040} [loadgen] 2022/07/14 15:01:14 query 'love': matched 3040 [client] 2022/07/14 15:01:15 {"match_count":349} [loadgen] 2022/07/14 15:01:15 query 'hello': matched 349 [client] 2022/07/14 15:01:15 {"match_count":484} [loadgen] 2022/07/14 15:01:15 query 'faith': matched 484 [loadgen] 2022/07/14 15:01:15 query 'insolence': matched 14 [client] 2022/07/14 15:01:15 {"match_count":14} [client] 2022/07/14 15:01:21 {"match_count":484} [loadgen] 2022/07/14 15:01:21 query 'faith': matched 484 [client] 2022/07/14 15:01:21 {"match_count":728} [loadgen] 2022/07/14 15:01:21 query 'world': matched 728 [client] 2022/07/14 15:01:22 {"match_count":484} [loadgen] 2022/07/14 15:01:22 query 'faith': matched 484 [loadgen] 2022/07/14 15:01:22 query 'hello': matched 349 [client] 2022/07/14 15:01:22 {"match_count":349} [client] 2022/07/14 15:01:23 {"match_count":1036} [loadgen] 2022/07/14 15:01:23 query 'friend': matched 1036 [loadgen] 2022/07/14 15:01:28 query 'tear': matched 463 ...
すべてのスパンが Cloud Trace に正しく送信されていることを確認しましょう。Cloud コンソールにアクセスし、[トレースリスト] に移動します。検索ボックスから簡単にアクセスできます。そうでない場合は、左側のペインにあるメニューをクリックします。
レイテンシ グラフ全体に青い点が多数分散しています。各スポットは 1 つのトレースを表します。
いずれかをクリックすると、トレースの詳細が表示されます。
この簡単なクイック ビューでも、多くの分析情報を把握できます。たとえば、ウォーターフォール グラフから、レイテンシの原因のほとんどが shakesapp.ShakespeareService/GetMatchCount
という名前のスパンによるものであることがわかります。(上記の画像の 1 を参照)。この点は、概要の表で確認できます。(右端の列には、各スパンの所要時間が示されます)。また、このトレースは「friend」というクエリに対するものです。(上の画像の 2 を参照)。
これらの簡単な分析から、GetMatchCount
メソッド内のより詳細なスパンを把握する必要があることがわかるでしょう。stdout 情報と比較して、可視化は強力です。Cloud Trace の詳細については、公式ドキュメントをご覧ください。
概要
このステップでは、stdout エクスポータを Cloud Trace エクスポータに置き換え、Cloud Trace でトレースを可視化しました。また、トレースの分析を開始する方法についても学びました。
次のステップ
次のステップでは、サーバー サービスのソースコードを変更して、GetMatchCount にサブスパンを追加します。
7. 分析を強化するためにサブスパンを追加
前の手順で、loadgen で観測されたラウンドトリップ時間の原因は、ほとんどがサーバー サービスの GetMatchCount メソッド(gRPC ハンドラ)内のプロセスであることがわかりました。ただし、ハンドラ以外には計測を行っていないため、ウォーターフォール グラフから詳細な分析情報を得ることはできません。これは、マイクロサービスの計測を開始する際の一般的なケースです。
このセクションでは、サーバーが Google Cloud Storage を呼び出すサブスパンを計測します。これは、一部の外部ネットワーク I/O が処理に時間がかかることが一般的であり、呼び出しが原因かどうかを特定することが重要であるためです。
サーバーでサブスパンをインストルメント化する
サーバーで main.go
を開き、関数 readFiles
を見つけます。この関数は、Google Cloud Storage へのリクエストを呼び出して、シェイクスピアの著作のすべてのテキスト ファイルを取得します。この関数では、クライアント サービスの HTTP サーバー計測で行ったように、サブスパンを作成できます。
step0/src/server/main.go
func readFiles(ctx context.Context, bucketName, prefix string) ([]string, error) { type resp struct { s string err error } // step4: add an extra span span := trace.SpanFromContext(ctx) span.SetName("server.readFiles") span.SetAttributes(attribute.Key("bucketname").String(bucketName)) defer span.End() // step4: end add span ...
以上で、新しいスパンの追加は完了です。アプリを実行して、動作を確認しましょう。
マイクロサービスを実行してトレースを確認する
編集したら、skaffold コマンドで通常どおりクラスタを実行します。
skaffold dev
トレースリストから query.request
という名前のトレースを選択します。shakesapp.ShakespeareService/GetMatchCount
の下に新しいスパンが追加されている以外は、同様のトレース ウォーターフォール グラフが表示されます。(下の赤い長方形で囲まれた部分)
このグラフからわかるのは、Google Cloud Storage への外部呼び出しが大量のレイテンシを占有しているものの、他の要素がレイテンシの大部分を占めているということです。
トレースのウォーターフォール グラフを数回見ただけで、多くの分析情報を得ることができました。アプリケーションのパフォーマンスの詳細を取得するにはどうすればよいですか?ここでプロファイラが役立ちますが、この Codelab はここで終了し、プロファイラに関するチュートリアルはすべてパート 2 に委ねましょう。
概要
このステップでは、サーバー サービスに別のスパンを計測し、システム レイテンシに関する詳細な分析情報を取得しました。
8. 完了
OpenTelemetry で分散トレースを正常に作成し、Google Cloud Trace でマイクロサービス全体のリクエスト レイテンシを確認しました。
演習を拡張するには、次のトピックを自分で試してください。
- 現在の実装では、ヘルスチェックによって生成されたすべてのスパンが送信されます。(
grpc.health.v1.Health/Check
)Cloud Trace からこれらのスパンを除外するにはどうすればよいですか?ヒントはこちらにあります。 - イベントログとスパンを関連付けて、Google Cloud Trace と Google Cloud Logging でどのように機能するかを確認します。ヒントはこちらにあります。
- 一部のサービスを別の言語のサービスに置き換えて、その言語の OpenTelemetry で計測化を試みます。
また、プロファイラについて詳しくは、パート 2 をご覧ください。その場合は、以下のクリーンアップ セクションをスキップできます。
クリーンアップ
この Codelab の終了後に、Kubernetes クラスタを停止し、プロジェクトを削除して、Google Kubernetes Engine、Google Cloud Trace、Google Artifact Registry で予期しない料金が発生しないようにしてください。
まず、クラスタを削除します。skaffold dev
でクラスタを実行している場合は、Ctrl+C キーを押すだけです。skaffold run
でクラスタを実行している場合は、次のコマンドを実行します。
skaffold delete
コマンド出力
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
クラスタを削除したら、メニューペインで [IAM と管理] > [設定] を選択し、[シャットダウン] ボタンをクリックします。
次に、ダイアログのフォームにプロジェクト ID(プロジェクト名ではない)を入力し、シャットダウンを確認します。