Seguimiento distribuido con Spring Cloud Sleuth y Cloud Trace

1. Descripción general

El seguimiento distribuido es importante para obtener información y observabilidad en una arquitectura de microservicios de varios niveles. Cuando tienes llamadas encadenadas de servicio a servicio, desde el servicio A al servicio B y al servicio C, es importante comprender que las llamadas se realizaron correctamente y también la latencia en cada paso.

En Spring Boot, puedes usar Spring Cloud Sleuth para agregar sin problemas la instrumentación de seguimiento distribuido a tu aplicación. De forma predeterminada, puede reenviar los datos de seguimiento a Zipkin.

Google Cloud Platform tiene Cloud Trace, que es un servicio administrado que te permite almacenar datos de seguimiento sin tener que administrar tu propia instancia de Zipkin ni tu almacenamiento. Cloud Trace también puede generar informes de distribución de latencia y detectar automáticamente las regresiones del rendimiento.

Tienes dos opciones para usar Cloud Trace desde una aplicación de Spring Boot:

  1. Usa un proxy de Stackdriver Trace Zipkin y, luego, configura Spring Cloud Sleuth para que use este proxy como el extremo de Zipkin.
  2. También puedes usar Spring Cloud GCP Trace, que se integra sin problemas con Spring Cloud Sleuth y reenvía los datos de seguimiento directamente a Cloud Trace.

En este codelab, aprenderás a compilar una nueva aplicación de Spring Boot y a usar Spring Cloud GCP Trace para el registro de seguimiento distribuido.

Qué aprenderás

  • Cómo crear una aplicación de Java con Spring Boot y configurar Cloud Trace

Requisitos

  • Un proyecto de Google Cloud Platform
  • Un navegador como Chrome o Firefox
  • Se recomienda estar familiarizado con editores de texto estándares de Linux, como Vim, Emacs o Nano.

¿Cómo usarás este instructivo?

Ler Leer y completar los ejercicios

¿Cómo calificarías tu experiencia con la compilación de aplicaciones web con HTML/CSS?

Principiante Intermedio Avanzado

¿Cómo calificarías tu experiencia con el uso de los servicios de Google Cloud Platform?

Principiante Intermedio Avanzado

2. Configuración y requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a Google Cloud Console y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una cadena de caracteres que no se utiliza en las APIs de Google. Puedes actualizarla cuando quieras.
  • El ID del proyecto es único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). La consola de Cloud genera automáticamente una cadena única. Por lo general, no importa cuál sea. En la mayoría de los codelabs, deberás hacer referencia al ID de tu proyecto (suele identificarse como PROJECT_ID). Si no te gusta el ID que se generó, podrías generar otro aleatorio. También puedes probar uno propio y ver si está disponible. No se puede cambiar después de este paso y se usa el mismo durante todo el proyecto.
  • Recuerda que hay un tercer valor, un número de proyecto, que usan algunas APIs. Obtén más información sobre estos tres valores en la documentación.
  1. A continuación, deberás habilitar la facturación en la consola de Cloud para usar las APIs o los recursos de Cloud. Ejecutar este codelab no costará mucho, tal vez nada. Para cerrar recursos y evitar que se generen cobros más allá de este instructivo, puedes borrar los recursos que creaste o borrar el proyecto. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de $300.

Google Cloud Shell

Si bien Google Cloud y Kubernetes se pueden operar de manera remota desde tu laptop, en este codelab usaremos Google Cloud Shell, un entorno de línea de comandos que se ejecuta en la nube.

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shell853e55310c205094.png.

55efc1aaa7a4d3ad.png

Si es la primera vez que inicias Cloud Shell, aparecerá una pantalla intermedia en la que se describirá qué es. Si apareció una pantalla intermedia, haz clic en Continuar.

9c92662c6a846a5c.png

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

9f0e51b578fecce5.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo necesarias. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer con un navegador.

Una vez que te conectes a Cloud Shell, deberías ver que te autenticaste y que el proyecto se configuró con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
gcloud auth list

Resultado del comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto:
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

3. Crea un nuevo servicio REST de Spring Boot

Después de que se inicie Cloud Shell, puedes usar la línea de comandos para generar una nueva aplicación de Spring Boot con Spring Initializr:

$ 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

Para crear un nuevo controlador de REST, agrega una clase nueva:

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!";
  }
}

Asegúrate de tener la versión correcta de la JVM para la aplicación:

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

Puedes iniciar la aplicación Spring Boot de forma normal con el complemento de Spring Boot. Omitamos las pruebas para este lab:

$ ./mvnw -DskipTests spring-boot:run

Una vez que se haya iniciado la aplicación, haga clic en el ícono de Vista previa en la Web 3a9b40fafa650b2b.png, en la barra de herramientas de Cloud Shell, y seleccione Vista previa en el puerto 8080.

3aca52f76c6c22a3.png

Después de una breve espera, deberías ver el resultado:

6793a3339447cbb5.png

En Cloud Shell, también deberías ver los mensajes de registro con el ID de seguimiento y el ID de intervalo:

18d597c388de1ba.png

4. Usa Cloud Trace

Habilita la API de Cloud Trace

Primero debes habilitar la API de Cloud Trace antes de usar Cloud Trace para almacenar tus datos de seguimiento. Para habilitar la API, ejecuta el siguiente comando:

$ gcloud services enable cloudtrace.googleapis.com

Configura la credencial predeterminada de la aplicación

Para este lab, deberás configurar una credencial predeterminada de la aplicación. Spring Cloud GCP Trace Starter seleccionará automáticamente esta credencial.

Primero, accede:

$ 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: ...

Haz clic en el vínculo para abrir una nueva pestaña del navegador y, luego, haz clic en Permitir.

85f500de6f5dc0a8.png

Luego, copia y pega el código de verificación en Cloud Shell y presiona Intro. Deberías ver lo siguiente:

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

Cómo agregar Spring Cloud GCP Trace

En este servicio, ya usamos Spring Cloud Sleuth para el seguimiento. Agreguemos el iniciador de Spring Cloud GCP Trace para reenviar los datos a Cloud Trace.

Agrega la dependencia de 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>

De forma predeterminada, Spring Cloud Sleuth no muestrea cada solicitud. Para facilitar un poco nuestras pruebas, aumenta la frecuencia de muestreo al 100% en application.properties para asegurarte de que veamos los datos de seguimiento, además de ignorar algunas URLs que no nos interesan:

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

Vuelve a ejecutar la aplicación y usa la vista previa en la Web de Cloud Shell para verla:

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

De forma predeterminada, Spring Cloud GCP Trace agrupa los datos de seguimiento y los envía una vez cada 10 segundos o cuando se recibe una cantidad mínima de datos de seguimiento. Esto se puede configurar y puedes consultar la documentación de referencia de Spring Cloud GCP Trace para obtener más información.

Realiza una solicitud al servicio:

$ curl localhost:8080

En la consola de Cloud, navega a OperationsTraceTrace list.

be48cb0f99b5f7c2.png

En la parte superior, reduce el intervalo de tiempo a 1 hora. De forma predeterminada, la opción Recarga automática está activada. Por lo tanto, a medida que lleguen los datos de seguimiento, deberían aparecer en la consola.

3522eef823df39d8.png

Los datos de registro deberían aparecer en aproximadamente 30 segundos.

9628f6e1d2e75b05.png

Haz clic en el punto azul para ver los detalles del registro:

ba9051a8d4f3e725.png

¡Eso fue bastante simple!

5. Crea una segunda aplicación web de Spring Boot

Abre una sesión nueva de Cloud Shell. Para ello, haz clic en el ícono +:

9799bee5fea95aa6.png

En la nueva sesión, crea la segunda aplicación de 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

Para crear un nuevo controlador de REST, agrega una clase nueva:

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";
  }
}

Agrega Spring Cloud GCP Trace a 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>

Configura Sleuth para que muestre el 100% de las solicitudes:

src/main/resources/application.properties

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

Por último, puedes iniciar la aplicación de Spring Boot en el puerto 8081 con el complemento de 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. Actualiza el primer servicio para que consuma el segundo

Mientras se ejecuta trace-service-two, regresa a la primera ventana de la sesión de Cloud Shell y modifica trace-service-one.

Primero, inicializa un nuevo objeto RestTemplate:

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);
        }
}

En WorkController.meeting(), realiza una llamada al servicio de reuniones.

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);
  }

  ...
}

Vuelve a iniciar el servicio y activa el extremo desde la línea de comandos:

$ 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

En ambas ventanas de sesión, deberías ver los mensajes de registro, con el ID de seguimiento propagado de un servicio a otro.

En la lista de Cloud Trace, deberías ver el segundo registro:

13490977f1638702.png

Puedes hacer clic en el nuevo punto azul y ver el detalle del registro:

ca69ef9cdd13d4aa.png

También puedes hacer clic en cualquier intervalo de este diagrama para ver sus detalles.

7. Informe de rendimiento y distribución de la latencia

Cuando usas Cloud Trace como almacenamiento de datos de seguimiento, Cloud Trace puede usar los datos para generar un informe de distribución de latencia. Necesitarás más de 100 registros para generar el informe de esta manera:

c8713f3d9e51dc25.png

Puedes ejecutar esas primeras 100 solicitudes con hey, que viene preinstalado en Cloud Shell.

$ hey localhost:8080 -n 150

Además, Cloud Trace puede detectar automáticamente la regresión del rendimiento del mismo servicio en dos períodos diferentes en Informe de análisis.

8. Resumen

En este lab, creaste 2 servicios simples y agregaste un seguimiento distribuido con Spring Cloud Sleuth, y usaste Spring Cloud GCP para reenviar la información de seguimiento a Cloud Trace.

9. ¡Felicitaciones!

Aprendiste a escribir tu primera aplicación web de App Engine.

Más información

Licencia

Este trabajo cuenta con una licencia Atribución 2.0 Genérica de Creative Commons.