Client-side vs server-side discovery, Eureka's registration/heartbeat/self-preservation mechanics, Consul as an alternative, and DNS-based discovery in Kubernetes vs registry-based discovery.
Published September 23, 2026
In a microservices system where service instances scale up/down and get rescheduled constantly, hard-coding IP addresses is a non-starter — service discovery is the mechanism that lets a caller find a currently-healthy instance without knowing its address in advance.
[Client] → queries registry directly → [Service Registry] → returns list of healthy instances
[Client] → picks an instance itself (load balancing logic lives in the client) → calls it directly
The calling service (or a client-side library like Spring Cloud's LoadBalancerClient) queries the registry, gets back a list of healthy instances, and applies its own load-balancing logic (round-robin, random, etc.) to pick one. This is the Eureka + client-side load balancer model.
[Client] → calls a STABLE endpoint (doesn't know or care about instances) → [Infra resolves the actual instance]
The client calls a fixed, stable address (a Kubernetes Service, an AWS ALB) and the infrastructure — not the client — resolves which specific instance actually handles the request. The client never sees individual instance addresses or does any load-balancing decision itself.
@EnableEurekaClient // on a service instance
@SpringBootApplication
class OrderServiceApplication { ... }
eureka:
instance:
lease-renewal-interval-in-seconds: 30 # heartbeat frequency
lease-expiration-duration-in-seconds: 90 # how long without a heartbeat before eviction
On startup, a service instance registers itself with the Eureka server (announcing its address and metadata). It then sends a periodic heartbeat to prove it's still alive — if the registry stops receiving heartbeats from an instance for longer than the lease-expiration window, that instance is evicted from the registry, and clients stop being routed to it.
Self-preservation mode: if Eureka observes an unusually large fraction of instances suddenly failing to heartbeat simultaneously, it assumes this is more likely a network partition between the registry and its clients (not that a huge fraction of real instances genuinely died at once) and stops evicting instances, keeping the last-known-good registry state rather than aggressively removing entries. This deliberately trades some staleness (potentially still routing to an instance that actually did die) for avoiding a worse failure mode — mass eviction during a network blip that would otherwise make the entire system appear to have no healthy instances at all, a self-inflicted outage caused by the discovery mechanism itself.
Consul takes a different approach to instance health: rather than relying purely on a heartbeat/lease model, it supports pluggable active health checks (an HTTP endpoint check, a TCP check, a script-based check the Consul agent runs directly) — Consul actively probes instances rather than only passively waiting for them to report in. Consul also ships a distributed key-value store, commonly used for configuration management alongside its service-discovery role, whereas Eureka is narrowly scoped to service discovery alone.
Kubernetes' own Service resolves via DNS — calling http://order-service inside a cluster resolves through Kubernetes' internal DNS to the Service's stable virtual IP, which kube-proxy then load-balances across healthy backing Pods. This is server-side discovery by construction: application code makes an ordinary DNS-resolved HTTP call with zero discovery-specific client code at all — no Eureka client library, no explicit registry query. Eureka's registry-based model requires services to run a Eureka client that explicitly registers and queries the registry; Kubernetes' DNS-based model requires no client-side discovery code whatsoever, with the platform itself handling routing transparently.
Client-side discovery gives the client more control (custom load-balancing logic, retries, circuit-breaking decisions made with direct visibility into available instances) at the cost of every client needing discovery-aware code. Server-side discovery simplifies clients dramatically (plain HTTP calls to a stable address, no discovery library needed) at the cost of less client-side control over routing decisions — which is exactly why Kubernetes-native architectures lean server-side/DNS-based by default, while Spring Cloud/Eureka-based architectures (more common in pre-Kubernetes or hybrid deployments) lean client-side.
Q: What happens to in-flight requests to an instance that gets evicted from the registry mid-request? A: Discovery only affects routing of NEW requests — an in-flight request to an instance that subsequently gets evicted isn't retroactively cancelled by the registry; it either completes normally or fails on its own terms (timeout, connection reset), which is why discovery alone doesn't replace the need for client-side retry/circuit-breaker logic for requests already in progress.
Q: Is Eureka's self-preservation mode always a net positive? A: It's a deliberate tradeoff, not a strict improvement — during a genuine mass-failure event (not a network partition), self-preservation mode means the registry keeps advertising instances that are actually dead, and clients keep getting routed to them and failing, for longer than strict eviction would have allowed. Operators need to know this mode exists and can be disabled if a specific deployment's failure characteristics make aggressive eviction the safer default.
Q: How does load balancing interact with service discovery in the client-side model specifically? A: Discovery answers 'which instances exist and are healthy'; load balancing (round-robin, least-connections, or more sophisticated strategies) answers 'which of those healthy instances should THIS specific request go to' — they're separate, composable concerns, and Spring Cloud's client-side model explicitly layers a LoadBalancerClient on top of the Eureka-provided instance list rather than conflating the two.
Q: Why might a team running on Kubernetes still choose to run Eureka anyway? A: Typically during a migration (a system with pre-existing Eureka-based services being incrementally moved onto Kubernetes, where ripping out Eureka everywhere at once isn't practical) or when specific Eureka features (client-side load-balancing control, cross-region registry federation) aren't well-served by Kubernetes' simpler DNS-based model for that team's specific needs.