Netflix Eureka: Service Discovery in Action
In a monolithic application, components talk to each other through in-process method calls. But once you break your system into microservices, those components live on different hosts, scale up and down dynamically, and get assigned ephemeral network addresses. How does one service find another when IP addresses are constantly changing?
This is the problem service discovery solves, and Netflix Eureka is one of the most battle-tested tools for the job.
What Is Eureka?
Eureka is a REST-based service registry originally built by Netflix and later open-sourced as part of the Netflix OSS stack. It has two main components:
- Eureka Server — the registry where services announce their presence.
- Eureka Client — embedded in each microservice; it registers the service on startup and periodically fetches the registry to discover peers.
The core idea is simple: instead of hardcoding hostnames and ports, services ask the registry "where is service X?" and get back a list of healthy instances.
The Registration Lifecycle
Understanding Eureka means understanding its lifecycle:
- Registration — When a client starts, it POSTs its metadata (host, port, health URL, etc.) to the Eureka Server.
- Renewal (Heartbeat) — The client sends a heartbeat every 30 seconds (by default) to prove it's alive.
- Fetch Registry — Clients pull the full registry (every 30 seconds) and cache it locally.
- Cancellation — On graceful shutdown, the client sends a cancel request to deregister.
- Eviction — If the server misses heartbeats past the eviction threshold, it removes the instance.
Setting Up a Eureka Server
With Spring Cloud, standing up a Eureka Server is remarkably lean. Add the dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Then enable it in your main application class:
@SpringBootApplication
@EnableEurekaServer
public class DiscoveryServerApplication {
public static void main(String[] args) {
SpringApplication.run(DiscoveryServerApplication.class, args);
}
}
Configure application.yml so the server doesn't try to register with itself:
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
enable-self-preservation: true
Boot it up and visit http://localhost:8761 to see the Eureka dashboard.
Registering a Client
Any microservice becomes discoverable by adding the client starter:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
And pointing it at the server:
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
The spring.application.name becomes the service ID other services use to look it up.
Discovering and Calling Services
Once registered, you can call other services by name rather than by URL. With a load-balanced RestTemplate:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Service
public class InventoryClient {
private final RestTemplate restTemplate;
public InventoryClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public Inventory checkStock(String sku) {
// "inventory-service" is resolved via Eureka
return restTemplate.getForObject(
"http://inventory-service/api/stock/" + sku,
Inventory.class);
}
}
Notice there's no IP or port—Spring Cloud LoadBalancer resolves inventory-service to a live instance and distributes calls across all healthy nodes.
Self-Preservation Mode: A Common Gotcha
Eureka has a feature called self-preservation that catches many engineers off guard. If the server suddenly stops receiving the expected number of heartbeats (below ~85% within a window), it assumes there's a network partition rather than mass service failure. Instead of evicting instances, it preserves the registry to avoid wrongly removing healthy services.
This is a deliberate design choice rooted in the CAP theorem: Eureka favors availability over consistency. It would rather serve slightly stale registry data than risk removing instances that are actually reachable.
In development, self-preservation can be confusing because dead instances linger. You can disable it locally:
eureka:
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 5000
But keep it enabled in production—it's a safety net for real network turbulence.
High Availability with Peer Awareness
A single Eureka Server is a single point of failure. In production, run multiple servers that register with each other (peer awareness):
# Instance running as peer1
eureka:
instance:
hostname: peer1
client:
service-url:
defaultZone: http://peer2:8761/eureka/,http://peer3:8761/eureka/
Each server replicates its registry to its peers, so if one node fails, clients seamlessly fall back to another.
When Should You Use Eureka?
Eureka shines in JVM-heavy, Spring Cloud ecosystems where client-side load bal
Top comments (0)