martes, 19 de junio de 2018

EUREKA - RIBBON - Client Load Balancing (II)

Vamos con RIBBON.

Los que no lo hayan visto la primera entrada deberán inexcusablemente hacerlo, ya que para que lo que aquí compartimos funcione necesita de EUREKA, y es en dicha primera entrada donde se explica.

En la tercera desplegaremos todos los elementos en un entorno docker.

En la cuarta lo haremos sobre un entorno kubernetes.

El código de ambos micorservicios lo tenéis en microservicio1 y microservicio2.


Primer microservicio

Mostramos los detalles del primer microservicio, el que hará de "servidor" y recibirá peticiones del segundo.


pom.xml

Sólo mostramos la dependencia que nos permite registrarlo en EUREKA

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



application.yml

Este es su contenido:

    spring:
      application:
        name: client-one-load-balancing
      profiles:
        active: des

    eureka:
      client:
        enabled: true
        service-url:
          defaultZone: http://localhost:8761/eureka/
      instance: 
        leaseRenewalIntervalInSeconds: 1
        leaseExpirationDurationInSeconds: 1

Lo importante para esta entrada es la configuración de acceso a eureka. 
Habilitamos la conexión, indicando la url del server.

Por defecto, cuando un microservicio se registra en eureka, cada 30 segundos lanza un ping para indicar que está activo. Eureka no se da por enterado del nuevo microservicio hasta tres pings, por tanto 90 segundos. 

Con "leaseRenewalIntervalInSeconds: 1" indicamos que nos basta con uno para darlo por activo.

Igualmente, hasta que no pasan 3 intervalos de 30 segundos sin recibir ping del cliente, eureka no lo hace desaparecer del registro. 

Con "leaseExpirationDurationInSeconds: 1" indicamos que con un intervalo basta para "des-registrarlo". 


java

En la clase main, añadimos la anotación "@EnableEurekaClient" a la cabecera, juntamente con la habitual "@SpringBootApplication".

Para dar servicio hemos declarado un endpoint "/saludo" y otro para la raíz "/", dentro de la clase MainController (anotade la clase con "@RestController")

    @Value("${server.port}")
    String puerto;

    @RequestMapping(value = "/saludo")
    public String greet() {
log.info("Acceso /saludo");

List<String> greetings = Arrays.asList("Hola", "Saludos", "Saludos cordiales");
Random rand = new Random();

int randomNum = rand.nextInt(greetings.size());
        String retorno = greetings.get(randomNum);
        return retorno + ", desde puerto " + puerto;
    }

    @RequestMapping(value = "/")
    public String home() {
log.info("Acceso /");
return "Hola!";
    }


Arranque

Arrancaremos tres réplicas del mismo microservicio. Para hacerlo de la misma forma con los tres arranques los lanzaremos desde línea de comandos. 

Abrimos cmd de windows y nos vamos al directorio raíz del proyecto, donde está ubicado el pom.xml. Nos aseguramos que el JAVA_HOME apunta al jdk 8 (echo %JAVA_HOME%). Si no es así deberemos setear dicha variable en cada una de las consolas (set JAVA_HOME=C:\XXXXXXXX). Por ejemplo en mi caso he de hacer 

    set JAVA_HOME=C:\Java\java8_131

Una vez hecho esto lanzamos los siguientes comandos, uno por cada consola

    mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=8090
    mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=8091
    mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=8092

Ya tenemos nuestro primer microservicio levantado y respondiendo a los puertos 8090, 8091 y 8092. 



Podemos validarlo a partir de la url

    http://localhost:8090/saludo
    http://localhost:8091/saludo
    http://localhost:8092/saludo

Veremos que en cada una pone un literal al azar de cualquiera de estos 

    "Hola", "Saludos", "Saludos cordiales"

  añadiendo el puerto activo.

Vemos en el dashboard de eureka nuestros tres microservicios


Los tres registados bajo el nombre "client-one-load-balancing". Este nombre es importante!!!!

Vamos con el segundo microservicio


Segundo microservicio

Estos son los detalles del segundo microservicio, el que hace de cliente.

pom.xml

Necesitamos las siguientes dependencias

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

La específica en este caso es la dependencia de ribbon. La de eureka cliente es como en el primer microservicio.


application.yml

Esta es nuestra configuración usando Ribbon con nombres de servicio suminstrados por Eureka:

     server:
      port: 9999
  
    spring:
      application:
        name: client-two-load-balancing
      profiles:
        active: des

    client-one-load-balancing:
      ribbon:
        #eureka:
          #enabled: false
        listOfServers: client-one-load-balancing:8090,client-one-load-balancing:8091,client-one-load-balancing:8092
        #listOfServers: localhost:8090,localhost:8091,localhost:8092
        ServerListRefreshInterval: 15000
    
    eureka:
      client:
        enabled: true
        service-url:
          defaultZone: http://localhost:8761/eureka/
      instance: 
        leaseRenewalIntervalInSeconds: 1
        leaseExpirationDurationInSeconds: 1

Remarcamos en negrita lo específico de este segundo microservicio.
Vemos el nombre "client-one-load-balancing", que es el nombre de registro del microservicio uno. Vemos también la lista de servers "listOfServers" con los tres servicios levantados, cada uno con su puerto, y de nuevo, en lugar de dominio o ip, vemos el nombre de registro en eureka.

El atributo "ServerListRefreshInterval: 15000" indica, en milisegundos, el intervalo entre ping y ping lanzado desde el microservicio dos a los microservicios "unos".


NOTA:
Si quisiésemos trabajar sin EUREKA deberíamos quitar los comentarios de

       eureka:
          enabled: false
          listOfServers: localhost:8090,localhost:8091,localhost:8092

y comentar:

       #listOfServers: client-one-load-balancing:8090,client-one-load-balancing:8091,client-one-load-balancing:8092

ya que en ese caso no habría ningún servidor de registro que habilite el descubrimiento de nombres.

Deberíamos también eliminar la configuración de EUREKA y la anotación "@EnableEurekaClient" del Application.java de ambos microservicios.

Asimismo deberíamos eliminar la dependencia siguiente de ambos microservicios.

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


java

En la parte java, usaremos la anotación "@EnableEurekaClient" de la misma forma que en el microservicio uno.

Añadimos una clase de configuración que nos exige ribbon para realizar el blanceo y los "pings". Podéis verla tras la descarga del código del gitlab.

El MainController tiene ciertas particularidades. Pego la clase completa


    @RestController
    @RibbonClient(name = "client-one-load-balancing", configuration = Configuration.class)
    public class MainController {

private static Logger log = LoggerFactory.getLogger(MainController.class);

@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}

@Autowired
RestTemplate restTemplate;

@RequestMapping("/hola")
public String hi(@RequestParam(value = "nombre", defaultValue = "Rigoberto") String nombre) {
log.info("parametro recibido: " + nombre);
String saludo = this.restTemplate.getForObject("http://client-one-load-balancing/saludo", String.class);
return String.format("%s, %s!", saludo, nombre);
}

    }

En negrita lo más importante. Se añade la anotación "@RibbonClient" apuntando al nombre del registro eureka del microservicio uno, indicando la clase de configuración comentada más arriba.

Se añade la antación "@LoadBalanced" al bean restTemplate para que haga balanceo a los microservicios declarados en la "listOfServers" del application.yml

Por último, se invoca al microservicio uno vía restTemplate, añadiendo a lo que devuelve aquel, el nombre recibido por parámteros.


Prueba

Arrancamos este segundo microservicio desde eclipse.

Lanzamos repetidamente la url "http://localhost:9999/hola?nombre=Antonio" (podéis cambiar el "nombre" a vuestro gusto.  Obtendremos diferentes resultados. Por ejemplo






Como se puede observar, estamos invocando al microservicio uno, el cual mediante ribbon balancea las peticiones llamando a cualquiera de los microservicios uno. En las capturas se ve graficamente por el puerto de respuesta.

A nivel de logs veremos las diferentes peticiones como van llegando a cualquier consola 

    Acceso /saludo

Cada 15 segundos se verá en cada una de las consolas un log del ping, que se realiza a la raíz, dejando esta traza

    Acceso /

Ahora podemos jugar.... paremos con "CTRL + C" cualquiera de los microservicios uno. Si lanzamos peticiones antes de los 15 segundos de intervalo entre ping's, es posible que alguna petición se dirija al mcroservicio parado dando un error de acceso. Si esperamos dichos 15 segundos veremos que ninguna petición llega al microservicio parado.

Paremos un segundo y hagamos lo mismo, ahora todas las peticiones se encamian al único microservicio uno activo.

Ahora hagamos al revés, id levantando uno a uno los microservicios uno parados, y pasado 15 segundos veremos que vuelve a estar activos, pudiendo recibir peticiones de forma correcta.

Y todo desde cliente.



Nuestro código

No hay comentarios:

Publicar un comentario