Seguimiento distribuido con Spring Cloud Sleuth y Stackdriver Trace

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 Stackdriver 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. Stackdriver Trace también puede generar informes de distribución de latencia y detectar automáticamente las regresiones de rendimiento.

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

  1. Usa un proxy de Zipkin de Stackdriver Trace 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 Stackdriver 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 Spring Boot Java y configurar Stackdriver 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

Configuración del entorno de autoaprendizaje

Si aún no tienes una Cuenta de Google (Gmail o Google Apps), debes crear una. Accede a Google Cloud Platform Console (console.cloud.google.com) y crea un proyecto nuevo:

Screenshot from 2016-02-10 12:45:26.png

Recuerde el ID de proyecto, un nombre único en todos los proyectos de Google Cloud (el nombre anterior ya se encuentra en uso y no lo podrá usar). Se mencionará más adelante en este codelab como PROJECT_ID.

A continuación, deberás habilitar la facturación en la consola de Cloud para usar los recursos de Google Cloud.

Ejecutar este codelab debería costar solo unos pocos dólares, pero su costo podría aumentar si decides usar más recursos o si los dejas en ejecución (consulta la sección “Limpiar” al final de este documento).

Los usuarios nuevos de Google Cloud Platform son aptos para obtener una prueba gratuita de USD 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.

Activa Google Cloud Shell

En GCP Console, haga clic en el ícono de Cloud Shell en la barra de herramientas superior derecha:

Haga clic en "Start Cloud Shell":

El aprovisionamiento y la conexión al entorno debería llevar solo unos minutos:

Esta máquina virtual está cargada con todas las herramientas para desarrolladores que necesitará. 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 su trabajo, si no todo, se puede hacer simplemente con un navegador o su Google Chromebook.

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

En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:

gcloud auth list

Resultado del comando

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
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].

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 dependencies=web,lombok,cloud-gcp,cloud-starter-sleuth \
  -d baseDir=trace-service-one | tar -xzvf - \
  && cd trace-service-one

Para crear un nuevo controlador 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!";
  }
}

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, haz clic en el ícono de Vista previa en la Web , en la barra de herramientas de Cloud Shell, y selecciona Vista previa en el puerto 8080.

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

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

Habilita la API de Stackdriver Trace

Primero debes habilitar la API de Stackdriver Trace para usar Stackdriver Trace y almacenar tus datos de seguimiento. Para habilitar la API, navega a API Services → Library.

Busca Stackdriver Trace.

Haz clic en API de Stackdriver Trace y, luego, en Habilitar si aún no está habilitada.

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.

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.

Agrega 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 Stackdriver Trace.

Agrega la dependencia de Spring Cloud GCP Trace:

pom.xml

<project>
  ...
  <dependencies>
    ...
    <!-- Add Stackdriver Trace Starter -->
    <dependency>
      <groupId>org.springframework.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 Stackdriver TraceLista de seguimiento.

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.

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

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

¡Eso fue bastante simple!

Abre una sesión nueva de Cloud Shell haciendo clic en el ícono +:

En la nueva sesión, crea la segunda aplicación de Spring Boot:

$ curl https://start.spring.io/starter.tgz -d packaging=jar \
  -d dependencies=web,lombok,cloud-gcp,cloud-starter-sleuth \
  -d baseDir=trace-service-two | tar -xzvf - \
  && cd trace-service-two

Para crear un nuevo controlador 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 Stackdriver Trace starter -->
    <dependency>
      <groupId>org.springframework.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 -Dserver.port=8081

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

Primero, inicializa un nuevo bean 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 vista previa web:

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

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 seguimiento de Stackdriver Trace, deberías ver el segundo seguimiento:

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

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

Cuando usas Stackdriver Trace como el almacenamiento de datos de seguimiento, Stackdriver 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:

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

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

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.