Cómo Crear Microservicios con Spring Cloud y Spring Cloud Netflix

C

La arquitectura de microservicios ha ganado gran popularidad en los últimos tiempos. Con ella se logra conseguir simplicidad en nuestros servicios y así se garantiza un mantenimiento menos complejo. Hoy, Will Manuel Leyton, nos muestra la implementación de microservicios con Spring Cloud y Spring Cloud Netflix.

Netflix OSS y Spring Cloud lograron abstraer diversos  patrones (Api Gateway, Service Registry, Externalized Configuration, Circuit Breaker, Distributed Tracing, etc) que permiten que solo nos enfoquemos en desarrollar componentes específicos del dominio de nuestro negocio, ahorrandonos tiempo con esto.

Hoy realizaremos la implementación de microservicios con los stacks de Spring Cloud y Spring Cloud Netflix, el cual encapsula los componentes más populares de Netflix OSS y se integra con aplicaciones Spring Boot.

Pre – Requisitos

  1. Java >= 8.
  2. Git.
  3. Gradle.
  4. Conocimiento en Spring Boot.
  5. Cuenta GitHub
  6. IDE para Java (Eclipse, IntellIJ, etc).
  7. Lombok
  8. Internet.
 

Flujo de Aprendizaje

1. Desarrollar Service Registry con Eureka.
2. Desarrollar Configuration Server con Spring Cloud Config.
3. Desarrollar API Gateway con Zuul.
4. Desarrollar Microservicios.

 

  • Microservicio greeting-service
  • Microservicio meddle-service
5. Implementar Circuit Breaker para Fallos con Hystrix.
6. Implementar Trazabilidad con Sleuth.

1. Desarrollo de Service Registry con Eureka

El patrón service registry permite que los diferentes servicios e instancias se registren en un servidor que actúa como una base de datos, la cual es consultada mediante un API y se logra descubrir instancias basados en un identificador, Eureka es un servidor de registro diseñado por Netflix OSS.

Para desarrollar el servidor eureka debemos seguir los siguientes pasos:

  1. Dirigirnos a Spring initializr: https://start.spring.io
  2. Crear proyecto register-server con las siguientes especificaciones:

 

 

 

Donde seleccionaremos las dependencias: Eureka Server, Actuator y DevTools y luego daremos click en botón Generate Project, lo cual descargara un proyecto.

  1. Importar Proyecto gradle en nuestro IDE.
  2. Anotar clase lanzadora RegisterServerApplication con @EnableEurekaServer para habilitar un servidor de registro:
  1. @EnableEurekaServer
  2. @SpringBootApplication
  3. public class RegisterServerApplication {
  4.  
  5.     public static void main(String[] args) {
  6.         SpringApplication.run(RegisterServerApplication.class, args);
  7.     }
  8. }
  1. Renombrar archivo application.properties por bootstrap.yml y agregar:
  1. server:
  2.   port: ${EUREKA_PORT:8761}
  3.  
  4. spring:
  5.   application:
  6.     name: register-server
  7.   
  8. eureka:
  9.   client:
  10.     register-with-eureka: false
  11.     fetch-registry: false

Donde se configura el puerto, el nombre de la aplicación y el no registro en el servidor de registro.

2. Desarrollar Configuration Server con Spring Cloud Config

El patrón externalized configuration permite externalizar toda la configuración de las aplicaciones, como las credenciales, etc.

Spring Cloud Config Server es un servidor que permite externalizar la configuración basada en archivos de propiedades en repositorios git, base de datos, etc.

Para desarrollar el servidor de configuración debemos seguir los siguientes pasos:

  1. Crear repositorio config-repo en GitHub, GitLab, etc.
  2. Agregar archivo application.yml en config-repo, el cual servirá como configuración global para todos los microservicios conectados al servidor de configuración y agregar la siguiente configuración:
  1. eureka:
  2.   client:
  3.     service-url:
  4.       defaultZone: ${EUREKA_URI:http://localhost:${EUREKA_PORT:8761}/eureka}
  5.     register-with-eureka: true
  1. Realizar commit y push para empujar los cambios al repositorio remoto de GitHub.
  2. Dirigirnos a spring initializr: https://start.spring.io
  3. Crear proyecto config-server con las siguientes especificaciones:

 

 

 

  1. Donde seleccionaremos las dependencias: Config Server, Eureka Discovery Client, Actuator y DevTools y luego daremos click en botón Generate Project, lo cual descargara un proyecto.
  2. Importar Proyecto gradle en nuestro IDE.
  3. Anotar clase lanzadora ConfigServerApplication con @EnableDiscoveryClient  para habilitar la funcionalidad de cliente del servidor de registro Eureka:
  1. @EnableConfigServer
  2. @EnableDiscoveryClient
  3. @SpringBootApplication
  4. public class ConfigServerApplication {
  5.  
  6.     public static void main(String[] args) {
  7.         SpringApplication.run(ConfigServerApplication.class, args);
  8.     }
  9. }
  1. Renombrar archivo application.properties por bootstrap.yml y agregar:
  1. server:
  2.   port: ${CONFIG_PORT:8888}
  3.  
  4. spring:
  5.   application:
  6.     name: config-server
  7.   cloud:
  8.     config:
  9.       server:
  10.         git:
  11.           uri: ${CONFIG_REPO_URI}
  12.           username: ${CONFIG_REPO_USERNAME}
  13.           password: ${CONFIG_REPO_PASSWORD}
  14.   
  15. eureka:
  16.   client:
  17.     service-url:
  18.       defaultZone: ${EUREKA_URI:http://localhost:${EUREKA_PORT:8761}/eureka}
  19.     register-with-eureka: true

Donde se configura el puerto, nombre de la aplicación, servidor de registro, el servidor de configuración basado en su application name y las credenciales del repositorio, el cual brindará los archivos de configuración.

 

La variable de entorno ${CONFIG_REPO_URI} es la url http del repositorio config-repo creado en GitHub, ${CONFIG_REPO_USERNAME} y ${CONFIG_REPO_PASSWORD} son las credenciales para acceder al repositorio.

3. Desarrollar API Gateway con Zuul

El patron api gateway permite crear una puerta de enlace desde sistemas externos a nuestro clouster de API’s, basado en enrrutamiento por identificador de microservicio (application name propertie), Zuul es un servidor gateway diseñado por Netflix OSS.

Para desarrollar el Api Gateway debemos seguir los siguientes pasos:

  1. Dirigirnos a spring initializr
  2. Crear proyecto api-gateway con las siguientes especificaciones:

 

 

Donde seleccionaremos las dependencias: Zuul, Eureka Discovery Client, Config Client, Actuator y DevTools y luego daremos click en botón Generate Project, lo cual descargara un proyecto.

  1. Importar Proyecto gradle en nuestro IDE.
  2. Anotar clase lanzadora ApiGatewayApplication con @EnableZuulProxy para habilitar la funcionalidad de gateway y @EnableDiscoveryClient  para habilitar la funcionalidad de cliente del servidor de registro Eureka:
  1. @EnableZuulProxy
  2. @EnableDiscoveryClient
  3. @SpringBootApplication
  4. public class ApiGatewayApplication {
  5.  
  6.     public static void main (String[] args) {
  7.         SpringApplication.run(ApiGatewayApplication.class, args);
  8.     }
  9. }
  1. Renombrar archivo application.properties por bootstrap.yml y agregar:
  1. server:
  2.   port: ${GATEWAY_PORT:9090}
  3.  
  4. spring:
  5.   application:
  6.     name: api-gateway
  7.   cloud:
  8.     config:
  9.       discovery:
  10.         enabled: true
  11.         service-id: config-server

Donde se configura el puerto, nombre de la aplicación, servidor de configuración basado en su application name, el cual brindará los archivos de configuración.

  1. Crear archivo api-gateway.yml en config-repo y agregar en el archivo:
  1. zuul:
  2.   prefix: /api

Donde se configura el prefijo con el que se resolverán las peticiones desde sistemas externos.

  1. Realizar commit y push para empujar los cambios al repositorio remoto de GitHub.

4. Desarrollar Microservicios

4.1. Microservicio greeting-service

 

Desarrollaremos un microservicio que exponga un controlador que devuelva un saludo, el cual se registrará en el register-server y buscará su configuración en config-server. Para desarrollar el microservicio debemos seguir los siguientes pasos:

 

  1. Agregar archivo greeting-service.yml en config-repo, el cual servirá como configuración en el perfil default para el microservicio greeting-service y agregar la siguiente configuración:
  1. greeting:
  2.   message: Hello
  1. Realizar commit y push para empujar los cambios al repositorio remoto de GitHub.
  2. Dirigirnos a spring initializr: https://start.spring.io
  3. Crear proyecto greeting-service con las siguientes especificaciones:

 

  1. Donde seleccionaremos las dependencias: Eureka Discovery Client, Config Client, Web, Lombok, Actuator y DevTools y luego daremos click en botón Generate Project, lo cual descargara un proyecto.
  2. Importar Proyecto gradle en nuestro IDE.
  3. Anotar clase lanzadora GreetingServiceApplication con @EnableDiscoveryClient  para habilitar la funcionalidad de cliente del servidor de registro Eureka:
  1. @EnableDiscoveryClient
  2. @SpringBootApplication
  3. public class GreetingServiceApplication {
  4.  
  5.     public static void main(String[] args) {
  6.         SpringApplication.run(GreetingServiceApplication.class, args);
  7.     }
  8. }
  1. Renombrar archivo application.properties por bootstrap.yml y agregar:
  1. server:
  2.   port: ${GREETING_PORT:8080}
  3.  
  4. spring:
  5.   application:
  6.     name: greeting-service
  7.   cloud:
  8.     config:
  9.       discovery:
  10.         enabled: true
  11.         service-id: config-server
  1. Crear paquete dto y agregar clase GreetingResponse:
  1. @Getter
  2. @Setter
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. public class GreetingResponse {
  6.  
  7.     private String message;
  8. }
  1. Crear paquete service.inter y agregar interface GreetingService:
  1. public interface GreetingService {
  2.  
  3.     GreetingResponse greeting(String name);
  4. }
  1. Crear paquete service.impl y agregar implementación GreetingServiceImp:
  1. @Service
  2. public class GreetingServiceImp implements GreetingService {
  3.  
  4.     @Value(
  5.             value = «${greeting.message}»)
  6.     String baseMessage;
  7.  
  8.     @Override
  9.     public GreetingResponse greeting(String name) {
  10.         String message = baseMessage + » « + name;
  11.         return new GreetingResponse(message);
  12.     }
  13. }
  1. Crear paquete controller y agregar interface GreetingController:
  1. @RestController
  2. @AllArgsConstructor
  3. @RequestMapping(
  4.         value = {
  5.             «/greeting»
  6.         })
  7. public class GreetingController {
  8.  
  9.     private GreetingService greetingService;
  10.  
  11.     @GetMapping
  12.     public ResponseEntity<GreetingResponse> greeting(@RequestParam(
  13.             value = «name») String name) {
  14.         return ResponseEntity.ok(greetingService.greeting(name));
  15.     }
  16. }

 

4.2. Microservicio middle-service

 

Desarrollaremos un microservicio que exponga un controlador que permita comunicarnos con greeting-service. El microservicio se registrará en el register-server y buscará su configuración en config-server.

Para desarrollar el microservicio debemos seguir los siguientes pasos:

  1. Agregar archivo middle-service.yml en config-repo, el cual servirá como configuración en el perfil default para el microservicio middle-service.
  2. Realizar commit y push para empujar los cambios al repositorio remoto de GitHub.
  3. Dirigirnos a spring initializr
  4. Crear proyecto middle-service con las siguientes especificaciones:

 

 

 

  1. Donde seleccionaremos las dependencias: Eureka Discovery Client, Config Client, Web, Lombok, Ribbon, Actuator y DevTools y luego daremos click en botón Generate Project, lo cual descargara un proyecto.
  2. Importar Proyecto gradle en nuestro IDE.
  3. Anotar clase lanzadora MiddleServiceApplication con @EnableDiscoveryClient  para habilitar la funcionalidad de cliente del servidor de registro Eureka:
  1. @EnableHystrix
  2. @EnableDiscoveryClient
  3. @SpringBootApplication
  4. public class MiddleServiceApplication {
  5.  
  6.     public static void main(String[] args) {
  7.         SpringApplication.run(MiddleServiceApplication.class, args);
  8.     }
  9. }
  1. Renombrar archivo application.properties por bootstrap.yml y agregar:
  1. server:
  2.   port: ${MIDDLE_PORT:8090}
  3.  
  4. spring:
  5.   application:
  6.     name: middle-service
  7.   cloud:
  8.     config:
  9.       discovery:
  10.         enabled: true
  11.         service-id: config-server
  1. Crear paquete configuration y agregar clase AppConfiguration, donde configuraremos el bean RestTemplate anotado con @LoadBalanced para permitir el balanceo mediante ribbon y la lista de instancias suministrada por el register-server:
  1. @Configuration
  2. public class AppConfiguration {
  3.  
  4.     @Bean
  5.     @LoadBalanced
  6.     public RestTemplate restTemplate(RestTemplateBuilder builder) {
  7.         return builder.build();
  8.     }
  9. }
  1. Crear paquete dto y agregar clase GreetingResponse:
  1. @Getter
  2. @Setter
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. public class GreetingResponse {
  6.  
  7.     private String message;
  8. }
  1. Crear paquete service.inter y agregar interface GreetingClient:
  1. public interface GreetingClient {
  2.  
  3.     GreetingResponse greeting(String name);
  4. }
  1. Crear paquete service.impl y agregar implementación GreetingClientImp:
  1. @Service
  2. @AllArgsConstructor
  3. public class GreetingClientImp implements GreetingClient {
  4.  
  5.     private static final String NAME_PARAM_KEY = «name»;
  6.  
  7.     private static final String GREETING_SERVICE_URL = «http://greeting-service/greeting?name={name}»;
  8.  
  9.     private RestTemplate restTemplate;
  10.  
  11.     @Override
  12.     public GreetingResponse greeting(String name) {
  13.         Map<String, Object> parameters = new HashMap<>();
  14.         parameters.put(NAME_PARAM_KEY, name);
  15.         return restTemplate.getForObject(GREETING_SERVICE_URL, GreetingResponse.class, parameters);
  16.     }
  17. }
  1. Crear paquete controller y agregar interface MiddleController:
  1. @RestController
  2. @AllArgsConstructor
  3. @RequestMapping(
  4.         value = {
  5.             «/middle»
  6.         })
  7. public class MiddleController {
  8.  
  9.     private GreetingClient greetingClient;
  10.  
  11.     @GetMapping(
  12.             value = {
  13.                 «/greeting»
  14.             })
  15.     public ResponseEntity<GreetingResponse> greeting(@RequestParam(
  16.             value = «name») String name) {
  17.         return ResponseEntity.ok(greetingClient.greeting(name));
  18.     }
  19. }

 

5. Implementar Circuit Breaker para Fallos con Hystrix

Cuando nos comunicamos con diferentes sistemas es posible que se presenten fallos y estos se propaguen, afectando nuestro sistema y generando un potencial consumo de recursos, por lo cual el patrón circuit breaker nos ayuda con este tipo de problema.

Circuit breaker funciona abriendo un cortocircuito cuando se alcanza un umbrall de fallos consecutivos, este cortocircuito realiza un llamado a una función fallback, logrando que no gastemos recursos en los siguientes intentos de llamado hasta que el circuito pase al estado de medio abierto, donde se realizará nuevos intentos hacia el sistema externo, en el que si se presenta un fallo se vuelve abrir el cortocircuito, realizaremos la implementación de este patrón con la librería Hystrix de NetflixOSS en el microservicio middle-service:

 

  1. Agregar dependencia de Hystrix en nuestro archivo build.gradle del microservicio middle-service:

implementation ‘org.springframework.cloud:spring-cloud-starter-netflix-hystrix’

 

  1. Actualizar  clase GreetingClientImp agregando HystrixCommand y método fallback:
  1. @Service
  2. @AllArgsConstructor
  3. public class GreetingClientImp implements GreetingClient {
  4.  
  5.     private static final String NAME_PARAM_KEY = «name»;
  6.  
  7.     private static final String GREETING_SERVICE_URL = «http://greeting-service/greeting?name={name}»;
  8.  
  9.     private RestTemplate restTemplate;
  10.  
  11.     @Override
  12.     @HystrixCommand(
  13.             fallbackMethod = «greetingFallback»)
  14.     public GreetingResponse greeting(String name) {
  15.         Map<String, Object> parameters = new HashMap<>();
  16.         parameters.put(NAME_PARAM_KEY, name);
  17.         return restTemplate.getForObject(GREETING_SERVICE_URL, GreetingResponse.class, parameters);
  18.     }
  19.  
  20.     public GreetingResponse greetingFallback(String name) {
  21.         return new GreetingResponse(name + «, an error occurred»);
  22.     }
  23. }

6. Implementar Trazabilidad con Sleuth

El patrón distributed tracing permite realizar seguimiento a los flujos de peticiones entre nuestros diferentes componentes de la arquitectura montada, agregando ID’s para identificación de la petición que se pueden identificar en los log’s:

 

  1. Agregar dependencia de Sleuth en nuestros archivos build.gradle de api-gateway, greeting-service y middle-service :

implementation ‘org.springframework.cloud:spring-cloud-starter-sleuth’

7. Correr Aplicaciones

  1. Correr register-server.
  2. Correr config-server.
  3. Correr api-gateway.
  4. Correr greeting-service.
  5. Correr middle-service.
  6. Test:

curl X GET ‘http://localhost:9090/api/middle-service/middle/greeting?name=YourName’ H ‘cache-control: no-cache’

Conclusión

Los componentes proporcionados por Spring Cloud y Spring Cloud Netflix nos facilitan la implementación de los más populares patrones para la construcción de microservicios, ahorrandonos tiempo de codificación y garantizando estabilidad, pues sus componentes presentan alta acogida en la comunidad de desarrolladores.

Ofrece tus servicios a clientes internacionales. Conecta sin comisiones 🚀

Will Manuel Leyton
Por Will Manuel Leyton

Entradas recientes