Cloud Native 16 min read

Mastering Eureka: Service Registration & Discovery for Resilient Microservices

This guide explains why learning the classic Eureka service registry remains valuable, compares architectures with and without Eureka, and provides step‑by‑step code for both non‑clustered and clustered setups, including self‑protection mode, load‑balanced clients, and how to retrieve registration information via DiscoveryClient.

Java Captain
Java Captain
Java Captain
Mastering Eureka: Service Registration & Discovery for Resilient Microservices

Service Registration/Discovery – Eureka

Although Nacos is the mainstream service registry, the classic Eureka remains worth learning for several reasons: early microservice projects used it, and many later solutions are inspired by its design, making the transition to Nacos easier.

Some early distributed microservice projects used Eureka, so you may encounter it in real work.

Later service‑registry technologies reference Eureka’s design; understanding Eureka simplifies learning Nacos and deepens comprehension.

Introducing Eureka

Without Eureka, a typical architecture is:

Service Consumer →

RestTemplate

(direct call) → Service Provider

Example controller without Eureka:

@RestController
@RequestMapping("/member/consumer")
@Slf4j
public class MemberConsumerController {
    public static final String MEMBER_SERVICE_PROVIDER_URL = "http://localhost:10001";
    @Autowired
    private RestTemplate restTemplate;
    @PostMapping("/save")
    public Result<Member> save(Member member) {
        return restTemplate.postForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/save", member, Result.class);
    }
    @GetMapping("/get/{id}")
    public Result<Member> getMemberById(@PathVariable("id") Long id) {
        return restTemplate.getForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/get/" + id, Result.class);
    }
}

Drawbacks of this simple structure:

High concurrency in enterprise projects can overwhelm a single consumer.

A single provider leads to poor availability.

Providers are usually deployed as a cluster, so multiple service instances exist.

The consumer cannot hard‑code URLs; it needs dynamic discovery.

Even after discovery, the consumer must decide which instance to call, introducing load‑balancing concerns.

Eureka solves all these problems.

Project After Introducing Eureka

With Eureka, the architecture becomes:

Service Provider (cluster) registers/renews/cancels with Eureka Server (cluster).

Service Consumer registers itself, discovers services via Eureka Server, then performs remote calls.

Analysis:

The provider is deployed as a cluster for high availability.

Eureka Server can also be clustered to avoid a single point of failure.

Eureka consists of two components: Eureka Server and Eureka Client.

Eureka Server stores registration information of all healthy instances, visible via its UI.

Eureka Client registers with the server, sends heartbeats (default 30 s), and includes a built‑in round‑robin load balancer; missing heartbeats (default 90 s) cause the server to remove the instance.

Service Governance

Eureka implements service governance.

Traditional RPC frameworks make managing inter‑service dependencies complex.

Service governance provides registration, discovery, load balancing, and fault tolerance.

Service Registration and Discovery

Eureka follows a client‑server design; the server acts as the registry.

Microservices connect to Eureka Server, maintain heartbeats, and are monitored for health.

When a service starts, it registers its address and metadata under an alias.

Consumers retrieve the actual address via the alias and invoke the service.

Eureka Server (non‑cluster) Implementation

pom.xml dependency:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

application.yml configuration:

# Server port
server:
  port: 9001
# Eureka Server settings
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

Main class:

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

Eureka Client (non‑cluster) Implementation

pom.xml dependency:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml configuration:

# Server port
server:
  port: 10001
spring:
  application:
    name: member-service-provider-10001
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/e_commerce_center_db?useSSL=true&useUnicode=true&characterEncoding=UTF-8
    username: root
    password: zy
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.zy88.springcloud.entity
# Eureka client settings
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:9001/eureka

Main class:

@EnableEurekaClient
@SpringBootApplication
public class MemberApplication {
    public static void main(String[] args) {
        SpringApplication.run(MemberApplication.class, args);
    }
}

Eureka Self‑Protection Mode

By default, Eureka Client sends heartbeats; if the server does not receive a heartbeat for 90 s, it removes the instance. When many heartbeats are missed (e.g., network issues), the server enables self‑protection to keep all instances registered, favoring availability over strict accuracy. This is an AP‑style CAP trade‑off.

To disable self‑protection (not recommended for production):

eureka:
  server:
    enable-self-preservation: false

Eureka Server (cluster) Implementation

Why a cluster?

Microservice RPC needs high availability.

A single registry failure makes the whole system unavailable.

Running multiple Eureka servers provides load balancing and fault tolerance.

application.yml for a clustered server (instance 9001):

server:
  port: 9001
# Eureka Server settings
eureka:
  instance:
    hostname: eureka9001.com
  client:
    register-with-eureka: false
    fetch-registry: false
  service-url:
    defaultZone: http://eureka9002.com:9002/eureka/

Update the hosts file (e.g., C:\Windows\System32\drivers\etc\hosts) to map the hostnames to IPs.

Eureka Client – Provider (cluster) Implementation

Modify the provider’s

application.yml

to register with both servers:

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka9001.com:9001/eureka,http://eureka9002.com:9002/eureka

Ensure all instances share the same

spring.application.name

(e.g.,

member-service-provider

) for unified discovery.

Eureka Client – Consumer (cluster) Implementation

Update the consumer controller to use the service alias instead of a hard‑coded URL:

@RestController
@RequestMapping("/member/consumer")
@Slf4j
public class MemberConsumerController {
    public static final String MEMBER_SERVICE_PROVIDER_URL = "http://MEMBER-SERVICE-PROVIDER";
    @Autowired
    private RestTemplate restTemplate;
    @PostMapping("/save")
    public Result<Member> save(Member member) {
        return restTemplate.postForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/save", member, Result.class);
    }
    @GetMapping("/get/{id}")
    public Result<Member> getMemberById(@PathVariable("id") Long id) {
        return restTemplate.getForObject(MEMBER_SERVICE_PROVIDER_URL + "/member/get/" + id, Result.class);
    }
}

Add a load‑balanced

RestTemplate

bean so that Eureka/Ribbon can choose an instance automatically:

@Configuration
public class CustomizationBean {
    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

Notes:

The @LoadBalanced annotation enables Ribbon’s client‑side load balancing (default round‑robin, configurable).

With Ribbon integrated, the consumer calls the service name without worrying about host or port.

DiscoveryClient – Retrieving Eureka Registration Information

Enable discovery with

@EnableDiscoveryClient

and inject

DiscoveryClient

to list services and instances:

@EnableDiscoveryClient
@RestController
@RequestMapping("/member/consumer")
@Slf4j
public class MemberConsumerController {
    public static final String MEMBER_SERVICE_PROVIDER_URL = "http://MEMBER-SERVICE-PROVIDER";
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;
    @GetMapping("/discovery")
    public Object discovery() {
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            log.info("Service name = {}", service);
            List<ServiceInstance> instances = discoveryClient.getInstances(service);
            for (ServiceInstance instance : instances) {
                log.info("id= {}, host= {}, port= {}, uri= {}", instance.getServiceId(), instance.getHost(), instance.getPort(), instance.getUri());
            }
        }
        return discoveryClient;
    }
    // save and get methods omitted for brevity
}

Access

http://localhost/member/consumer/discovery

to view the registration details, as shown in the screenshots below:

microservicesload balancingservice discoveryeurekaSpring Cloudself‑protection
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.