sábado, 12 de diciembre de 2020

Apache Camel: Service Discovery con Spring Cloud Netflix

Ya hemos visto bastante de Apache Camel, y hoy veremos como realizar Service Discovery a través de la librería de Spring Cloud Netflix. Pero antes como siempre veremos varios conceptos para entender mejor luego el ejemplo.

Debemos ubicarnos en un entorno de creación y utilización de Microservicios. Y como, si creamos Microservicios y los desplegamos a través de contenedores en la nube, sus localizaciones de red (IPs y direcciones) pueden ser dinámicas. Y por tanto nos pueden llevar a que la configuración que tengamos sobre la ubicación de los mismos no sea válida siempre. 

De ahí surge la necesidad del Service Discovery, o lo que es lo mismo, detección automática de dispositivos y servicios ofrecidos en una misma red. De esta forma, siempre tendremos la configuración correcta sobre los Microservicios disponibles. 

Para llevarlo a cabo necesitamos de un Service Registry que será un servidor encargado de recoger la información sobre los Microservicios: su ubicación, estado, etc. Y los Microservicios actuarían como los clientes de este Service Registry. Hay diferentes implementaciones de Service Registry y nosotros utilizaremos Netflix Eureka. 

Para llevar a cabo el Service Discovery se pueden utilizar varios patrones, y nosotros vamos a elegir el Client‑Side Discovery Pattern. Donde será el  cliente el encargado de registrarse en el Service Registry. 

Una vez asentadas las bases, podemos empezar con nuestro ejemplo. El cual consta de 3 aplicaciones:

  • Un Service Registry realizado solo con Spring Boot
  • Un Service Client realizado con Spring Boot, el cual tendrá un recurso que nos devolverá valores. 
  • Un Service Client realizado con Apache Camel, el cual se conectará al Service Registry y al otro Service Client dinámicamente. 
Empecemos por el Service Registry. Será la parte más sencilla, básicamente un proyecto de Spring Boot con la dependencia spring-cloud-starter-netflix-eureka-server y la anotación @EnableEurekaServer.

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(final String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

Eso sí, al ser una prueba de concepto en local y con un único Service Registry, tendremos que modificar el fichero de configuración de la aplicación para evitar errores de esta configuración y trazas excesivas. Y es debido a que el Service Registry está preparado para que funcione en un cluster y por tanto al iniciarse intenta buscar otras instancias y registrarse en las mismas. Por ello el fichero de configuración quedará de la siguiente forma:

server.port=8761

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

logging.level.com.netflix.eureka=OFF
logging.level.com.netflix.discovery=OFF

El siguiente paso será crear un cliente con Spring Boot que se conecte al Service Registry y que tenga un recurso denominado /books que devuelva información. Esta aplicación se denominará discovery-client.

Por último, procederemos a crear nuestro Microservicio con Apache Camel, el cual conectaremos al Service Registry y con el cual también invocaremos al Microservicio discovery-client. Para llevar a cabo todo esto nos basaremos en las siguientes librerías de Spring Boot y Spring Cloud. El resto serán las librerías habituales de Apache Camel. 

<dependency>
      <groupId>org.apache.camel.springboot</groupId>
      <artifactId>camel-spring-cloud-netflix-starter</artifactId>
</dependency>
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      <version>2.2.4.RELEASE</version>
</dependency>

A nivel de configuración tendremos que indicar, cuál será el nombre de nuestra aplicación (necesario a la hora de registrarse en el servidor Eureka) y donde se encuentra el Service Registry. Recordemos que vamos a utilizar el patrón Client‑Side Discovery, por tanto debe ser el cliente el que haga saber al servidor que está disponible. 

spring.application.name=app-camel-eureka-client
eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka/

Si ya arrancamos nuestra aplicación y accedemos al servidor Eureka en la ruta http://localhost:8761. Podremos ver que los dos Microservicios se encuentran disponibles y aparte algo de información sobre el propio servidor. 


Con esto ya podemos comprobar que nuestra infraestructura funciona, y gracias al servidor ubicar en cada momento a nuestros Microservicios. Ahora vamos a ver como podemos invocarlos dinámicamente desde Apache Camel, y vamos a verlo de dos formas diferentes. 

Para realizar la primera invocación dinámica vamos a hacer uso del componente de Apache Camel Service Call. A través del cual podremos hacer invocaciones a servicios remotos que estén registrados en un Service Registry. Tendremos que indicar el nombre del servicio y su recurso en este caso discovery-client y books

@Override
public void configure() throws Exception {
    restConfiguration().component("servlet").bindingMode(RestBindingMode.json);

    rest("/serviceCall").get().produces(MediaType.APPLICATION_JSON_VALUE).route()
    .serviceCall("discovery-client/books?bridgeEndpoint=true")
    //Is it becouse http endpoint produces a Stream as the body and once the stream is read, it is no longer available.
    .convertBodyTo(String.class)
    .log("Body: ${body}").unmarshal().json();
}

De esta forma no tendremos que configurar la URL del Microservicio a invocar, solo debemos conocer cuál es su identificador en el Service Registry. 

También podremos realizar esta llamada a través de una instancia de DiscoveryClient, utilidad de Spring Boot. El cual dado un identificador de un Microservicio, nos indicará su URI y otros valores asociados a ella. 

public static final String URL_DISCOVER_BOOKS = "%s/books?bridgeEndpoint=true";

@Autowired
private DiscoveryClient dClient;

@Override
public void configure() throws Exception {
    restConfiguration().component("servlet").bindingMode(RestBindingMode.json);

    rest("/discoveryCall").get().produces(MediaType.APPLICATION_JSON_VALUE).route()
    .to(String.format(URL_DISCOVER_BOOKS, dClient.getInstances("discovery-client").get(0).getUri()))
//Is it becouse http endpoint produces a Stream as the body and once the stream is read, it is no longer available. .convertBodyTo(String.class) .log("Body: ${body}").unmarshal().json(); }

Como siempre podéis ver que con Apache Camel, Spring Boot y todos los starters podemos realizar grandes cosas y fácilmente. Si quereis podeis ver todo el código aquí

No hay comentarios:

Publicar un comentario