Pollito Blog
April 9, 2024

Spring Cloud: API-Gateway y Naming-Server

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

[EDIT]: Quité la parte donde me desahogaba sobre mi vida personal que no aportaba al blog.

DISCLAIMER: Esto no es un copy-paste del curso Master Microservices with Spring Boot and Spring Cloud de Udemy. Te recomiendo copadamente comprar ese curso. Yo escribí todo el código que se muestra a continuación.

¡Mirá el código!

Podés revisar el código en los siguientes repositorios (en todos, quedate en la rama feature/docker-compose. Puede que veas otras ramas; eso soy yo experimentando con otras soluciones).

¿Qué es un API-Gateway?

Analicemos este diagrama:

diagram

Tenemos:

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

Una API Gateway es la puerta principal de tu aplicación, asegurándose de que cada solicitud se dirija al destino correcto. Este gateway cumple varias funciones críticas y se puede aprovechar en distintos casos:

Casos de uso:

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

Ejemplo

Analicemos el diagrama, otra vez, pero con más foco en cada paso.

diagram

  1. Alguien llama a api-gateway/microservice-a. El api-gateway recibe la solicitud y hace lo que esté programado para hacer con ella (podría, quizás, agregar un header, chequear la autenticación, codificar/decodificar info, o simplemente ser transparente y no hacer nada).
  2. El api-gateway sabe dónde está microservice-a y reenvía la solicitud.
  3. microservice-a recibe la solicitud. Necesita algo de microservice-b, así que hace una nueva solicitud que pasa por el gateway.
  4. Nuevamente, el api-gateway hace lo que esté programado para hacer con esta nueva solicitud a microservice-b. Sabe dónde está microservice-b y la reenvía.
  5. microservice-b recibe la solicitud, la procesa y responde.
  6. El api-gateway retorna (o reenvía la respuesta).
  7. microservice-a procesa la respuesta de microservice-b y responde.
  8. Respuesta final.

¿Podrías haber ahorrado algunas solicitudes/respuestas pasando directamente de microservice-a a microservice-b? Sí, totalmente. Pero solo por motivos de ejemplo, decidí hacerlo de esta manera. Quizás en tu caso necesites ahorrar esas solicitudes extra, o tal vez siempre deban pasar por el gateway. Cada realidad es distinta.

Un vistazo al código de API-Gateway

Al mirar el código del api-gateway, te das cuenta de algo… ¡Está bastante vacío!

api-gateway code

¿Cómo sabe el api-gateway a dónde enviar las solicitudes? La respuesta está en el 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 de spring-cloud-starter-gateway le confiere al microservicio todas las características de un gateway.

Acá, la gran protagonista es spring-cloud-starter-netflix-eureka-client. Registra tu API Gateway como un cliente en el Eureka Server (un registro de servicios). Esto permite al gateway descubrir y hacer seguimiento de las instancias de microservicios disponibles en tu ecosistema.

Cuando llega una solicitud al API Gateway, ocurren los siguientes pasos:

  1. El gateway identifica la ruta y el microservicio al que se debe reenviar la solicitud según las reglas de enrutamiento configuradas.
  2. El gateway consulta al Eureka Server para obtener las instancias actuales del microservicio objetivo, incluyendo sus ubicaciones de red.
  3. El Eureka Server responde con la información sobre las instancias disponibles. Puede devolver múltiples instancias si el microservicio objetivo está escalado horizontalmente para alta disponibilidad.
  4. El gateway aplica cualquier estrategia de balanceo de carga configurada para seleccionar una instancia si hay varias disponibles.
  5. La solicitud se reenvía a la instancia de microservicio elegida para su manejo.

Esta combinación de Spring Cloud Gateway y Eureka Client permite el enrutamiento dinámico basado en el descubrimiento de servicios, haciendo el sistema más resiliente y escalable.

La API Gateway no necesita estar configurado de forma estática con las ubicaciones de los microservicios. En cambio, los resuelve de forma dinámica, acomodando cambios en tiempo real en el panorama de microservicios, como eventos de escalado o servicios que se caen por mantenimiento.

Naming-Server

El Eureka Client registra los microservicios en un registro de servicios. Ahora necesitamos ese registro. Yo lo llamo naming-server.

Cuando mirás su código, te das cuenta de algo… ¡Está literalmente vacío! Solo tiene 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 la hace una dependencia en el archivo pom.xml.

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

Algunas consideraciones

Registrándose en Naming-Server

Cada microservicio que quiera registrarse en el naming-server para ser encontrado por otros microservicios 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 # o la dirección donde esté el eureka server
  instance:
    prefer-ip-address: true

¿Qué son esas dependencias de Micrometer y Zipkin?

El curso Master Microservices with Spring Boot and Spring Cloud de Udemy también incluye contenido sobre logging y tracing, así que decidí implementarlos acá también.

Sin entrar en demasiadas tecnicidades, esas dependencias ayudan a:

Lo único que tuvo que cambiar en el código de negocio para que estas dependencias funcionen 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))    // <-- ESTO ES NUEVO
        .addCapability(new MicrometerCapability(meterRegistry))                     // <-- ESTO ES NUEVO
        .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

Usá el archivo docker-compose para arrancar todo. No voy a entrar en detalles de 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 podés hacerlo desde CMD.

docker desktop

Si entrás a localhost:8761 , vas a encontrar el Eureka Server con todos los servicios que se registraron.

Eureka Server

Ejecutar este curl hará todo el proceso de pasar por el api-gateway, microservice-a, microservice-b y regresar.

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

postman

Podés ver cómo la solicitud recorre todos los microservicios gracias a Zipkin. Entrá a http://localhost:9411/zipkin/ .

zipkin

Hacé clic en “RUN QUERY” y vas a ver tu solicitud.

run query

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

show

Próximos pasos

Spring Cloud: Deployment en GKE

Hey, check me out!

You can find me here