Pollito Blog
April 9, 2024

Spring Cloud: api-gateway y naming-server

Posted on April 9, 2024  •  9 minutes  • 1761 words  • Other languages:  English

Inspiración

Al final de mi previo blog Anime Poster Generator 4: Cómo un backend intenta hacer frontend , dije:

Las personas muy importantes que deciden mi salario no se sentarán conmigo para una revisión anual hasta que complete algunos cursos en una plataforma educativa de su elección, a la que debo pagar de mi dinero o utilizar el bono educativo que me dan (que al final del día, es mi dinero) […] No puedo evitar pensar que es estúpido que quieras que te demuestre que conozco Java después de un año codificando en Java. Pero bueno, lo que sea, seguiré sus reglas (aunque qué pérdida de tiempo).

La plataforma educativa en cuestión es pluralsight . Simplemente hice speedrun del conocimiento requerido que tenía que demostrar, saltándome los cursos por completo y pasando directamente a las evaluaciones de habilidades.

Cuando llegó el momento de mostrar mis conocimientos de Spring Cloud, recordé que tenía algunas notas sobre el curso de Udemy Master Microservices with Spring Boot y Spring Cloud . Es un curso muy completo que terminé allá por abril de 2023.

Curiosamente, el cuestionario de evaluación de habilidades se centró más en sleuth y ribbon , en ambos no tengo experiencia ni los uso en mi trabajo. De todos modos, salí con una buena calificación. Este es un ejemplo perfecto del hecho casi inútil que es evaluar a los desarrolladores.

Aqui el resultado: mi perfil en pluralsight + mi score de DEVSU (99%, nice).

skills

Después de leer mis notas sobre Spring Cloud, decidí volver a visitar el curso para mejorarlas y tal vez escribir un blog. Qué agradable sorpresa fue ver que el chico que hizo el curso todavía lo está actualizando a la última versión de Spring Boot. Otra razón más para que vayas a gastar el dinero en el curso. El hombre es un educador natural.

Pero bueno, ahorita les presento lamento boliviano mis notas sobre Spring Cloud.

DESCARGO DE RESPONSABILIDAD: esto no es un copiar y pegar del curso de Udemy Master Microservices with Spring Boot and Spring Cloud . Recomiendo ampliamente comprar ese curso. Todo el código que se muestra a continuación fue escrito por mí. Disfrute.

Check el código!

Puede chequear el código en los siguientes repositorios (en todos ellos, siga la de feature/docker-compose. Puede encontrar otras ramas, soy yo experimentando otras soluciones).

¿Qué es un api-gateway?

Analicemos este diagrama:

diagram

Tenemos:

Todo bien hasta acá. Entonces… Qué es “api-gateway”?

Un API Gateway es la puerta de entrada a la aplicación, lo que garantiza que cada solicitud se dirija al destino correcto. Esta puerta de enlace cumple varias funciones críticas y se puede aprovechar en varios casos de uso:

Casos de uso:

Al actuar como punto central para gestionar y dirigir el tráfico, un microservicio de API Gateway mejora la mantenibilidad, la escalabilidad y la seguridad de las aplicaciones basadas en la nube.

Ejemplo

Analicemos el diagrama, nuevamente, centrándonos más en el paso a paso:

diagram

  1. Alguien llama api-gateway/microservice-a. api-gateway recibe esta solicitud y hace todo lo que está codificado para hacer con dicha solicitud (tal vez podría agregar un encabezado, verificar la autenticación, codificar/decodificar información o simplemente ser transparente y no hacer nada).
  2. api-gateway sabe dónde está el microservice-a y pasa la solicitud.
  3. microservice-a recibe la solicitud. Necesita algo del microservice-b, por lo que realiza una nueva solicitud que pasa por api-gateway.
  4. Nuevamente, api-gateway hace todo lo que está codificado para hacer con esta nueva solicitud al microservice-b. Sabe dónde está el microservice-b y pasa la solicitud.
  5. microservice-b recibe una solicitud, la procesa y la devuelve.
  6. retorno de api-gateway.
  7. microservice-a hace lo que hay que hacer con la respuesta del microservicio-b y retorna.
  8. Respuesta final.

¿Podría haber ahorrado algunas peticiones de request/response pasando directamente del microservice-a al microservice-b? Sí totalmente. Sólo como ejemplo, decidí hacerlo de esta manera. Tal vez su realidad necesite evitar esas solicitudes adicionales, o tal vez necesite pasar siempre por el API Gateway. Cada realidad es diferente.

Revisión al código de api-gateway

Cuando miras el código de api-gateway te das cuenta de que, está bastante vacío.

api-gateway code

¿Cómo sabe el API-gateway dónde enviar las solicitudes? La respuesta está en pom.xml.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

La dependencia spring-cloud-starter-gateway le da al microservicio todas las características de API Gateway comentadas.

Aquí la estrella del espectáculo es spring-cloud-starter-netflix-eureka-client. Registra el API Gateway como cliente con Eureka Server (un registro de servicios). Esto permite que el API Gateway descubra y realice un seguimiento de las instancias de microservicios disponibles en el ecosistema.

Cuando llega una solicitud a API Gateway, se producen los siguientes pasos:

  1. El API Gateway identifica la ruta y el microservicio al que se debe reenviar la solicitud según las reglas de enrutamiento configuradas.
  2. El API Gateway consulta el servidor Eureka para obtener las instancias actuales del microservicio de destino, incluidas sus ubicaciones de red.
  3. El Servidor Eureka responde con la información sobre las instancias disponibles. Podría devolver varias instancias si el microservicio de destino se escala horizontalmente para lograr alta disponibilidad.
  4. El API Gateway aplica cualquier estrategia de equilibrio de carga configurada para seleccionar una instancia si hay varias disponibles.
  5. La solicitud se envía a la instancia de microservicio elegida para su procesamiento.

Esta combinación de Spring Cloud Gateway y Eureka Client permite el enrutamiento dinámico basado en el descubrimiento de servicios, lo que hace que el sistema sea más resistente y escalable.

No es necesario configurar API Gateway de forma estática con las ubicaciones de los microservicios. En cambio, los resuelve dinámicamente, acomodando cambios en tiempo real en el panorama de los microservicios, como eventos de escala o servicios que caen por mantenimiento.

naming-server

Eureka Client registra microservicios en un registro de servicios. Ahora necesitamos eso, un registro de servicios. Yo lo llamo naming-server.

Cuando miras su código, notas algo… ¡Está literalmente vacío! Solo la clase principal de Spring Boot con una anotación.

@SpringBootApplication
@EnableEurekaServer
public class NamingServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(NamingServerApplication.class, args);
    }

}

Nuevamente, toda la magia se hace mediante una dependencia en el archivo pom.xml.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

Algunas consideraciones

Registrarse en el naming-server

Cada microservicio que quiera registrarse en el servidor de nombres para que otros microservicios lo encuentren, necesita:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>3.2.4</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>4.1.1</version>
</dependency>
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka #or wherever eureka server is
  instance:
    prefer-ip-address: true

¿Qué son esas dependencias de micrometer y zipkin?

El curso de Udem Master Microservices with Spring Boot and Spring Cloud viene con contenido acerca de logging y tracing, asi que decidí implementarlo aquí también.

Sin entrar en aspectos técnicos, esas dependencias ayudan con:

Lo único que tuvo que cambiar en el código comercial adecuado para que estas dependencias funcionaran fue:

@Configuration
@ComponentScans(
    value = {
      @ComponentScan(
          basePackages = {
            "dev.pollito.microserviceb.api",
          })
    })
@RequiredArgsConstructor
public class MicroserviceBApiConfig {
  private final MicroserviceBProperties microserviceBProperties;
  private final MeterRegistry meterRegistry;
  private final ObservationRegistry observationRegistry;

  @Bean
  public HelloWorldApi microServiceBApi() {
    return Feign.builder()
        .client(new OkHttpClient())
        .encoder(new GsonEncoder())
        .decoder(new GsonDecoder())
        .errorDecoder(new MicroserviceBErrorDecoder())
        .logger(new Slf4jLogger(HelloWorldApi.class))
        .logLevel(Logger.Level.FULL)
        .addCapability(new MicrometerObservationCapability(observationRegistry))    // <-- THIS IS NEW
        .addCapability(new MicrometerCapability(meterRegistry))                     // <-- THIS IS NEW
        .target(HelloWorldApi.class, microserviceBProperties.getBaseUrl());
  }
}
logging:
  pattern:
    level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
management:
  tracing:
    sampling:
      probability: 1.0

Hagamos que esto funcione

Utilice el archivo docker-compose para comenzar. No entraré en detalles sobre cómo funciona Docker Compose. Este es un blog de Spring Cloud, no de Docker.

Personalmente, me gusta usar docker desktop para estas cosas, pero puedes usar el CMD.

docker desktop

Si marca localhost:8761 , encontrará el servidor Eureka con todos los servicios que se registraron.

Eureka Server

La ejecución de este curl hará que todo el proceso pase por api-gateway, microservice-a, microservice-b y viceversa.

curl --location 'http://172.22.224.1:8765/microservice-a'

postman

Podemos ver toda la solicitud viajar a través de los micoservicios gracias a zipkin. Vaya a http://localhost:9411/zipkin/ .

zipking

Haga clic en “RUN QUERY” y encontrará su solicitud.

run query

Haga clic en “SHOW” para ver más detalles.

show

Próximos pasos

Implementar esta misma idea en Google Cloud GKE.

Hey, check me out!

You can find me here