AlgoInsight

System Design

What Is Service Discovery?

In a modern system, services are constantly being created, destroyed, and moved - so how does one service ever find another? Service discovery is the answer, and it's the quiet machinery that makes microservices possible.

By Admin2026-06-1813 min readservice-discoverymicroservicesdistributed-systemssystem-designarchitecturenetworking

In a simple system, finding a service is easy: it lives at a fixed address you hardcode and never think about again. But modern systems aren't simple. In a cloud or microservices environment, services are constantly spinning up and shutting down, scaling out and back in, crashing and restarting - each time potentially on a different machine with a different address. The service you need to call might be at one address now and a completely different one a minute from now.

So how does one service reliably find another when addresses are constantly changing? That's the problem service discovery solves. It's the mechanism that lets services locate each other dynamically, without hardcoded addresses - and it's essential, invisible infrastructure underneath almost every microservices system. This guide explains what service discovery is, why dynamic environments make it necessary, the two main approaches, and the tools that implement it.

The problem: addresses won't hold still

To appreciate service discovery, you have to feel the problem it solves. Picture a system with dozens of microservices. The order service needs to call the payment service. In the old world, you'd configure the order service with the payment service's address - payment-service is at 10.0.1.5 - and be done.

But in a modern environment, that breaks constantly:

Hardcoding addresses simply doesn't work when addresses are ephemeral. You need a dynamic, always-current way to answer the question: "where are the healthy instances of the service I need right now?"


The solution: a service registry

At the heart of service discovery is a service registry - a central, always-current database of which services exist and where they're located. Think of it as a constantly updated phone book for services: instead of looking up a fixed address, a service asks the registry "where is the payment service?" and gets back the current, healthy addresses.

The registry works through a continuous cycle:

  1. Registration. When a service instance starts up, it registers itself with the registry - announcing "I'm an instance of the payment service, and I'm at this address." When it shuts down, it deregisters.
  2. Health checking. The registry continually checks whether registered instances are still alive and healthy (often via heartbeats or health-check probes). If an instance stops responding, the registry removes it, so dead instances aren't handed out.
  3. Discovery. When a service needs to call another, it queries the registry to get the current list of healthy addresses for that service, and picks one to send its request to.
sequenceDiagram
    participant P as Payment Service (new instance)
    participant R as Service Registry
    participant O as Order Service
    P->>R: register "payment-service @ 10.0.1.7"
    R->>P: health check (heartbeat)
    P->>R: still alive ✓
    O->>R: where is payment-service?
    R->>O: healthy instances: [10.0.1.7, 10.0.1.9]
    O->>P: send request to 10.0.1.7
This sequence diagram shows service discovery in action. A new payment service instance registers itself with the service registry, announcing its address. The registry health-checks it via heartbeat and confirms it's alive. Later, the order service asks the registry where the payment service is, and the registry returns the list of currently healthy instances. The order service then sends its request to one of them.

The registry is the single source of truth for "what's running and where," kept current by registration and health checks. Everything else in service discovery is about how services register and how they query.


Two approaches: client-side vs server-side discovery

There are two main patterns for how the discovery actually happens, and the difference is who does the work of looking up and choosing an instance.

Client-side discovery

In client-side discovery, the calling service does the work itself. It queries the registry directly, gets the list of healthy instances, and chooses one (applying a load-balancing algorithm like round robin) - then sends the request straight to that instance.

Server-side discovery

In server-side discovery, the client doesn't deal with the registry at all. It simply sends its request to a fixed point - a load balancer or router - and that component queries the registry, picks a healthy instance, and forwards the request.

Client-Side Discovery Server-Side Discovery
Who queries the registry The calling service A load balancer / router
Client complexity Higher (needs discovery logic) Lower (just calls one address)
Network hops Direct (fewer) Extra hop through the balancer
Logic location Duplicated in each client Centralized in the balancer
Best for Performance-sensitive, controlled environments Simplicity, polyglot systems

Server-side discovery is common in cloud and container platforms because it keeps services simple and centralizes the logic - but client-side discovery is efficient and gives clients more control. Many systems use a mix.


How services register: self vs third-party

There's also a choice in how instances get into the registry:

In many modern platforms, the orchestration system (the thing that runs and schedules your containers) handles registration automatically - services come and go, and the platform keeps the registry current without the services doing anything. This is part of why container orchestration and service discovery are so tightly linked.


Common tools

Service discovery is usually provided by a dedicated tool rather than built from scratch. The well-known ones:

In many container platforms, service discovery is built in - the platform automatically registers services and lets others find them by name, so much of this happens without you configuring a separate tool. Whichever tool is used, the underlying concept is the same: a current registry, kept fresh by registration and health checks, that services query to find each other.


A worked example: a request finds its way

To see service discovery in action, trace a single call in a microservices system. The order service needs to charge a customer, so it must call the payment service - but it doesn't know where the payment service is, because instances are constantly changing.

With client-side discovery, here's what happens: the order service asks the service registry, "where is the payment service?" The registry, kept current by each payment instance registering itself and passing health checks, responds with the current healthy addresses - say two instances. The order service applies a load-balancing choice (round robin, perhaps), picks one, and sends its request directly to that instance.

A minute later, traffic spikes and three more payment instances start up. Each registers itself with the registry on startup. Now when the order service next asks, it gets five addresses instead of two - automatically, with no configuration change anywhere. And if one of those instances crashes, it fails its health check, the registry drops it, and the order service simply stops being handed that dead address. The whole system adapts to instances appearing and disappearing without anyone touching a config file. That continuous, automatic adaptation is exactly what service discovery provides.

Why DNS alone isn't always enough

You might wonder: isn't this just DNS? DNS does translate names to addresses, and DNS-based discovery is a real, lightweight option. But plain DNS has limitations in a fast-changing environment. DNS responses are cached - by clients and resolvers - for a period (the TTL), so when an instance dies or a new one appears, it can take time for that change to propagate. In an environment where instances come and go in seconds, that lag can mean traffic is sent to dead instances or new instances sit unused. Dedicated service discovery tools react faster and integrate health checking directly, so the registry reflects reality more quickly than DNS caching allows. DNS-based discovery works well when changes are infrequent; purpose-built discovery shines when instances are highly dynamic.

The registry must be reliable

A subtle but critical point: the service registry is itself a piece of infrastructure that everything depends on - so if it fails, services can't find each other and the whole system can grind to a halt. This makes the registry a potential single point of failure, which is why it's run as a distributed, replicated system rather than a single instance. Tools like etcd and ZooKeeper are built precisely for this: they maintain a consistent, replicated store across multiple nodes so the registry survives individual failures. The registry's reliability is foundational - a discovery system is only as dependable as the registry at its heart.

Service mesh: the modern evolution

In large microservices systems, service discovery has evolved into a broader pattern called a service mesh. Instead of each service handling discovery, load balancing, and retries itself, a lightweight proxy (a "sidecar") runs alongside each service and handles all of that network communication transparently. The mesh manages service discovery, load balancing, health checking, retries, and security between services - taking that logic out of the application code entirely. The services just make calls as if to local addresses, and the mesh figures out where everything actually is. A service mesh is, in essence, service discovery and traffic management elevated into dedicated infrastructure, which is increasingly how large systems handle the problem at scale.

The challenges discovery introduces

Like every building block, service discovery solves a problem but adds considerations of its own. The registry must be highly available and consistent - a stale or unavailable registry breaks discovery. Health checks must be tuned: too aggressive and healthy-but-slow instances get dropped, too lenient and dead instances linger (the same trade-off heartbeats face). And there's a propagation delay between an instance's state changing and every client learning about it, which systems must tolerate gracefully. None of these is a reason to avoid service discovery - it's essential in dynamic environments - but they're the realities you design around, which is why mature platforms invest so heavily in making the registry fast, consistent, and reliable.


Where it fits with other building blocks

Service discovery doesn't work alone - it interlocks with several other components:

Together these make a microservices system navigable: services can find and call each other reliably even as instances constantly appear, disappear, and move.

Interview: If a system design discussion involves microservices, mentioning service discovery shows you understand how the pieces actually communicate. A strong point: "Since instances are dynamic, I'd use a service registry with health checks so services can find healthy instances by name rather than hardcoded addresses - either client-side discovery for efficiency or server-side through a load balancer to keep services simple." Recognizing that hardcoded addresses don't work in a dynamic environment, and naming the registry-plus-health-check solution, signals real understanding of how distributed systems are wired together.


The bottom line

Service discovery is the mechanism that lets services find each other in a dynamic environment where addresses are constantly changing. At its core is a service registry - a current directory of which services exist and where, kept accurate through registration and health checks. Services find each other either through client-side discovery (the client queries the registry and picks an instance itself) or server-side discovery (a load balancer does it on the client's behalf), and registration happens via self-registration or a third-party registrar - often automatically in modern container platforms.

It's invisible infrastructure, but it's what makes microservices viable: without it, dynamic, scaling, failing services couldn't reliably find one another. We cover how it fits into a complete architecture across System Design Fundamentals.


Go deeper

More articles