00:00

Service Registry in Microservices

In a microservices architecture, an application is divided into many small services. Each service runs independently and has its own server, port and life cycle. Because instances come and go all the time, services need a reliable way to find each other. This is where the service registry plays a central role.

This guide explains what a service registry is, what it stores, how instances register and stay healthy, how registries balance consistency and availability, and how to run, inspect and secure a registry with Eureka, Consul and Kubernetes.

1. What Is a Service Registry?

A service registry is a central, always-up-to-date directory of running service instances. Every instance registers itself when it starts, and the registry keeps track of:

  • The service name, such as payment-service
  • The IP address and port of each instance
  • The current status, such as UP or DOWN

Instead of hard-coding locations, microservices ask the registry where other services are. This makes the system flexible and reliable.

Real-life analogy: A service registry is like a hotel reception desk. Guests (service instances) check in and share their room numbers. If someone wants to meet a guest, they ask reception instead of knocking on every door. When guests check out, reception removes them from the list.

2. Why Do We Need a Service Registry?

In traditional applications, services run on fixed servers and ports. In microservices:

  • Services scale up or down automatically.
  • IP addresses and ports change frequently, especially with containers.
  • Instances can crash and restart at any time.

Managing these locations by hand is not practical. The service registry solves this by acting as a dynamic directory that updates itself as the system changes. It is the foundation of service discovery.

3. How Does a Service Registry Work?

3.1 Service registration

When a microservice instance starts, it registers with the registry by sending its name, network details and status.

3.2 Service discovery

When one service wants to call another, it asks the registry for the service’s location. The registry responds with the available, healthy instances.

3.3 Health monitoring

The registry continuously checks that registered instances are still alive. If an instance becomes unhealthy or stops, it is removed automatically, so no more traffic is sent to it.

Registry life cycle of one instance
 start ----> REGISTER ----> heartbeat ... heartbeat ... heartbeat
                |                                        |
                v                                        v
           status: UP                         clean shutdown: DEREGISTER
                                              crash: heartbeats stop
                                                 -> lease expires
                                                 -> instance REMOVED

4. What a Registry Stores

FieldExampleUsed for
Service name / IDpayment-serviceLooking up all instances of a service
Instance IDpayment-service:7f3c21Telling instances of the same service apart
Host and port10.0.3.17:8083Sending requests to the instance
StatusUP, DOWN, STARTING, OUT_OF_SERVICEDeciding whether the instance should get traffic
Health check URL/actuator/healthChecking whether the instance is healthy
Metadataversion=2.1, zone=eu-west-1aSmarter routing, such as same-zone or version-based
Lease / last heartbeatRenewed every 30 sRemoving instances that stopped responding

5. Self-Registration vs Third-Party Registration

There are two ways for instances to get into the registry:

Self-registrationThird-party registration
Who registers the instance?The service itself, at startupA separate component, the registrar, that watches the platform
Who deregisters it?The service, at shutdown (plus lease expiry on crash)The registrar, when the platform reports the instance gone
Code in the serviceNeeds a registry client libraryNone: the service does not know the registry exists
ExamplesSpring Cloud Eureka client, Consul clientKubernetes, AWS ECS with Cloud Map, Nomad with Consul
Best forSpring applications on VMs or plain DockerContainer platforms and mixed-language systems

Third-party registration is more robust because it works even if a service is badly written or crashes during startup. That is one reason why platforms such as Kubernetes have become the default registry for many teams.

6. Health Checking: Heartbeats vs Active Checks

Heartbeats (TTL)Active health checks
How it worksEach instance sends “I am alive” messages; the registry removes it if they stopThe registry or an agent calls each instance’s health endpoint regularly
Detects a crashed processYes, after the lease expiresYes, after a few failed checks
Detects a running but broken instanceOnly if the instance reports its own healthYes, if the health endpoint checks dependencies
Load on the registryLowHigher: the registry or its agents make the calls
ExamplesEurekaConsul, Kubernetes readiness and liveness probes

With Eureka, set eureka.client.healthcheck.enabled=true so that an instance whose Actuator health is DOWN also reports DOWN to the registry, and not just a running process.

7. Client-Side and Server-Side Discovery

The registry is used in two styles of discovery:

  • Client-side discovery: the calling service asks the registry directly and decides which instance to call. The client handles load balancing and has more control.
  • Server-side discovery: the client sends the request to a load balancer or gateway, which asks the registry and forwards the request. The client stays simple, and load balancing is handled centrally.

Both styles depend on the same registry. The Service Discovery guide shows them in detail with Spring Cloud code.

8. Popular Service Registry Tools

ToolConsistency modelHighlights
EurekaAvailability first (AP)Widely used with Spring Boot and Netflix OSS; simple to run as a Spring Boot app
ConsulConsistency first (CP, Raft)Discovery, health checks, DNS interface, key-value configuration and service mesh
ZooKeeperConsistency first (CP)Distributed coordination; used for discovery in older and big-data systems
etcdConsistency first (CP, Raft)Reliable key-value store; the database behind Kubernetes
NacosConfigurable (AP or CP)Discovery plus configuration management; popular with Spring Cloud Alibaba
KubernetesBacked by etcdBuilt-in registry through Services and EndpointSlices

9. Consistency vs Availability in Registries

When the network between registry nodes breaks, a distributed registry must choose between two goals (this trade-off is known as the CAP theorem):

  • Availability first (AP): every node keeps answering, even if its data may be slightly out of date. Eureka works this way.
  • Consistency first (CP): nodes only answer if they agree on the latest data; a minority side of a split stops answering. Consul, ZooKeeper and etcd work this way.
Availability first (Eureka)Consistency first (Consul, ZooKeeper, etcd)
During a network splitStill answers, possibly with stale entriesMinority side refuses requests
RiskCalling an instance that is already goneServices cannot look anything up for a while
MitigationClient timeouts and retriesRun an odd number of nodes (3 or 5) across zones

For service discovery, slightly stale data is usually acceptable, because callers retry on another instance. That is why availability-first registries work well here, while consistency-first stores shine when you also need reliable configuration or coordination.

10. A Highly Available Eureka Registry

The registry must never become a single point of failure. Eureka servers can run as a cluster of peers that replicate registrations to each other. Here are two peers, registry-1 and registry-2:

application.yml (registry-1)
server:
  port: 8761

spring:
  application:
    name: service-registry

eureka:
  instance:
    hostname: registry-1
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://registry-2:8762/eureka/   # replicate with the other peer
application.yml (registry-2)
server:
  port: 8762

spring:
  application:
    name: service-registry

eureka:
  instance:
    hostname: registry-2
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://registry-1:8761/eureka/

Both are the same Spring Boot application with @EnableEurekaServer; only the configuration differs. Services then list both peers, so they keep working if one is down:

application.yml (any service)
eureka:
  client:
    service-url:
      defaultZone: http://registry-1:8761/eureka/,http://registry-2:8762/eureka/

Clients also keep a local cache of the registry, so existing calls continue even if every registry node is briefly unreachable. In production, run the peers in different availability zones.

11. Looking Inside the Registry: The Eureka REST API

Eureka exposes its data through a simple REST API, which is useful for debugging and scripts:

Terminal
# All registered applications and instances
curl -H "Accept: application/json" http://localhost:8761/eureka/apps

# Only the instances of one service (names are upper case in Eureka)
curl -H "Accept: application/json" http://localhost:8761/eureka/apps/PAYMENT-SERVICE
Response (shortened)
{
  "application": {
    "name": "PAYMENT-SERVICE",
    "instance": [
      {
        "instanceId": "payment-service:7f3c21",
        "hostName": "10.0.3.17",
        "app": "PAYMENT-SERVICE",
        "ipAddr": "10.0.3.17",
        "status": "UP",
        "port": { "$": 52114, "@enabled": "true" },
        "healthCheckUrl": "http://10.0.3.17:52114/actuator/health",
        "metadata": { "version": "2.1", "zone": "eu-west-1a" },
        "leaseInfo": {
          "renewalIntervalInSecs": 30,
          "durationInSecs": 90
        }
      }
    ]
  }
}

The same API lets operators take an instance out of service temporarily, for example before maintenance, by changing its status to OUT_OF_SERVICE, so it stops receiving traffic without being shut down.

12. Using Instance Metadata

Instances can publish extra information as metadata, such as their version or zone:

application.yml (payment-service v2.1)
eureka:
  instance:
    metadata-map:
      version: "2.1"
      zone: eu-west-1a

Other services can read it through Spring’s DiscoveryClient, for example to call only instances of a specific version during a gradual rollout:

VersionAwareLocator.java
package com.example.order.discovery;

import java.net.URI;
import java.util.List;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;

@Component
public class VersionAwareLocator {

    private final DiscoveryClient discoveryClient;

    public VersionAwareLocator(DiscoveryClient discoveryClient) {
        this.discoveryClient = discoveryClient;
    }

    // Returns the addresses of instances running the requested version
    public List<URI> instancesWithVersion(String serviceName, String version) {
        return discoveryClient.getInstances(serviceName).stream()
                .filter(instance -> version.equals(instance.getMetadata().get("version")))
                .map(ServiceInstance::getUri)
                .toList();
    }
}

Keep metadata small and simple: a few short key-value pairs. The registry is a directory, not a configuration database.

13. Securing the Service Registry

An unprotected registry is risky: anyone who can reach it could register a fake instance and receive other services’ traffic, or remove real instances. Protect it:

  • Keep the registry on a private network, never on the public internet.
  • Require authentication for registering and reading.
  • Use TLS for all registry traffic.

For a Eureka server, add Spring Security with HTTP Basic authentication:

RegistrySecurityConfig.java
package com.example.registry.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class RegistrySecurityConfig {

    @Bean
    public SecurityFilterChain registrySecurity(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/actuator/health").permitAll()
                .anyRequest().authenticated())
            .httpBasic(Customizer.withDefaults())
            // Eureka clients send POST/PUT/DELETE without CSRF tokens
            .csrf(csrf -> csrf.ignoringRequestMatchers("/eureka/**"));
        return http.build();
    }
}
application.yml (registry and clients)
# Registry: the account clients use (pass the real password as an environment variable)
spring:
  security:
    user:
      name: registry-client
      password: ${REGISTRY_PASSWORD}

# Clients: credentials in the registry URL
eureka:
  client:
    service-url:
      defaultZone: http://registry-client:${REGISTRY_PASSWORD}@registry-1:8761/eureka/

14. Registering with Consul

Consul uses active health checks and works with any language. With Spring Cloud, add spring-cloud-starter-consul-discovery and point the service at a Consul agent:

application.yml (payment-service with Consul)
spring:
  application:
    name: payment-service
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        health-check-path: /actuator/health   # Consul calls this endpoint
        health-check-interval: 10s
        instance-id: ${spring.application.name}:${random.value}
        tags:
          - version=2.1

Consul calls each instance’s health endpoint every 10 seconds and marks it as failing if the check fails. Services that are not written in Java can register with Consul through its HTTP API or a configuration file, and any client can find services through Consul’s DNS interface, such as payment-service.service.consul.

15. Kubernetes as a Service Registry

On Kubernetes, the platform itself is the service registry, using third-party registration:

  • Every pod gets an IP address when it starts.
  • A Service selects pods by label, such as app: payment-service.
  • Kubernetes keeps an up-to-date list of the matching, ready pods in EndpointSlices, stored in etcd.
  • Readiness probes decide whether a pod is listed; failing pods are removed automatically.
Terminal
# The registry entries Kubernetes keeps for a service
kubectl get endpointslices -l kubernetes.io/service-name=payment-service

# Example output
NAME                    ADDRESSTYPE   PORTS   ENDPOINTS                         AGE
payment-service-x7k2p   IPv4          8083    10.1.2.14,10.1.3.22,10.1.4.9      3d

Services simply call http://payment-service; no registry client and no registration code are needed. That is why most teams running on Kubernetes do not operate a separate registry such as Eureka.

16. Advantages and Challenges

AdvantagesChallenges
Eliminates hard-coded service locationsThe registry itself must be highly available
Supports automatic scaling up and downExtra lookups can add slight latency (reduced by client caching)
Improves fault tolerance: unhealthy instances are removedEntries can be briefly out of date
Makes microservices more flexible and independentNeeds proper monitoring and security
Enables smarter routing with metadataAnother component to run, unless the platform provides it

17. Best Practices

  1. Prefer your platform’s registry, such as Kubernetes, before running a separate one.
  2. Run the registry as a cluster across availability zones: two or more Eureka peers, or three or five Consul/etcd nodes.
  3. Connect real health checks to the registry, not just “the process is running”.
  4. Deregister on shutdown with graceful shutdown, so traffic stops before instances disappear.
  5. Secure the registry: private network, authentication and TLS.
  6. Use unique instance IDs, especially with random ports or several instances per host.
  7. Keep metadata small and meaningful, such as version and zone.
  8. Make callers resilient with timeouts and retries, because registry data can be slightly stale.
  9. Monitor the registry: instances per service, expired leases, replication errors and response times.

18. Common Mistakes to Avoid

MistakeWhat goes wrongBetter approach
A single registry nodeIf it fails, new instances cannot register or be foundRun a replicated cluster
Registry open to anyoneFake instances can steal trafficRequire authentication and keep it private
Health checks that only test “process alive”Broken instances keep getting trafficReport real health through Actuator
Duplicate instance IDsInstances overwrite each other in the registryGenerate a unique ID per instance
Using the registry as a configuration storeLarge, slow registry entriesUse a config server or ConfigMaps for configuration
Two registries on KubernetesEureka and Kubernetes can disagreeUse Kubernetes discovery or Spring Cloud Kubernetes
Ignoring stale entriesCalls to dead instances failUse timeouts and retries on the client

19. Summary

A service registry is the directory at the heart of microservices. Instances register when they start, prove they are alive with heartbeats or health checks, and are removed when they stop or fail, so other services always find healthy instances by name. Registries differ in how they register instances (self-registration or third-party), how they check health, and whether they favor availability, like Eureka, or consistency, like Consul and etcd. Run your registry as a secure, replicated cluster, or let a platform such as Kubernetes act as the registry for you. With a reliable registry, developers can focus on business logic instead of tracking addresses. Continue with Service Discovery to see how services use the registry to call each other.