Spring Cloud Sleuth と Cloud Trace を使用した分散トレース

1. 概要

分散トレースは、多層マイクロサービス アーキテクチャの分析情報とオブザーバビリティを得るうえで重要です。サービス A からサービス B、サービス C へとサービス間呼び出しを連結する場合、呼び出しが成功したことと、各ステップのレイテンシを把握することが重要です。

Spring Boot では、Spring Cloud Sleuth を使用して分散トレース計測をアプリケーションにシームレスに追加できます。デフォルトでは、トレースデータを Zipkin に転送できます。

Google Cloud Platform には Cloud Trace があります。Cloud Trace は、独自の Zipkin インスタンスやストレージを管理しなくても、トレースデータを保存できるマネージド サービスです。Cloud Trace は、レイテンシ分布レポートを生成し、パフォーマンスの低下を自動的に検出することもできます。

Spring Boot アプリケーションから Cloud Trace を使用するには、次の 2 つの方法があります。

  1. Stackdriver Trace Zipkin プロキシを使用して、このプロキシを Zipkin エンドポイントとして使用するように Spring Cloud Sleuth を構成するだけです。
  2. または、Spring Cloud GCP Trace を使用します。Spring Cloud GCP Trace は Spring Cloud Sleuth とシームレスに統合され、トレースデータを Cloud Trace に直接転送します。

この Codelab では、新しい Spring Boot アプリケーションを作成し、Spring Cloud GCP Trace を使用して分散トレースを行う方法を学びます。

学習内容

  • Spring Boot Java アプリケーションを作成し、Cloud Trace を構成する方法。

必要なもの

  • Google Cloud Platform プロジェクト
  • ChromeFirefox などのブラウザ
  • Linux の標準的なテキスト エディタ(vim、emacs、nano など)を使い慣れていること

このチュートリアルをどのように使用しますか?

通読するのみ 通読し、演習を行う

HTML/CSS ウェブアプリの作成経験をどのように評価されますか。

初心者 中級者 上級者

Google Cloud Platform サービスのご利用経験についてどのように評価されますか?

<ph type="x-smartling-placeholder"></ph> 初心者 中級 上達 をご覧ください。

2. 設定と要件

セルフペース型の環境設定

  1. Google Cloud Console にログインして、プロジェクトを新規作成するか、既存のプロジェクトを再利用します。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • プロジェクト名は、このプロジェクトの参加者に表示される名称です。Google API では使用されない文字列です。いつでも更新できます。
  • プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Cloud コンソールでは一意の文字列が自動生成されます。通常は、この内容を意識する必要はありません。ほとんどの Codelab では、プロジェクト ID(通常は PROJECT_ID と識別されます)を参照する必要があります。生成された ID が好みではない場合は、ランダムに別の ID を生成できます。または、ご自身で試して、利用可能かどうかを確認することもできます。このステップ以降は変更できず、プロジェクトを通して同じ ID になります。
  • なお、3 つ目の値として、一部の API が使用するプロジェクト番号があります。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
  1. 次に、Cloud のリソースや API を使用するために、Cloud コンソールで課金を有効にする必要があります。この Codelab の操作をすべて行って、費用が生じたとしても、少額です。このチュートリアルの終了後に請求が発生しないようにリソースをシャットダウンするには、作成したリソースを削除するか、プロジェクトを削除します。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。

Google Cloud Shell

Google Cloud と Kubernetes はノートパソコンからリモートで操作できますが、この Codelab では Cloud 上で動作するコマンドライン環境である Google Cloud Shell を使用します。

Cloud Shell をアクティブにする

  1. Cloud Console で、[Cloud Shell をアクティブにする] 853e55310c205094.png をクリックします。

55efc1aaa7a4d3ad.png

Cloud Shell を初めて起動する場合は、内容を説明する中間画面が表示されます。中間画面が表示されたら、[続行] をクリックします。

9c92662c6a846a5c.png

Cloud Shell のプロビジョニングと接続に少し時間がかかる程度です。

9f0e51b578fecce5.png

この仮想マシンには、必要なすべての開発ツールが読み込まれます。5 GB の永続的なホーム ディレクトリが用意されており、Google Cloud で稼働するため、ネットワークのパフォーマンスと認証が大幅に向上しています。この Codelab での作業のほとんどはブラウザを使って行うことができます。

Cloud Shell に接続すると、認証が完了し、プロジェクトに各自のプロジェクト ID が設定されていることがわかります。

  1. Cloud Shell で次のコマンドを実行して、認証されたことを確認します。
gcloud auth list

コマンド出力

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Cloud Shell で次のコマンドを実行して、gcloud コマンドがプロジェクトを認識していることを確認します。
gcloud config list project

コマンド出力

[core]
project = <PROJECT_ID>

上記のようになっていない場合は、次のコマンドで設定できます。

gcloud config set project <PROJECT_ID>

コマンド出力

Updated property [core/project].

3. 新しい Spring Boot REST サービスを作成する

Cloud Shell が起動したら、コマンドラインを使用して、Spring Initializr で新しい Spring Boot アプリケーションを生成できます。

$ curl https://start.spring.io/starter.tgz -d packaging=jar \
  -d bootVersion=2.7.6 \
  -d dependencies=web,lombok,cloud-gcp,distributed-tracing \
  -d jvmVersion=17 \
  -d type=maven-project \
  -d baseDir=trace-service-one | tar -xzvf - \
  && cd trace-service-one

新しいクラスを追加して新しい REST コントローラを作成します。

src/main/java/com/example/demo/WorkController.java

package com.example.demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;

@RestController
@Slf4j
public class WorkController {
  Random r = new Random();

  public void meeting() {
    try {
      log.info("meeting...");
      // Delay for random number of milliseconds.
      Thread.sleep(r.nextInt(500));
    } catch (InterruptedException e) {
    }
  }

  @GetMapping("/")
  public String work() {
    // What is work? Meetings!
    // When you hit this URL, it'll call meetings() 5 times.
    // Each time will have a random delay.
    log.info("starting to work");
    for (int i = 0; i < 5; i++) {
      this.meeting();
    }
    log.info("finished!");
    return "finished work!";
  }
}

アプリケーションに適切な JVM バージョンがあることを確認します。

$ export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64

Spring Boot プラグインを使用して、Spring Boot アプリケーションを通常どおり起動できます。このラボのテストはスキップします。

$ ./mvnw -DskipTests spring-boot:run

アプリケーションが開始したら、Cloud Shell ツールバーのウェブでプレビュー アイコン 3a9b40fafa650b2b.png をクリックし、[プレビューのポート: 8080] を選択します。

3aca52f76c6c22a3.png

しばらくすると、結果が表示されます。

6793a3339447cbb5.png

Cloud Shell には、トレース ID とスパン ID を含むログメッセージも表示されます。

18d597c388de1ba.png

4. Cloud Trace の使用

Cloud Trace API を有効にする

Cloud Trace を使用してトレースデータを保存する前に、まず Cloud Trace API を有効にする必要があります。API を有効にするには、次のコマンドを実行します。

$ gcloud services enable cloudtrace.googleapis.com

アプリケーションのデフォルト認証情報を設定する

このラボでは、アプリケーションのデフォルト認証情報を構成する必要があります。この認証情報は、Spring Cloud GCP Trace スターターによって自動的に取得されます。

まず、ログインします。

$ gcloud auth application-default login
You are running on a Google Compute Engine virtual machine.
The service credentials associated with this virtual machine
will automatically be used by Application Default
Credentials, so it is not necessary to use this command.
If you decide to proceed anyway, your user credentials may be visible
to others with access to this virtual machine. Are you sure you want
to authenticate with your personal account?
Do you want to continue (Y/n)? Y

Go to the following link in your browser:
    https://accounts.google.com/o/oauth2/auth...
Enter verification code: ...

リンクをクリックして新しいブラウザタブを開き、[許可] をクリックします。

85f500de6f5dc0a8.png

確認コードをコピーして Cloud Shell に再度貼り付け、Enter キーを押します。以下のように表示されます。

Credentials saved to file: [/tmp/tmp.jm9bnQ4R9Q/application_default_credentials.json]
These credentials will be used by any library that requests
Application Default Credentials.

Spring Cloud GCP Trace を追加する

このサービスでは、トレースに Spring Cloud Sleuth をすでに使用しています。データを Cloud Trace に転送するための Spring Cloud GCP Trace スターターを追加しましょう。

Spring Cloud GCP Trace の依存関係を追加します。

pom.xml

<project>
  ...
  <dependencies>
    ...
    <!-- Add Cloud Trace Starter -->
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>spring-cloud-gcp-starter-trace</artifactId>
    </dependency>
  </dependencies>
  ...
</project>

デフォルトでは、Spring Cloud Sleuth はすべてのリクエストをサンプリングするわけではありません。テストを簡単にするために、application.properties のサンプルレートを 100% に引き上げてトレースデータを表示し、重要でない URL を無視します。

$ echo "
spring.sleuth.sampler.probability=1.0
spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*)
" > src/main/resources/application.properties

アプリケーションを再度実行し、Cloud Shell のウェブ プレビューを使用してアプリケーションを表示します。

$ export GOOGLE_CLOUD_PROJECT=`gcloud config list --format 'value(core.project)'`
$ ./mvnw -DskipTests spring-boot:run

デフォルトでは、Spring Cloud GCP Trace はトレースデータをバッチ処理し、10 秒に 1 回、または最小数のトレースデータを受信したときに送信します。これは構成可能です。詳細については、Spring Cloud GCP Trace のリファレンス ドキュメントをご覧ください。

サービスにリクエストを送信します。

$ curl localhost:8080

Cloud コンソールで、[オペレーション] → [トレース] → [トレースリスト] に移動します。

be48cb0f99b5f7c2.png

上部で、期間を 1 時間に絞り込みます。デフォルトでは、[自動再読み込み] はオンになっています。トレースデータが到着すると、コンソールに表示されます。

3522eef823df39d8.png

トレースデータは 30 秒ほどで表示されます。

9628f6e1d2e75b05.png

青い点をクリックしてトレースの詳細を表示します。

ba9051a8d4f3e725.png

簡単だったね!

5. 2 つ目の Spring Boot ウェブ アプリケーションを作成する

+ アイコンをクリックして新しい Cloud Shell セッションを開きます。

9799bee5fea95aa6.png

新しいセッションで、2 つ目の Spring Boot アプリケーションを作成します。

$ curl https://start.spring.io/starter.tgz -d packaging=jar \
  -d bootVersion=2.7.6 \
  -d dependencies=web,lombok,cloud-gcp,distributed-tracing \
  -d jvmVersion=17 \
  -d type=maven-project \
  -d baseDir=trace-service-two | tar -xzvf - \
  && cd trace-service-two

新しいクラスを追加して新しい REST コントローラを作成します。

src/main/java/com/example/demo/MeetingController.java

package com.example.demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;

@RestController
@Slf4j
public class MeetingController {
  Random r = new Random();

  @GetMapping("/meet")
  public String meeting() {
    try {
      log.info("meeting...");
      Thread.sleep(r.nextInt(500 - 20 + 1) + 20);
    } catch (InterruptedException e) {
    }
    return "finished meeting";
  }
}

Spring Cloud GCP Trace を pom.xml に追加する

pom.xml

<project>
  ...
  <dependencies>
    ...
    <!-- Add Cloud Trace starter -->
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>spring-cloud-gcp-starter-trace</artifactId>
    </dependency>
  </dependencies>
  ...
</project>

すべてのリクエストをサンプリングするように Sleuth を構成します。

src/main/resources/application.properties

$ echo "
spring.sleuth.sampler.probability=1.0
spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*)
" > src/main/resources/application.properties

最後に、Spring Boot プラグインを使用して、ポート 8081 で Spring Boot アプリケーションを起動します。

$ export GOOGLE_CLOUD_PROJECT=`gcloud config list --format 'value(core.project)'`
$ ./mvnw -DskipTests spring-boot:run -Dspring-boot.run.jvmArguments="-Dserver.port=8081"

6. 1 つ目のサービスを更新して 2 つ目のサービスを使用する

trace-service-two を実行している間に、最初の Cloud Shell セッション ウィンドウに戻り、trace-service-one に変更を加えます。

まず、新しい RestTemplate Bean を初期化します。

src/main/java/com/example/demo/DemoApplication.java

package com.example.demo;

...

import org.springframework.web.client.RestTemplate;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemoApplication {
        @Bean
        public RestTemplate restTemplate() {
                return new RestTemplate();
        }
        
        public static void main(String[] args) {
                SpringApplication.run(DemoApplication.class, args);
        }
}

WorkController.meeting() で、会議サービスを呼び出します。

src/main/java/com/example/demo/WorkController.java

package com.example.demo;

...
import org.springframework.web.client.RestTemplate;
import org.springframework.beans.factory.annotation.Autowired;

@RestController
@Slf4j
public class WorkController {
  @Autowired
  RestTemplate restTemplate;

  public void meeting() {
    String result = restTemplate.getForObject("http://localhost:8081/meet", String.class);
    log.info(result);
  }

  ...
}

サービスを再度開始し、コマンドラインからエンドポイントをトリガーします。

$ export GOOGLE_CLOUD_PROJECT=`gcloud config list --format 'value(core.project)'`

# The '&' places the process in the background. Bring it back to the foreground with 'fg'.
$ ./mvnw -DskipTests spring-boot:run &

$ curl localhost:8080

両方のセッション ウィンドウに、トレース ID がサービス間で伝播されたログメッセージが表示されます。

Cloud Trace のトレースリストに 2 番目のトレースが表示されます。

13490977f1638702.png

新しい青い点をクリックすると、トレースの詳細が表示されます。

ca69ef9cdd13d4aa.png

この図のスパンをクリックして、スパンの詳細を確認することもできます。

7. レイテンシの分布とパフォーマンス レポート

Cloud Trace をトレースデータのストレージとして使用すると、Cloud Trace はこのデータを使用してレイテンシ分布レポートを作成できるようになります。次のようなレポートを作成するには、100 個を超えるトレースが必要です。

c8713f3d9e51dc25.png

Cloud Shell にプリインストールされている hey を使用すると、最初の 100 件以上のリクエストを実行できます。

$ hey localhost:8080 -n 150

さらに Cloud Trace では、分析レポートを使用して、同じサービスのパフォーマンスの低下を 2 つの異なる期間で自動的に検出できます。

8. まとめ

このラボでは、Spring Cloud Sleuth を使用して 2 つのシンプルなサービスを作成し、分散トレースを追加し、Spring Cloud GCP を使用してトレース情報を Cloud Trace に転送しました。

9. 完了

ここでは、最初の App Engine ウェブ アプリケーションを作成する方法を学習しました。

詳細

ライセンス

この作業はクリエイティブ・コモンズの表示 2.0 汎用ライセンスにより使用許諾されています。