使用 Spring Cloud Sleuth 和 Cloud Trace 进行分布式跟踪

1. 概览

要深入了解和观测多层微服务架构,分布式跟踪非常重要。当您将服务到服务的调用串联时(从服务 A 到服务 B 到服务 C),必须了解调用是否成功,还必须每个步骤中的延迟。

在 Spring Boot 中,您可以使用 Spring Cloud Sleuth 将分布式跟踪插桩无缝地添加到您的应用。默认情况下,它可以将跟踪记录数据转发到 Zipkin。

Google Cloud Platform 提供 Cloud Trace 这项代管式服务,让您无需管理自己的 Zipkin 实例或存储空间即可存储跟踪记录数据。Cloud Trace 还可以生成延迟分布报告并自动检测性能下降问题。

您可以通过以下两种方式在 Spring Boot 应用中使用 Cloud Trace:

  1. 使用 Stackdriver Trace Zipkin 代理,只需将 Spring Cloud Sleuth 配置为将此代理用作 Zipkin 端点
  2. 或者,使用 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 Web 应用方面的经验水平?

新手水平 中等水平 熟练水平

您如何评价自己在使用 Google Cloud Platform 服务方面的经验水平?

<ph type="x-smartling-placeholder"></ph> 新手 中级 熟练

2. 设置和要求

自定进度的环境设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用 PROJECT_ID 标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。
  • 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。

Google Cloud Shell

虽然可以通过笔记本电脑远程操作 Google Cloud 和 Kubernetes,但在此 Codelab 中,我们将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。

激活 Cloud Shell

  1. 在 Cloud Console 中,点击激活 Cloud Shell853e55310c205094

55efc1aaa7a4d3ad.png

如果这是您第一次启动 Cloud Shell,系统会显示一个中间屏幕,说明它是什么。如果您看到中间屏幕,请点击继续

9c92662c6a846a5c

预配和连接到 Cloud Shell 只需花几分钟时间。

9f0e51b578fecce5

这个虚拟机装有所需的所有开发工具。它提供了一个持久的 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,然后选择在端口 8080 上预览

3aca52f76c6c22a3

短暂等待后,您应该会看到结果:

6793a3339447cbb5

在 Cloud Shell 中,您还应该会看到具有跟踪记录 ID 和 span ID 的日志消息:

18d597c388de1ba

4. 使用 Cloud Trace

启用 Cloud Trace API

您必须先启用 Cloud Trace API,然后才能使用 Cloud Trace 存储跟踪记录数据。如需启用该 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

然后,复制验证码并粘贴回 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 进行跟踪。我们来添加 Spring Cloud GCP Trace 入门版,以将数据转发到 Cloud 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%,以确保我们能看到轨迹数据,并忽略一些我们不关心的网址:

$ 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 秒或在收到一定数量的跟踪记录数据时发送一次。这是可配置的。如需了解详情,请参阅 Spring Cloud GCP Trace 参考文档

向服务发出请求:

$ curl localhost:8080

在 Cloud 控制台中,依次前往操作跟踪跟踪记录列表

be48cb0f99b5f7c2.png

在顶部将时间范围缩短为 1 小时。默认情况下,自动重新加载处于开启状态。因此,一旦跟踪记录数据到达,它就会显示在控制台中!

3522eef823df39d8.png

跟踪记录数据应会在大约 30 秒内显示。

9628f6e1d2e75b05

点击蓝色点可查看跟踪记录详情:

ba9051a8d4f3e725.png

这非常简单!

5. 创建第二个 Spring Boot Web 应用

点击 + 图标,打开一个新的 Cloud Shell 会话:

9799bee5fea95aa6

在新会话中,创建第二个 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 来对请求进行 100% 采样:

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. 更新第一个服务以使用第二个服务

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 的跟踪列表中,您应该会看到第二条跟踪记录:

13490977f1638702

您可以点击新的蓝色点来查看跟踪记录详情:

ca69ef9cdd13d4aa.png

您还可以点击此图表中的任意 span 来查看 span 的详细信息。

7. 延迟时间分布情况和效果报告

当您使用 Cloud Trace 作为跟踪记录数据存储时,Cloud Trace 可以使用这些数据生成延迟时间分布报告。您需要超过 100 条跟踪记录才能构建如下报告:

c8713f3d9e51dc25.png

您可以使用 Cloud Shell 中预装的 hey 来运行前 100 多个请求!

$ hey localhost:8080 -n 150

此外,Cloud Trace 还可以在分析报告下自动检测同一服务在两个不同时间段内的性能下降情况。

8. 总结

在本实验中,您创建了 2 项简单的服务,使用 Spring Cloud Sleuth 添加了分布式跟踪记录,并使用 Spring Cloud GCP 将跟踪记录信息转发到 Cloud Trace。

9. 恭喜!

您已了解如何编写您的第一个 App Engine Web 应用!

了解详情

许可

此作品已获得 Creative Commons Attribution 2.0 通用许可授权。