Eureka is a REST-based service registry for locating services in cloud environments. It enables service discovery in microservices architecture, allowing services to find and communicate with each other without hard-coded hostnames and ports.
Overview
- Eureka Server: Service registry that maintains a list of available service instances
- Eureka Client: Services that register themselves with Eureka and discover other services
- Service Discovery: Dynamic location of service instances in a distributed system
Dependencies
Maven Dependencies
<!-- Spring Cloud Dependencies Management --> <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> <!-- Eureka Server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!-- Eureka Client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- Spring Boot Web (for REST controllers) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Boot Actuator (for health checks) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- Config Client (if using Spring Cloud Config) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
Gradle Dependencies
plugins {
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
ext {
set('springCloudVersion', "2023.0.0")
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-config'
}
Eureka Server Implementation
Example 1: Basic Eureka Server
package com.example.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Example 2: Eureka Server Configuration
# application.yml for Eureka Server server: port: 8761 spring: application: name: eureka-server eureka: client: register-with-eureka: false # Don't register itself with Eureka fetch-registry: false # Don't fetch the registry from other Eureka servers service-url: defaultZone: http://localhost:8761/eureka/ server: enable-self-preservation: true # Prevents eviction of instances in case of network issues eviction-interval-timer-in-ms: 10000 # How often to check for expired instances renewal-percent-threshold: 0.85 # Threshold for self-preservation instance: hostname: localhost # Management endpoints management: endpoints: web: exposure: include: health,info,metrics endpoint: health: show-details: always
Example 3: High Availability Eureka Server
package com.example.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerHAApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerHAApplication.class, args);
}
// Disable security for Eureka dashboard (for development)
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll()
);
return http.build();
}
}
Example 4: Multi-Node Eureka Server Configuration
# application-peer1.yml - First Eureka Server Node spring: application: name: eureka-server profiles: peer1 server: port: 8761 eureka: instance: hostname: peer1 appname: eureka-server client: service-url: defaultZone: http://peer2:8762/eureka/,http://peer3:8763/eureka/ register-with-eureka: true fetch-registry: true --- # application-peer2.yml - Second Eureka Server Node spring: application: name: eureka-server profiles: peer2 server: port: 8762 eureka: instance: hostname: peer2 appname: eureka-server client: service-url: defaultZone: http://peer1:8761/eureka/,http://peer3:8763/eureka/ register-with-eureka: true fetch-registry: true --- # application-peer3.yml - Third Eureka Server Node spring: application: name: eureka-server profiles: peer3 server: port: 8763 eureka: instance: hostname: peer3 appname: eureka-server client: service-url: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/ register-with-eureka: true fetch-registry: true
Eureka Client Implementation
Example 5: Basic Service Registration
package com.example.orderservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
@RestController
@RequestMapping("/orders")
class OrderController {
@GetMapping("/{id}")
public Order getOrder(@PathVariable String id) {
return new Order(id, "Order " + id, 99.99);
}
@PostMapping
public Order createOrder(@RequestBody Order order) {
// Simulate order creation
return new Order("ORD-123", order.getDescription(), order.getAmount());
}
// Order DTO
public static class Order {
private String id;
private String description;
private double amount;
public Order() {}
public Order(String id, String description, double amount) {
this.id = id;
this.description = description;
this.amount = amount;
}
// getters and setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public double getAmount() { return amount; }
public void setAmount(double amount) { this.amount = amount; }
}
}
Example 6: Eureka Client Configuration
# application.yml for Order Service
spring:
application:
name: order-service # This is the service ID used for discovery
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
register-with-eureka: true
fetch-registry: true
enabled: true
instance:
instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
appname: ${spring.application.name}
hostname: localhost
prefer-ip-address: false
lease-renewal-interval-in-seconds: 30 # How often to send heartbeat
lease-expiration-duration-in-seconds: 90 # Time before instance is expired
metadata-map:
zone: primary
version: 1.0.0
environment: development
# Health check configuration
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
show-components: always
# Enable health checks for Eureka
eureka:
client:
healthcheck:
enabled: true
Service Discovery and Communication
Example 7: Service Discovery using DiscoveryClient
package com.example.orderservice.service;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@Service
public class ServiceDiscoveryService {
private final DiscoveryClient discoveryClient;
private final RestTemplate restTemplate;
public ServiceDiscoveryService(DiscoveryClient discoveryClient, RestTemplate restTemplate) {
this.discoveryClient = discoveryClient;
this.restTemplate = restTemplate;
}
// Get all available services
public List<String> getAvailableServices() {
return discoveryClient.getServices();
}
// Get instances of a specific service
public List<ServiceInstance> getServiceInstances(String serviceId) {
return discoveryClient.getInstances(serviceId);
}
// Get service URL for a specific service
public String getServiceUrl(String serviceId) {
List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
if (instances.isEmpty()) {
throw new RuntimeException("No instances available for service: " + serviceId);
}
// Simple round-robin (for demonstration)
ServiceInstance instance = instances.get(0);
return instance.getUri().toString();
}
// Call another service using discovery
public String callUserService(String userId) {
String userServiceUrl = getServiceUrl("user-service");
String url = userServiceUrl + "/users/" + userId;
return restTemplate.getForObject(url, String.class);
}
// Get service instances with metadata
public void printServiceInstances(String serviceId) {
List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
System.out.println("Instances for service: " + serviceId);
for (ServiceInstance instance : instances) {
System.out.println("Instance ID: " + instance.getInstanceId());
System.out.println("URI: " + instance.getUri());
System.out.println("Host: " + instance.getHost());
System.out.println("Port: " + instance.getPort());
System.out.println("Metadata: " + instance.getMetadata());
System.out.println("---");
}
}
}
Example 8: Using @LoadBalanced RestTemplate
package com.example.orderservice.config;
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 RestTemplateConfig {
@Bean
@LoadBalanced // Enables client-side load balancing
public RestTemplate loadBalancedRestTemplate() {
return new RestTemplate();
}
}
package com.example.orderservice.service;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class UserServiceClient {
private final RestTemplate restTemplate;
public UserServiceClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// Uses service ID instead of actual URL
public User getUserById(String userId) {
// Note: Using service ID (user-service) instead of host:port
String url = "http://user-service/users/{userId}";
return restTemplate.getForObject(url, User.class, userId);
}
public List<User> getAllUsers() {
String url = "http://user-service/users";
User[] users = restTemplate.getForObject(url, User[].class);
return Arrays.asList(users != null ? users : new User[0]);
}
public User createUser(User user) {
String url = "http://user-service/users";
return restTemplate.postForObject(url, user, User.class);
}
// User DTO
public static class User {
private String id;
private String name;
private String email;
// constructors, getters, setters
public User() {}
public User(String id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
}
Example 9: Using OpenFeign for Declarative REST Clients
// Add Feign dependency
// implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
package com.example.orderservice.config;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableFeignClients
public class FeignConfig {
}
package com.example.orderservice.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(name = "user-service", path = "/users")
public interface UserServiceFeignClient {
@GetMapping("/{id}")
User getUserById(@PathVariable("id") String userId);
@GetMapping
List<User> getAllUsers();
@PostMapping
User createUser(@RequestBody User user);
@PutMapping("/{id}")
User updateUser(@PathVariable("id") String userId, @RequestBody User user);
@DeleteMapping("/{id}")
void deleteUser(@PathVariable("id") String userId);
// User DTO
class User {
private String id;
private String name;
private String email;
// constructors, getters, setters
public User() {}
public User(String id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
}
package com.example.orderservice.service;
import com.example.orderservice.client.UserServiceFeignClient;
import org.springframework.stereotype.Service;
@Service
public class OrderProcessingService {
private final UserServiceFeignClient userServiceClient;
public OrderProcessingService(UserServiceFeignClient userServiceClient) {
this.userServiceClient = userServiceClient;
}
public ProcessedOrder createOrderWithUserValidation(String userId, Order order) {
// Validate user exists
UserServiceFeignClient.User user = userServiceClient.getUserById(userId);
if (user == null) {
throw new RuntimeException("User not found: " + userId);
}
// Process order
String orderId = generateOrderId();
return new ProcessedOrder(orderId, user, order);
}
private String generateOrderId() {
return "ORD-" + System.currentTimeMillis();
}
public static class ProcessedOrder {
private final String orderId;
private final UserServiceFeignClient.User user;
private final Order order;
public ProcessedOrder(String orderId, UserServiceFeignClient.User user, Order order) {
this.orderId = orderId;
this.user = user;
this.order = order;
}
// getters
public String getOrderId() { return orderId; }
public UserServiceFeignClient.User getUser() { return user; }
public Order getOrder() { return order; }
}
public static class Order {
private String description;
private double amount;
// constructors, getters, setters
public Order() {}
public Order(String description, double amount) {
this.description = description;
this.amount = amount;
}
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public double getAmount() { return amount; }
public void setAmount(double amount) { this.amount = amount; }
}
}
Advanced Eureka Configurations
Example 10: Custom Eureka Instance Configuration
package com.example.orderservice.config;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class EurekaInstanceConfig {
@Bean
public EurekaInstanceConfigBean eurekaInstanceConfig(Environment env, InetUtils inetUtils) {
EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(inetUtils);
// Custom instance configuration
config.setAppname(env.getProperty("spring.application.name", "order-service"));
config.setInstanceId(env.getProperty("eureka.instance.instance-id",
config.getAppname() + ":" + config.getNonSecurePort()));
// Custom metadata
Map<String, String> metadata = new HashMap<>();
metadata.put("zone", "primary");
metadata.put("region", "us-east");
metadata.put("version", "1.0.0");
metadata.put("environment", env.getProperty("spring.profiles.active", "default"));
metadata.put("startup-time", String.valueOf(System.currentTimeMillis()));
config.setMetadataMap(metadata);
// Health check configuration
config.setStatusPageUrlPath("/actuator/info");
config.setHealthCheckUrlPath("/actuator/health");
// Lease configuration
config.setLeaseRenewalIntervalInSeconds(30);
config.setLeaseExpirationDurationInSeconds(90);
return config;
}
}
Example 11: Custom Health Check Handler
package com.example.orderservice.health;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicBoolean;
@Component
public class CustomHealthCheck implements HealthIndicator {
private final AtomicBoolean isHealthy = new AtomicBoolean(true);
@Override
public Health health() {
if (!isHealthy.get()) {
return Health.down()
.withDetail("reason", "Manual health check failure")
.build();
}
// Add custom health checks here
boolean databaseConnected = checkDatabaseConnection();
boolean externalServiceAvailable = checkExternalService();
if (databaseConnected && externalServiceAvailable) {
return Health.up()
.withDetail("database", "connected")
.withDetail("external-service", "available")
.build();
} else {
return Health.down()
.withDetail("database", databaseConnected ? "connected" : "disconnected")
.withDetail("external-service", externalServiceAvailable ? "available" : "unavailable")
.build();
}
}
public void setHealthy(boolean healthy) {
isHealthy.set(healthy);
}
private boolean checkDatabaseConnection() {
// Implement actual database health check
return true;
}
private boolean checkExternalService() {
// Implement actual external service health check
return true;
}
}
Monitoring and Management
Example 12: Eureka Dashboard and Monitoring
package com.example.orderservice.monitoring;
import com.netflix.appinfo.InstanceInfo;
import org.springframework.cloud.netflix.eureka.server.event.*;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class EurekaEventListener {
@EventListener
public void listen(EurekaInstanceRegisteredEvent event) {
InstanceInfo instanceInfo = event.getInstanceInfo();
System.out.println("Service Registered: " + instanceInfo.getAppName() +
" - " + instanceInfo.getInstanceId());
}
@EventListener
public void listen(EurekaInstanceRenewedEvent event) {
System.out.println("Service Heartbeat: " + event.getAppName() +
" - " + event.getInstanceId());
}
@EventListener
public void listen(EurekaInstanceCanceledEvent event) {
System.out.println("Service Unregistered: " + event.getAppName() +
" - " + event.getServerId());
}
@EventListener
public void listen(EurekaRegistryAvailableEvent event) {
System.out.println("Eureka Registry Started");
}
@EventListener
public void listen(EurekaServerStartedEvent event) {
System.out.println("Eureka Server Started");
}
}
Example 13: Service Discovery Controller
package com.example.orderservice.controller;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/discovery")
public class DiscoveryController {
private final DiscoveryClient discoveryClient;
public DiscoveryController(DiscoveryClient discoveryClient) {
this.discoveryClient = discoveryClient;
}
@GetMapping("/services")
public List<String> getServices() {
return discoveryClient.getServices();
}
@GetMapping("/services/{serviceId}")
public List<ServiceInstance> getServiceInstances(@PathVariable String serviceId) {
return discoveryClient.getInstances(serviceId);
}
@GetMapping("/services/{serviceId}/instances")
public List<Map<String, Object>> getServiceInstancesDetails(@PathVariable String serviceId) {
return discoveryClient.getInstances(serviceId).stream()
.map(instance -> Map.of(
"instanceId", instance.getInstanceId(),
"serviceId", instance.getServiceId(),
"host", instance.getHost(),
"port", instance.getPort(),
"uri", instance.getUri().toString(),
"metadata", instance.getMetadata(),
"secure", instance.isSecure()
))
.collect(Collectors.toList());
}
@GetMapping("/health")
public Map<String, Object> getDiscoveryHealth() {
return Map.of(
"discoveryClient", discoveryClient.description(),
"services", discoveryClient.getServices().size(),
"timestamp", System.currentTimeMillis()
);
}
}
Testing Eureka Services
Example 14: Integration Tests
package com.example.orderservice.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ActiveProfiles;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class OrderServiceIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@Test
void contextLoads() {
assertThat(discoveryClient).isNotNull();
}
@Test
void serviceRegistration() {
List<ServiceInstance> instances = discoveryClient.getInstances("order-service");
assertThat(instances).isNotEmpty();
ServiceInstance instance = instances.get(0);
assertThat(instance.getPort()).isEqualTo(port);
assertThat(instance.getServiceId()).isEqualTo("order-service");
}
@Test
void healthEndpoint() {
ResponseEntity<String> response = restTemplate.getForEntity(
"http://localhost:" + port + "/actuator/health", String.class);
assertThat(response.getStatusCode().is2xxSuccessful()).isTrue();
}
@Test
void orderEndpoint() {
ResponseEntity<String> response = restTemplate.getForEntity(
"http://localhost:" + port + "/orders/123", String.class);
assertThat(response.getStatusCode().is2xxSuccessful()).isTrue();
}
}
Example 15: Test Configuration
# application-test.yml spring: application: name: order-service-test eureka: client: enabled: false # Disable Eureka for tests register-with-eureka: false fetch-registry: false server: port: 0 # Random port for tests management: endpoints: web: exposure: include: health,info endpoint: health: enabled: true
Best Practices
1. Production Configuration
# application-prod.yml
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://eureka-server1:8761/eureka/,http://eureka-server2:8762/eureka/
register-with-eureka: true
fetch-registry: true
healthcheck:
enabled: true
instance:
prefer-ip-address: true
ip-address: ${POD_IP:localhost}
instance-id: ${spring.application.name}:${POD_ID:${random.value}}
lease-renewal-interval-in-seconds: 30
lease-expiration-duration-in-seconds: 90
metadata-map:
zone: ${ZONE:unknown}
environment: production
version: ${APP_VERSION:1.0.0}
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
show-components: always
# Circuit breaker configuration
resilience4j:
circuitbreaker:
instances:
userService:
register-health-indicator: true
sliding-window-size: 10
minimum-number-of-calls: 5
wait-duration-in-open-state: 10s
2. Security Configuration
package com.example.eurekaserver.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/eureka/**").permitAll()
.requestMatchers("/actuator/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("admin")
.password(passwordEncoder().encode("password"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Summary
Eureka provides robust service discovery for microservices:
- Service Registry: Centralized registry of available service instances
- Health Monitoring: Automatic health checks and instance eviction
- Load Balancing: Client-side load balancing with Ribbon
- High Availability: Multi-node Eureka server clusters
- Integration: Seamless integration with Spring Cloud ecosystem
Key benefits:
- Dynamic service discovery
- Automatic failover and load distribution
- Simplified service communication
- Production-ready with health monitoring
- Excellent Spring Boot integration
By implementing Eureka service discovery, you create a resilient and scalable microservices architecture where services can dynamically find and communicate with each other without hard-coded configurations.