Knowledge Guide
HomeSystem DesignMicroservices Patterns

Service Discovery Pattern A Solution

A service registry is a live, in-memory key–value store keyed by logical service name: each instance writes its own host:port on startup and keeps that entry alive by renewing a time-bounded lease with periodic heartbeats, so a caller resolves "where is payment-service?" against the current set of live addresses at request time instead of against a config file baked in at deploy time.

That one move — replacing a static binding with a runtime lookup — is what lets instances come, go, move, and scale without anyone re-configuring their callers. Everything else (load balancing, decoupled config, self-healing) falls out of it.

The two topologies

Discovery splits on who does the lookup and picks the instance. This choice drives almost every trade-off later.

diagram
diagram

The lifecycle: register, heartbeat, expire

The registry never trusts an entry forever — that would make crashed instances immortal. Each registration carries a lease with a TTL. The instance must renew (heartbeat) before the lease expires, or the registry evicts it. This heartbeat loop is the heart of the pattern and the source of its hardest failure mode.

diagram
diagram

Worked trace: order-service → payment-service

Two payment-service instances, an Eureka-style registry with TTL = 30s and a 10s heartbeat. Instance A crashes mid-stream. Follow the registry contents and what the caller sees.

tActor / eventRegistry state for payment-serviceWhat order-service observes
0sA starts, POST /register {A: 10.0.1.7:8443}, lease→30s[A@10.0.1.7:8443]
2sB starts, registers, lease→30s[A@10.0.1.7, B@10.0.1.9]
10s,20sA & B heartbeat; leases reset to 30s[A, B] both fresh
25sorder-svc looks up, gets both, round-robins → picks A[A, B]calls A → 200 OK
40sA & B heartbeat (A's last successful renew)[A, B] lease-A expires at 70s
42sA crashes — process dead, no de-register sent[A(zombie), B]
45sorder-svc looks up, still sees A, round-robins → picks A[A(zombie), B]connect timeout → error
50sorder-svc retries, picks B[A(zombie), B]calls B → 200 OK
70slease-A expires; registry evicts A[B]
75s+lookups return only B[B]always hits live B

The lesson is in the 28-second window (42s→70s): a crashed instance is still advertised until its lease lapses. Graceful shutdown (explicit de-register) closes this window; a hard crash does not. This is why callers must pair discovery with retries, timeouts, and circuit breakers — discovery alone cannot guarantee the address it hands you is alive right now.

Pitfalls

When to use it — and when not

Reach for explicit service discovery when instance addresses are ephemeral (autoscaling, container reschedules, spot instances), you have many services calling many services, and you want deploys/scaling to happen without touching caller config. These are the signals: dynamic IPs, horizontal scaling, and blue-green/rolling deploys.

Skip it when you have a handful of long-lived services on fixed hosts — a static config file or a single well-known load balancer VIP is simpler and has no SPOF to operate. Do not build a registry to solve a problem you do not have.

Choosing the mechanism

OptionModelYou gainIt costs
Kubernetes Service + CoreDNSServer-side, DNS-frontedFree with the platform; no client library; endpoints controller tracks pod health automaticallyLocked to k8s networking; kube-proxy adds a hop; DNS caching quirks
Netflix Eureka (+ Ribbon)Client-side, APNo extra network hop; client-side LB with zone-awareness; survives registry partitions (self-preservation)Fat client library per language; stale reads possible; you operate the Eureka cluster; effectively JVM-centric
Consul / etcdCP (Raft), active health checksStrong consistency; real health probing; DNS and HTTP APIs; also does config + KVLoses availability under quorum loss; more moving parts; heavier ops
Plain DNS (SRV records)Server-side, dumbZero new infrastructure; every language already speaks DNSNo health awareness; TTL-driven staleness; no rich metadata; slow to converge

Choose Kubernetes-native discovery when you already run on k8s — rolling your own Eureka there is redundant. Choose Eureka when you are on a JVM/Spring Cloud stack outside k8s and value availability over consistency (routing to a slightly stale list is acceptable). Choose Consul/etcd when you need genuine health checks, cross-language support, and can tolerate a CP registry that stops accepting writes rather than serve stale data. Choose plain DNS only for coarse, slow-changing topologies where operating a registry is not worth it.

Takeaways


Sources: Chris Richardson, Microservices Patterns (Manning) and microservices.io — Service Registry, Client-side / Server-side Discovery patterns; Sam Newman, Building Microservices, 2nd ed. (O'Reilly) on service discovery and DNS trade-offs; the Netflix Eureka and HashiCorp Consul documentation for heartbeat/TTL, self-preservation, and health-check behavior; the Kubernetes documentation on Services, EndpointSlices, and CoreDNS. Re-authored / Deepened for this guide.

🤖 Don't fully get this? Learn it with Claude

Stuck on Service Discovery Pattern A Solution? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🪜 Hint ladder (no spoilers)

Progressively stronger hints — you still solve it.

I'm working on the problem **Service Discovery Pattern A Solution** (System Design). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🎨 Explain the approach visually

See the technique, not just code.

Explain the optimal approach to **Service Discovery Pattern A Solution** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔍 Review my solution

Catch bugs, edge cases, sub-optimality.

I'll paste my solution to **Service Discovery Pattern A Solution**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔁 Drill the pattern

Lock in recognition with look-alikes.

Give me 2 problems that use the SAME underlying pattern as **Service Discovery Pattern A Solution**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes