Skip to main content

Command Palette

Search for a command to run...

πŸš€ Netflix Eureka Explained: The Secret Behind Microservice Communication

Learn Service Discovery, Heartbeats, Health Checks, Load Balancing, and Self-Preservation Mode with Real-World Spring Boot Examples

Updated
β€’6 min read
πŸš€ Netflix Eureka Explained: The Secret Behind Microservice Communication
A
I’m learning to think like a backend engineer β€” not just code like one. Focused on Java backend, AWS, and system design, I’m deeply interested in how scalable systems are built, how cloud infrastructure powers them, and how engineering decisions impact performance and reliability. I don’t just learn β€” I build, experiment, break things, and learn again. That’s how I grow. I believe curiosity, consistency, and learning from mistakes are what shape great engineers. Open to collaborations, real-world projects, and opportunities where I can build, contribute, and grow with like-minded people. This is my journey of becoming better every single day πŸš€

Microservices solve many problems that monolithic applications struggle with, but they introduce a new challenge

How do services find each other?

When your Rating Service needs to talk to the Hotel Service, it has to know exactly where to find it. You can get away with hardcoding URLs in tiny projects, but as your system grows, that turns into a massive headache. Netflix Eureka was built to cure exactly that headache.

So What Was The Problem Before Eureka ?

Imagine a simple microservices architecture:

User Service     β†’ localhost:8081
Hotel Service    β†’ localhost:8082
Rating Service   β†’ localhost:8083

If Rating Service wants to call Hotel Service, a common approach is:

@FeignClient(url = "http://localhost:8082")

This works initially but creates several problems at scale .

What If Port Changes?

If Hotel Service moves from:

8082 β†’ 9090

every service that depends on it must be updated.

Production Environments

In production, services run on different machines and Port mapping are dynamic :

Hotel Service   β†’ 10.10.1.4
Rating Service  β†’ 10.10.1.11

Hardcoding IP addresses becomes difficult to maintain as well as scale.

What happens when multiple instances are involved ?

To handle traffic, organizations often run multiple instances of the same service:

Hotel Service Instance 1 β†’ 10.10.1.4
Hotel Service Instance 2 β†’ 10.10.1.5
Hotel Service Instance 3 β†’ 10.10.1.6

Now the question becomes:

Which instance should the client call?

Here Comes Netflix Eureka

To fix this, Netflix created Eureka, a Service Discovery Server. You can picture it as a dynamic, automated phonebook for your microservices.

So, instead of having to memorize...

10.10.1.4:8082

services remember:

HOTEL-SERVICE

Eureka handles the mapping between service names and actual network locations.

Eureka Architecture

Without Eureka:

            Rating Service --- localhost:8082

The dependency is hardcoded.

With Eureka:

Every service registers itself with Eureka and can discover other services through it.

Eureka Is Like DNS for Microservices

When you visit:

google.com

you don't remember Google's IP address. DNS translates:

google.com --- 142.250.193.78

Similarly, Eureka translates:

HOTEL-SERVICE --- 10.1.5.44:8080

This allows services to communicate using logical names rather than physical addresses.

How Service Registration Works

When a microservice starts, it registers itself with Eureka.

Suppose Hotel Service starts.

Step 1: Read Service Name

spring:
  application:
    name: HOTEL-SERVICE

Step 2: Locate Eureka

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

Step 3: Register

The service sends a registration request containing:

{
  "serviceName": "HOTEL-SERVICE",
  "host": "localhost",
  "port": 8082,
  "status": "UP"
}

Step 4: Eureka Stores It

HOTEL-SERVICE
localhost:8082
UP

The service is now available for discovery.

Remember, Eureka Doesn't discover services.

A common misconception is that Eureka searches for services.

No, it doesn't. Services find Eureka and tell it:

"I am HOTEL-SERVICE"
"I am running on port 8082"

Eureka simply stores this information inside its registry.

Let's take an inside look at how the registry looks from its core:

Map<String, List<ServiceInstance>>

Example:

{
  "HOTEL-SERVICE": [
      instance1,
      instance2,
      instance3
  ],
  "USER-SERVICE": [
      instance1
  ]
}

Service Discovery in Action

Now suppose Rating Service needs to call Hotel Service.

Instead of using a URL:

@FeignClient(name = "HOTEL-SERVICE")

Note: Feing Client is a declarative REST client

Feign performs the following steps:

  1. Ask Spring Cloud LoadBalancer.

  2. LoadBalancer asks Eureka.

  3. Eureka returns available instances.

  4. LoadBalancer selects one instance.

  5. The request is sent.

The consumer never needs to know the actual IP address.

Eureka and Load Balancing

Assume Hotel Service has three instances:

8082 -- 8083 -- 8084

Eureka stores all of them.

Requests may be distributed as:

Request 1 β†’ 8082 --- Request 2 β†’ 8083
Request 3 β†’ 8084 --- Request 4 β†’ 8082

This enables client-side load balancing and allows applications to scale horizontally.

Heartbeats and Lease Renewal

Registration alone isn't enough. What happens if a service registers and then crashes?

Eureka would still believe it exists. To solve this, services periodically send Heartbeats.

A heartbeat simply means:

"I'm still alive."

By default:

eureka:
  instance:
    lease-renewal-interval-in-seconds: 30

A heartbeat is sent every 30 seconds.

Lease Expiration

Eureka also defines how long it should wait before considering a service dead.

eureka:
  instance:
    lease-expiration-duration-in-seconds: 90

If no heartbeat is received for 90 seconds, Eureka removes the instance from its registry.

A common production rule is:

Lease Expiration β‰ˆ 3 Γ— Heartbeat Interval

Self-Preservation Mode

One of Eureka's most important features is Self-Preservation Mode.

Imagine 1,000 services suddenly stop sending heartbeats.

Did all services crash?. Probably not.

More likely: Network Issue

If Eureka immediately removed all services, the entire system could become unavailable.

Instead, Eureka enters Self-Preservation Mode and temporarily keeps registry entries until it can determine whether the problem is actually service failure or just a networking issue.This protects distributed systems from large-scale outages.

Health Checks vs Heartbeats

Many developers confuse these concepts.

Heartbeat

Answers:

Is the service process alive?

Health Check

Answers:

Is the service actually healthy?

A service can still be running while its database is completely unavailable.

In that case:

Heartbeat = Alive
Health = Unhealthy

Integrating Spring Boot Actuator

Spring Boot Actuator provides health information through:

/actuator/health

Example response:

{
  "status": "UP"
}

To allow Eureka to use health information:

eureka:
  client:
    healthcheck:
      enabled: true

Now Eureka considers the actual application health instead of only checking whether the process is running.

Custom Health Indicators

Real-world applications depend on resources such as the following:

  • MySQL, Redis, Kafka, External APIs

Custom Health Indicators allow these dependencies to participate in health checks.

@Component
public class DatabaseHealthIndicator
        implements HealthIndicator {

    @Override
    public Health health() {

        boolean databaseUp = checkDatabase();

        if(databaseUp) {
            return Health.up().build();
        }

        return Health.down().build();
    }
}

If the database fails, Actuator reports the following:

{
  "status": "DOWN"
}

and Eureka can stop routing traffic to that instance.

Eureka Server Setup

Creating a Eureka Server is surprisingly simple.

Main Class

@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistryApplication {

    public static void main(String[] args) {
        SpringApplication.run(
            ServiceRegistryApplication.class,
            args
        );
    }
}

Configuration

server:
  port: 8761

spring:
  application:
    name: SERVICE-REGISTRY

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

Why These Properties?

register-with-eureka: false

The Eureka Server should not register itself.

fetch-registry: false

The Eureka Server should not fetch a registry from another Eureka Server because it is the registry.

Once you understand service registration, discovery, heartbeats, lease renewal, health checks, and self-preservation mode, Eureka stops being a configuration exercise and becomes a powerful distributed systems concept.