🌐 Netflix Eureka Cheatsheet Completo 🌐
Netflix Eureka es un servicio de descubrimiento de servicios basado en REST que permite a los microservicios registrarse en una ubicación central y luego descubrir otros servicios para comunicarse con ellos. Es parte del ecosistema de Spring Cloud y un componente clave en la construcción de arquitecturas de microservicios resilientes.
1. 🌟 Conceptos Clave
- Service Discovery (Descubrimiento de Servicios): El proceso mediante el cual los microservicios encuentran la ubicación de otros microservicios con los que necesitan comunicarse. En un entorno dinámico de microservicios (escalado, reinicio, fallos), las direcciones IP pueden cambiar constantemente.
- Eureka Server (Servidor de Eureka): El componente central que actúa como un registro de servicios. Los clientes de Eureka (microservicios) se registran en él y le envían “heartbeats” (latidos) para indicar que están vivos.
- Eureka Client (Cliente de Eureka): Cualquier microservicio que se registra en el Eureka Server o que consulta el Eureka Server para encontrar otros servicios.
- Registro (Registration): Cuando un Eureka Client se inicia, se registra en el Eureka Server, proporcionando su ID de instancia, URL de servicio y metadatos.
- Heartbeat (Latido): Los Eureka Clients envían periódicamente señales al Eureka Server para informarle que están vivos y en buen estado. Si un cliente no envía latidos, el servidor lo desregistra.
- Búsqueda (Discovery): Los clientes de Eureka consultan el Eureka Server para obtener una lista de instancias de un servicio deseado.
- Cache de Cliente: Los Eureka Clients mantienen una copia en caché del registro de servicios para reducir la carga en el servidor y permitir el descubrimiento incluso si el servidor no está disponible temporalmente.
- Resistencia a la Zona de Disponibilidad (Availability Zone Awareness): Eureka puede ser configurado para ser consciente de las zonas de disponibilidad de la nube, prefiriendo instancias de servicios en la misma zona para reducir la latencia.
2. 🛠️ Configuración Inicial (Spring Boot)
2.1. Configuración del Eureka Server (Registro de Servicios)
-
Añadir dependencias en
pom.xml:<dependencies> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> <relativePath/> </parent> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!-- Spring Cloud BOM (para gestionar versiones de Spring Cloud) --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2023.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </dependencies> -
Habilitar Eureka Server en la clase principal:
// src/main/java/com/example/eurekaserver/EurekaServerApplication.java package com.example.eurekaserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; // Habilita el servidor @SpringBootApplication @EnableEurekaServer // Anotación clave para habilitar el servidor Eureka public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } -
Configurar
application.yml(para el servidor Eureka):# src/main/resources/application.yml server: port: 8761 # Puerto por defecto de Eureka Server eureka: instance: hostname: localhost # Nombre del host donde se ejecuta este servidor client: register-with-eureka: false # El servidor Eureka NO se registra a sí mismo fetch-registry: false # El servidor Eureka NO intenta buscar otros servicios service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # URL para que los clientes se conecten- Iniciar la aplicación. Accede a la UI de Eureka en
http://localhost:8761.
- Iniciar la aplicación. Accede a la UI de Eureka en
2.2. Configuración del Eureka Client (Registro de Microservicios)
-
Añadir dependencias en
pom.xml(en el microservicio):<dependencies> <parent>...</parent> <!-- Tu parent de Spring Boot --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- Spring Cloud BOM --> <dependencyManagement>...</dependencyManagement> </dependencies> -
Habilitar Eureka Client en la clase principal (opcional a partir de Spring Boot 2.x):
- Spring Boot habilita el cliente automáticamente si está en el classpath.
@EnableDiscoveryCliento@EnableEurekaClient(deprecated) ya no son estrictamente necesarios.
// src/main/java/com/example/myservice/MyServiceApplication.java package com.example.myservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; // @EnableDiscoveryClient // Opcional, pero puede ser útil para claridad // @EnableEurekaClient // Específico de Eureka, si no quieres usar el genérico @EnableDiscoveryClient @SpringBootApplication public class MyServiceApplication { public static void main(String[] args) { SpringApplication.run(MyServiceApplication.class, args); } } -
Configurar
application.yml(para el microservicio cliente):# src/main/resources/application.yml spring: application: name: my-product-service # ¡CRÍTICO! El nombre del servicio que se registrará en Eureka server: port: 8080 # Puerto de este microservicio eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ # URL del Eureka Server register-with-eureka: true # Este cliente se registra en Eureka (default: true) fetch-registry: true # Este cliente obtiene el registro de Eureka (default: true) instance: hostname: localhost instance-id: ${spring.application.name}:${instanceId:${random.value}} # ID único de la instancia (útil para múltiples instancias) lease-renewal-interval-in-seconds: 10 # Frecuencia de envío de heartbeats (default: 30) lease-expiration-duration-in-seconds: 30 # Tiempo para que el servidor considere inactiva una instancia si no hay heartbeat (default: 90) # Prefer-ip-address: true # Para registrar la IP en lugar del hostname (útil en entornos de Docker/Kubernetes)- Iniciar la aplicación. Deberías verla registrada en la UI del Eureka Server.
3. 🚀 Descubrimiento de Servicios (Consumo)
Una vez que los servicios están registrados, otros microservicios pueden descubrir y llamar a sus instancias.
3.1. Usando DiscoveryClient (Manualmente)
// src/main/java/com/example/myservice/DiscoveryService.java
package com.example.myservice;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DiscoveryService {
private final DiscoveryClient discoveryClient; // Inyecta DiscoveryClient
public DiscoveryService(DiscoveryClient discoveryClient) {
this.discoveryClient = discoveryClient;
}
public String getProductServiceBaseUrl() {
List<ServiceInstance> instances = discoveryClient.getInstances("my-product-service"); // Nombre del servicio
if (instances != null && !instances.isEmpty()) {
ServiceInstance serviceInstance = instances.get(0); // Tomar la primera instancia disponible
return serviceInstance.getUri().toString(); // Obtener la URI base
}
return null;
}
}
3.2. Usando RestTemplate con @LoadBalanced (Cliente HTTP)
@LoadBalancedintegra Ribbon (cliente-side load balancing) con Eureka.
// src/main/java/com/example/myservice/AppConfig.java
package com.example.myservice;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppConfig {
@Bean
@LoadBalanced // Anotación clave para habilitar Ribbon/LoadBalancer con Eureka
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
// src/main/java/com/example/myservice/ProductServiceClient.java
package com.example.myservice;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ProductServiceClient {
private final RestTemplate restTemplate;
public ProductServiceClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getProductDetails(String productId) {
// Usa el nombre del servicio registrado en Eureka, NO el hostname:port
String url = "http://my-product-service/api/products/" + productId;
return restTemplate.getForObject(url, String.class);
}
}
3.3. Usando WebClient con @LoadBalanced (Cliente HTTP Reactivo)
- Para aplicaciones Spring WebFlux.
// src/main/java/com/example/myservice/AppConfig.java
package com.example.myservice;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class AppConfig {
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
// src/main/java/com/example/myservice/ProductServiceClient.java
package com.example.myservice;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
@Service
public class ProductServiceClient {
private final WebClient.Builder webClientBuilder;
public ProductServiceClient(@LoadBalanced WebClient.Builder webClientBuilder) { // Inyecta el builder LoadBalanced
this.webClientBuilder = webClientBuilder;
}
public Mono<String> getProductDetails(String productId) {
// Usa el nombre del servicio registrado en Eureka
return webClientBuilder.build().get()
.uri("http://my-product-service/api/products/{id}", productId) // WebClient usa el nombre del servicio
.retrieve()
.bodyToMono(String.class);
}
}
3.4. Usando FeignClient (Declarativo - Recomendado para REST)
FeignClientpermite definir interfaces declarativas para clientes REST, manejando la comunicación HTTP y el descubrimiento de servicios.
- Añadir dependencia en
pom.xml:<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> - Habilitar Feign en la clase principal (del cliente Feign):
// src/main/java/com/example/myservice/MyServiceApplication.java import org.springframework.cloud.openfeign.EnableFeignClients; // Habilita Feign @SpringBootApplication @EnableFeignClients // Anotación clave public class MyServiceApplication { /* ... */ } - Definir la interfaz Feign Client:
// src/main/java/com/example/myservice/client/ProductFeignClient.java package com.example.myservice.client; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; // 'my-product-service' es el nombre del servicio registrado en Eureka @FeignClient(name = "my-product-service") public interface ProductFeignClient { @GetMapping("/api/products/{id}") String getProductById(@PathVariable("id") String id); // Los nombres de los parámetros deben coincidir } - Inyectar y usar Feign Client:
// src/main/java/com/example/myservice/ProductConsumerService.java package com.example.myservice; import com.example.myservice.client.ProductFeignClient; import org.springframework.stereotype.Service; @Service public class ProductConsumerService { private final ProductFeignClient productFeignClient; public ProductConsumerService(ProductFeignClient productFeignClient) { this.productFeignClient = productFeignClient; } public String getProductInfo(String productId) { return productFeignClient.getProductById(productId); } }
4. 🌐 Alta Disponibilidad y Resiliencia (Eureka Cluster)
- Para evitar un Single Point of Failure (SPOF), puedes ejecutar múltiples instancias de Eureka Server.
- Cada Eureka Server se registra con los otros Eureka Servers (peer-to-peer replication).
- Los clientes pueden configurar múltiples
defaultZoneURLs.
# application.yml para Eureka Server A
server:
port: 8761
eureka:
instance:
hostname: eureka-server-a
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka-server-b:8762/eureka/ # Se registra con el peer B
# application.yml para Eureka Server B
server:
port: 8762
eureka:
instance:
hostname: eureka-server-b
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka-server-a:8761/eureka/ # Se registra con el peer A
# application.yml para un cliente (apunta a ambos)
eureka:
client:
service-url:
defaultZone: http://eureka-server-a:8761/eureka/,http://eureka-server-b:8762/eureka/
5. 💡 Buenas Prácticas y Consejos
- Nombre de Servicio Único (
spring.application.name): Es el identificador principal de tu microservicio en Eureka. Asegúrate de que sea único y descriptivo. - Heartbeat y
eviction: Ajustalease-renewal-interval-in-seconds(cliente) ylease-expiration-duration-in-seconds(servidor) según la tolerancia de tu sistema a instancias “muertas” pero aún registradas. - “Prefer-IP-Address”: En entornos de contenedor (Docker, Kubernetes) donde los hostnames internos no son fiables o las IPs son más directas, considera
eureka.instance.prefer-ip-address=true. - Zona de Disponibilidad (AZ) Awareness: En la nube, configura Eureka para ser consciente de las AZs. Los clientes prefieren llamar a servicios en su misma AZ para reducir latencia y costos.
- Deshabilita el Registro del Servidor: El Eureka Server no debe registrarse a sí mismo como cliente (
register-with-eureka: false,fetch-registry: false). - Usa
FeignClientpara Clientes REST: Simplifica drásticamente la creación de clientes REST declarativos y maneja el descubrimiento de servicios y el balanceo de carga automáticamente. - Hystrix / Resilience4j (Circuit Breakers): Combina Eureka con librerías de resiliencia como Resilience4j (sucesor de Hystrix). Esto evita cascadas de fallos en arquitecturas de microservicios.
- Dashboard de Eureka: Monitorea el estado de tus servicios registrados a través de la UI de Eureka Server.
- Evita la Inyección Directa de
DiscoveryClient: Aunque es posible, es mejor usar abstracciones de nivel superior como@LoadBalanced RestTemplate,WebClient.Builder, oFeignClientpara el consumo de servicios. - Registros Dinámicos (Netflix Sidecar): Para registrar servicios no JVM en Eureka (requiere una configuración más avanzada).
Este cheatsheet te proporciona una referencia completa de Netflix Eureka, cubriendo sus conceptos esenciales, cómo configurarlo como servidor y cliente, las diferentes formas de consumir servicios, la alta disponibilidad y las mejores prácticas para implementar un descubrimiento de servicios robusto en arquitecturas de microservicios.