Cloud Native 35 min read

Stop Blindly Choosing Service Discovery: Deep Comparison of Eureka, Nacos & ZooKeeper

The article recounts a real‑world outage caused by Eureka’s self‑protection mode, then establishes five key evaluation dimensions for service discovery, provides a detailed side‑by‑side analysis of Eureka, ZooKeeper and Nacos—including design goals, failure modes, scalability and operational features—and offers concrete guidance on selecting, configuring and migrating to the most suitable registry for production micro‑service environments.

Cloud Architecture
Cloud Architecture
Cloud Architecture
Stop Blindly Choosing Service Discovery: Deep Comparison of Eureka, Nacos & ZooKeeper

1. Incident that reshaped the view on service discovery

During a large‑scale load test of an e‑commerce system that grew to over 400 services, the order API’s 500 error rate spiked. Logs showed java.net.ConnectException: Connection refused. Full GC and short‑lived network jitter delayed heartbeats; Eureka entered self‑protection mode, stopped expiring stale instances, and the client cache mixed old IPs, terminated containers and newly rebuilt instances. Calls kept hitting stale instances, causing the outage.

Key conclusions:

Service discovery is not a “plug‑and‑play” component.

The failure mode directly determines whether a chain degrades, slows down, or crashes.

Teams that only watch the UP flag without understanding instance lifecycle, cache mechanisms and consistency trade‑offs will eventually pay the price in production.

2. Unified evaluation criteria: what service discovery actually protects

Five dimensions affect production behaviour.

2.1 Instance change propagation path

Chain: registration → heartbeat / long‑connection keep‑alive → change push or client pull → local cache → call. Critical questions:

How quickly can a consumer perceive a new instance?

How long does it take to evict an unhealthy instance?

Can the consumer continue operating when the registry is unavailable?

Does the consumer see raw data or a view processed by protection policies?

2.2 Consistency vs. availability trade‑offs

Prioritising strong consistency usually requires leader election, write serialization and a temporary write‑unavailability window.

Prioritising availability accepts a short window where stale instance lists may be read.

2.3 Client models

Local‑cache‑first (pull) – client periodically pulls the registry.

Session‑bound temporary nodes – client holds a session; loss of the session removes the node.

Push‑subscription with local cache – client receives change events but also keeps a fallback cache.

2.4 Scale stability

Metadata synchronization cost during massive up/down events.

Connection‑storm risk when many clients reconnect.

Whether write and subscription pressure can be evenly spread after cluster expansion.

2.5 Operations & governance capabilities

Permission management

Environment isolation

Monitoring & alerts

Auditing

Metadata governance

Cross‑region disaster recovery

Integration with Kubernetes / Gateway / Service Mesh

3. The three products actually solve three different problems

3.1 Eureka – AP design that prioritises service availability

Core ideas:

Do not block the call chain; keep a local cache.

Even if the server is briefly unavailable, the client can continue using cached data.

When heartbeats are delayed, network jitter or batch restarts happen, Eureka tends to retain old data instead of immediately removing suspicious instances. This makes the self‑protection mode both a rescue mechanism and an accident amplifier.

Eureka’s advantages

Simple architecture, easy‑to‑understand client model.

Low entry cost for small‑to‑medium, stable internal networks.

Real boundaries

Relies on client‑side periodic pull; not suited for extremely high‑frequency, massive instance churn.

Once self‑protection triggers, stale instances may linger longer than expected.

In newer Spring Cloud stacks it is becoming a maintenance‑only component.

3.2 ZooKeeper – CP design that prioritises strong consistency

Model:

Instances are stored as temporary nodes.

Session loss automatically deletes the node.

Leader coordinates data updates, guaranteeing order and consistency.

Clients use the Watch mechanism to perceive changes.

Strengths: distributed locks, leader election, metadata coordination. Weaknesses for service discovery: high write pressure and notification storms under massive instance churn.

ZooKeeper’s advantages

Session‑bound temporary nodes give clear removal semantics.

Strong consistency is ideal for control‑plane scenarios that require exact state.

Works well for a modest number of nodes with low change frequency.

Real boundaries

Large‑scale instance up/down creates heavy Watch traffic and session‑reconnection cost.

Leader election windows make writes unavailable, which conflicts with “always‑available registration” expectations.

More of a coordination base than a modern micro‑service registry.

3.3 Nacos – Integrated discovery & configuration platform for micro‑service governance

Official resource model: namespace → group → service → cluster → instance. Nacos manages not only the service‑name‑to‑instance mapping but also environment, business domain, deployment unit and instance metadata.

Instance types:

Temporary instances follow an AP‑style runtime path, maintained by client liveness and Distro sync.

Persistent instances follow a CP‑style persistent path, managed by the server.

Nacos’s advantages

Designed for micro‑service governance; discovery and configuration are unified.

Supports environment isolation, grouping, clustering and rich metadata – ideal for gray releases, same‑city priority and region routing.

Client subscription, push, cache and fault‑tolerance mechanisms match production needs.

Friendly to Spring Cloud Alibaba, Kubernetes and gateway‑based control planes.

Real boundaries

Not a “plug‑and‑play” control plane; complex traffic governance still needs additional components.

Mis‑configured namespace/group/cluster/metadata can quickly explode governance complexity.

When configuration, registration and part of governance are all placed in Nacos, permission models and environment isolation must be carefully designed.

4. Compare failure modes, not just features

Dimension | Eureka | ZooKeeper | Nacos
--- | --- | --- | ---
Core positioning | Microservice registration & discovery | Distributed coordination | Microservice discovery + configuration governance
Design tilt | AP | CP | AP for temporary, CP for persistent
Client model | Local cache + periodic pull | Session + temporary node + Watch | Subscription push + local cache + multi‑layer metadata
Instance removal | Heartbeat timeout & protection | Session loss deletes node | Temporary instances depend on client liveness; persistent instances removed by management flow
Typical failure risk | Stale instances linger | Election window unavailable, notification storm | Metadata governance; wrong instance type amplifies issues
Scale stretch | Average | Poor | Strong
Console & ops experience | Basic | Weak | Complete
Cloud‑native integration | Legacy compatible | Indirect | Friendly

4.1 Typical failure scenarios

Scenario 1 – Network jitter, massive heartbeat delay

Eureka: more likely to keep old instances; success rate drops but the registry itself may stay up.

ZooKeeper: session state is emphasized; disconnections quickly delete nodes, but reconnection can cause a storm.

Nacos: behaviour depends on instance type and client cache strategy; generally more flexible than pure polling.

Scenario 2 – Massive instance restart within minutes

Eureka: consumer cache refresh lag, old nodes remain.

ZooKeeper: connection reconnection, Watch notification and Leader write pressure stack.

Nacos: better suited, provided subscription, probe and flow‑control are correct.

Scenario 3 – Master node failure

Eureka: no strong master model; accepts eventual consistency.

ZooKeeper: enters election window; writes are affected.

Nacos: depends on deployment mode; overall more resilient through cluster and cache fallback.

5. When to choose which registry

5.1 Situations where Eureka still fits

Existing system already stable on Spring Cloud Netflix stack.

Service scale is moderate and instance churn is low.

Team is deeply familiar with its cache, self‑protection and failure handling.

No immediate need to merge discovery with configuration governance.

Not recommended for new large‑scale micro‑service platforms or when tight integration with modern Spring Cloud or Kubernetes ecosystems is required.

5.2 Situations where ZooKeeper is appropriate

Core requirement is distributed coordination rather than pure service discovery.

Service instance scale is small and change frequency is controllable.

Team has mature ZooKeeper operational expertise and understands sessions, Watchers and election windows.

Not recommended for massive service‑level registration workloads.

5.3 Situations where Nacos should be the default

Service count and instance scale are continuously growing.

Team wants discovery, configuration and metadata governance in a single platform.

Runtime is based on Spring Cloud Alibaba, Kubernetes and gateway‑level traffic control.

Need for namespace, group, cluster and rich metadata to support gray releases, region routing and version isolation.

If the system already fully relies on native Kubernetes Service + DNS with light governance, an extra layer may be unnecessary.

6. Engineering perspective: why Nacos fits production best

6.1 Matches modern instance lifecycle

Micro‑service instances are rarely long‑living machines; they are subject to container rollouts, HPA scaling, node drift, gray batch replacement and multi‑environment validation. Nacos’s namespace‑group‑cluster‑metadata model naturally captures these dimensions.

6.2 Discovery and governance together

Ops and developers see the same service view.

Gray release weight, version and region tags can be managed as metadata.

Configuration and discovery share a platform, reducing middleware count.

Costs:

Permission model must be well designed.

Environment isolation cannot rely on conventions alone.

Metadata naming conventions need strict enforcement.

6.3 Phased rollout path

First integrate discovery only, replace hard‑coded addresses or legacy registries.

Then add environment isolation, service grouping and instance metadata.

Next introduce gray release, same‑region priority and weight routing.

Finally add advanced configuration governance and cross‑cluster disaster recovery.

7. Production is not just “install a cluster”

7.1 Cluster design recommendations

Deploy a multi‑node cluster in production to avoid single points of failure.

Treat the registry and its backing database as separate high‑availability concerns.

Cross‑region replication is not a simple copy‑paste; latency, consistency and operational boundaries must be clarified.

7.2 Service modeling recommendations

A robust model should define: namespace: environment or tenant isolation. group: business domain or service collection. cluster: data‑center, region or deployment unit. metadata: version, traffic label, protocol capabilities, etc.

7.3 Health‑check recommendations

Process liveness – is the process running?

Container readiness – is the service ready to receive traffic?

Business health – are critical dependencies (DB, downstream services, thread pools) healthy?

Relying only on TCP reachability will cause the registry to expose “alive but not serviceable” instances.

7.4 Local cache and fallback strategies

Define how long a stale cache is acceptable.

Identify which services can continue using an old instance list.

Determine which critical APIs must actively circuit‑break or rate‑limit when discovery data is outdated.

“Continue available” and “continue correct” are different risk profiles that callers must understand.

8. Spring Cloud Alibaba integration with Nacos – production‑ready patterns

8.1 Common pitfalls

Using Ribbon for load balancing instead of Spring Cloud LoadBalancer.

Treating bootstrap.yml as the default config entry; modern projects should use application.yml with spring.config.import.

Only ensuring registration succeeds while ignoring graceful deregistration.

8.2 Basic configuration example

spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: 10.0.1.10:8848,10.0.1.11:8848,10.0.1.12:8848
        namespace: prod
        group: trade
        cluster-name: cn-east-1a
        ephemeral: true
        weight: 1
        metadata:
          version: v2
          zone: cn-east-1
          traffic-label: stable
management:
  endpoints:
    web:
      exposure:
        include: health,info
  health:
    probes:
      enabled: true

This configuration explicitly defines: namespace for environment isolation. group for business‑domain aggregation. cluster-name for region‑aware routing. metadata for version‑based gray releases. ephemeral: true to follow the natural instance lifecycle.

8.3 Service startup configuration

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

Production practice separates process start‑up from traffic exposure:

After the application starts, a readiness probe validates critical dependencies.

Only when the probe passes does the instance become visible to upstream services.

During shutdown, first deregister or stop receiving traffic, then terminate the process (avoid kill -9).

8.4 Consumer call with Spring Cloud LoadBalancer

@Configuration
public class HttpClientConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@RestController
@RequestMapping("/orders")
public class OrderController {
    private final RestTemplate restTemplate;
    public OrderController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
    @PostMapping("/{orderId}/deduct")
    public String deductStock(@PathVariable Long orderId) {
        return restTemplate.postForObject(
                "http://inventory-service/inventory/deduct/" + orderId,
                null,
                String.class);
    }
}

Beyond removing hard‑coded IPs, production still needs:

Timeout and connection‑pool tuning.

Bounded retry attempts.

Circuit‑breaker and fallback strategies.

8.5 Gray‑release routing needs more than a version field

Metadata (e.g., version, traffic tags) is only input. Actual routing logic must be implemented in gateways, callers or governance layers, with explicit fallback when no matching instance exists.

9. Most common production pitfalls – lifecycle mismatches

9.1 Instance registered but not ready to receive traffic

Process started but cache not warmed.

Database connection established but downstream services still unreachable.

Web container started while async workers or message consumers are not ready.

Solution:

Separate “process started” from “instance ready” using readiness probes.

Align registry health with business health.

9.2 Instance exited but still being called

No graceful traffic drain before shutdown.

Client cache still holds the stale instance.

Deployment script only stops the container without deregistering.

Solution:

Standardize shutdown: drain traffic → wait for connections to finish → deregister → stop process.

Set reasonable call timeouts and fallback strategies.

Make deregistration, probe switch‑off and gateway drain part of the release pipeline.

9.3 Misuse of permanent vs. temporary instances

Registering a short‑lived business service as a persistent instance leaves stale entries after the process exits; treating a truly long‑lived resource as temporary can cause premature removal during session loss. Instance type is a core part of the lifecycle model.

9.4 Blind retries amplify problems

Unlimited retries increase load and can deadlock thread pools when the registry is faulty or the instance list is stale.

Recommended pattern:

Fast‑fail on obvious errors.

Retry with a different instance but limit the number of attempts.

Circuit‑break failing targets.

Define clear policies for handling stale discovery windows.

10. Migrating from Eureka to Nacos – a safe path

10.1 Inventory and call‑graph audit

Identify core‑chain services.

Map cross‑region calls.

Spot services sensitive to instance‑change latency.

List services that depend on Eureka‑specific behaviours.

10.2 Dual registration without dual governance

During migration services can register to both Eureka and Nacos, but governance rules (weights, tags, gray policies) should live in only one system to avoid inconsistency.

10.3 Switch peripheral services first

Choose services with clear call relationships and low failure impact.

Prefer services where consistency windows are not critical.

Observe instance sync, cache convergence and alert behaviour before moving core services.

10.4 Define migration success criteria

Acceptable instance‑up perception latency.

Acceptable instance‑down removal latency.

Client fallback behaviour when the registry is unavailable.

Gray‑release, retry and circuit‑breaker logic still meet expectations.

Without pre‑defined metrics, a migration cannot be judged complete.

11. Short advice for teams

Eureka works for stable, medium‑scale systems but its failure mode (stale instances) mismatches highly dynamic containerised environments.

ZooKeeper excels at strong consistency coordination, not at massive service‑level discovery.

Nacos offers a balanced choice for modern Java micro‑service stacks, provided the team understands its instance types, governance semantics and client behaviour.

Service‑discovery selection is not about which tool is newer, but about which failure mode aligns with your business’s tolerance for stale data versus unavailability.

12. Five practical rules for rollout

Define the instance lifecycle first, then choose registry configuration.

Do not equate registry console “healthy” with business‑level availability.

Metadata (gray, weight, tags) is only input; actual traffic decisions must be implemented in callers, gateways or governance layers.

Always prepare fallback strategies for registry outages – local cache, rate‑limit, circuit‑break, degradation.

When service scale grows, discovery becomes a platform‑level governance problem rather than a simple SDK setting.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

cloud nativemicroservicesservice discoveryZooKeeperNacosEureka
Cloud Architecture
Written by

Cloud Architecture

Focuses on cloud‑native and distributed architecture engineering, sharing practical solutions and lessons learned. Covers microservice governance, Kubernetes, observability, and stability engineering to help your systems run stable, fast, and cost‑effectively.

0 followers
Reader feedback

How this landed with the community

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.