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
UPorDOWN
Instead of hard-coding locations, microservices ask the registry where other services are. This makes the system flexible and reliable.
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.
start ----> REGISTER ----> heartbeat ... heartbeat ... heartbeat
| |
v v
status: UP clean shutdown: DEREGISTER
crash: heartbeats stop
-> lease expires
-> instance REMOVED
4. What a Registry Stores
| Field | Example | Used for |
|---|---|---|
| Service name / ID | payment-service | Looking up all instances of a service |
| Instance ID | payment-service:7f3c21 | Telling instances of the same service apart |
| Host and port | 10.0.3.17:8083 | Sending requests to the instance |
| Status | UP, DOWN, STARTING, OUT_OF_SERVICE | Deciding whether the instance should get traffic |
| Health check URL | /actuator/health | Checking whether the instance is healthy |
| Metadata | version=2.1, zone=eu-west-1a | Smarter routing, such as same-zone or version-based |
| Lease / last heartbeat | Renewed every 30 s | Removing instances that stopped responding |
5. Self-Registration vs Third-Party Registration
There are two ways for instances to get into the registry:
| Self-registration | Third-party registration | |
|---|---|---|
| Who registers the instance? | The service itself, at startup | A 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 service | Needs a registry client library | None: the service does not know the registry exists |
| Examples | Spring Cloud Eureka client, Consul client | Kubernetes, AWS ECS with Cloud Map, Nomad with Consul |
| Best for | Spring applications on VMs or plain Docker | Container 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 works | Each instance sends “I am alive” messages; the registry removes it if they stop | The registry or an agent calls each instance’s health endpoint regularly |
| Detects a crashed process | Yes, after the lease expires | Yes, after a few failed checks |
| Detects a running but broken instance | Only if the instance reports its own health | Yes, if the health endpoint checks dependencies |
| Load on the registry | Low | Higher: the registry or its agents make the calls |
| Examples | Eureka | Consul, 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
| Tool | Consistency model | Highlights |
|---|---|---|
| Eureka | Availability first (AP) | Widely used with Spring Boot and Netflix OSS; simple to run as a Spring Boot app |
| Consul | Consistency first (CP, Raft) | Discovery, health checks, DNS interface, key-value configuration and service mesh |
| ZooKeeper | Consistency first (CP) | Distributed coordination; used for discovery in older and big-data systems |
| etcd | Consistency first (CP, Raft) | Reliable key-value store; the database behind Kubernetes |
| Nacos | Configurable (AP or CP) | Discovery plus configuration management; popular with Spring Cloud Alibaba |
| Kubernetes | Backed by etcd | Built-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 split | Still answers, possibly with stale entries | Minority side refuses requests |
| Risk | Calling an instance that is already gone | Services cannot look anything up for a while |
| Mitigation | Client timeouts and retries | Run 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:
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
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:
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:
# 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
{
"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:
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:
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:
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();
}
}
# 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:
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.
# 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
| Advantages | Challenges |
|---|---|
| Eliminates hard-coded service locations | The registry itself must be highly available |
| Supports automatic scaling up and down | Extra lookups can add slight latency (reduced by client caching) |
| Improves fault tolerance: unhealthy instances are removed | Entries can be briefly out of date |
| Makes microservices more flexible and independent | Needs proper monitoring and security |
| Enables smarter routing with metadata | Another component to run, unless the platform provides it |
17. Best Practices
- Prefer your platform’s registry, such as Kubernetes, before running a separate one.
- Run the registry as a cluster across availability zones: two or more Eureka peers, or three or five Consul/etcd nodes.
- Connect real health checks to the registry, not just “the process is running”.
- Deregister on shutdown with graceful shutdown, so traffic stops before instances disappear.
- Secure the registry: private network, authentication and TLS.
- Use unique instance IDs, especially with random ports or several instances per host.
- Keep metadata small and meaningful, such as version and zone.
- Make callers resilient with timeouts and retries, because registry data can be slightly stale.
- Monitor the registry: instances per service, expired leases, replication errors and response times.
18. Common Mistakes to Avoid
| Mistake | What goes wrong | Better approach |
|---|---|---|
| A single registry node | If it fails, new instances cannot register or be found | Run a replicated cluster |
| Registry open to anyone | Fake instances can steal traffic | Require authentication and keep it private |
| Health checks that only test “process alive” | Broken instances keep getting traffic | Report real health through Actuator |
| Duplicate instance IDs | Instances overwrite each other in the registry | Generate a unique ID per instance |
| Using the registry as a configuration store | Large, slow registry entries | Use a config server or ConfigMaps for configuration |
| Two registries on Kubernetes | Eureka and Kubernetes can disagree | Use Kubernetes discovery or Spring Cloud Kubernetes |
| Ignoring stale entries | Calls to dead instances fail | Use 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.
20. Frequently Asked Questions (FAQ)
Q1. What is a service registry in simple words?
A service registry is a live list of all running service instances and where to reach them. Instances add themselves when they start, keep proving they are alive, and are removed when they stop.
Other services look up names in this list instead of using fixed addresses, a bit like asking a hotel reception for a guest’s room number.
Q2. Is a service registry the same as service discovery?
No, but they belong together. The registry is the directory that stores the data. Service discovery is the process of using it: registering instances, looking them up and choosing one to call.
You can think of the registry as the phone book and discovery as making the call.
Q3. What is the difference between self-registration and third-party registration?
- Self-registration: each service registers and deregisters itself, using a client library, such as the Spring Cloud Eureka client.
- Third-party registration: a separate component, such as Kubernetes, watches running instances and updates the registry for them. Services need no registry code at all.
Third-party registration is more robust and language-independent; self-registration is simple when you are not on a container platform.
Q4. Which service registry should I choose?
- On Kubernetes: use the built-in registry (Services and EndpointSlices).
- Spring-only systems on VMs or plain Docker: Eureka is simple and well integrated.
- Mixed languages or when you also need key-value configuration and DNS: Consul.
- Spring Cloud Alibaba ecosystems: Nacos.
Avoid running two registries for the same services.
Q5. Why is Eureka called an AP registry?
In a network split, Eureka prefers to stay available: every node keeps answering, even if its list may be slightly out of date. In CAP terms, it favors Availability and Partition tolerance over strict consistency.
For discovery this is usually a good trade-off: a stale entry causes one failed call that the client retries elsewhere, while an unavailable registry would stop all lookups.
Q6. How many registry nodes should I run?
- Eureka: at least two peers, ideally in different availability zones.
- Consul, ZooKeeper, etcd: an odd number, usually three or five, because they need a majority to agree. Three nodes survive one failure; five survive two.
A single node is only acceptable for local development.
Q7. What happens to running services if the whole registry goes down?
With Eureka, clients keep a local cache of the registry, so services that already know each other can usually keep calling for some time. However, new instances cannot register, crashed instances are not removed, and newly started services cannot find anything.
Treat a registry outage as urgent, and design for it with clustering and client-side caching.
Q8. What do the instance statuses UP, DOWN, STARTING and OUT_OF_SERVICE mean?
| Status | Meaning | Gets traffic? |
|---|---|---|
UP | Running and healthy | Yes |
STARTING | Still starting up | No |
DOWN | Unhealthy, for example a failed health check | No |
OUT_OF_SERVICE | Deliberately taken out, such as for maintenance | No |
Q9. Should a service register before it is fully ready?
It should not receive traffic before it is ready. Register with a STARTING status, or connect readiness to the registry, so the instance is marked UP only after it has finished startup, warmed caches and connected to its database.
On Kubernetes, a readiness probe does exactly this: a pod is added to the Service’s endpoints only when the probe succeeds.
Q10. Can I store configuration in the service registry?
Only small, discovery-related metadata, such as version, zone or protocol. Application configuration, such as timeouts, feature flags or connection strings, belongs in a configuration system: Spring Cloud Config, Kubernetes ConfigMaps and Secrets, or Consul’s separate key-value store.
Large registry entries slow down every lookup and replication.
Q11. How do I take an instance out of service without stopping it?
Change its status to OUT_OF_SERVICE. With Eureka you can do this through its REST API or Spring Boot Actuator, and with Consul by enabling maintenance mode for the instance.
Callers stop sending new requests, but the instance keeps running, so you can debug it, collect diagnostics or let running work finish before shutting it down.
Q12. Why do Eureka service names appear in upper case?
Eureka stores application names in upper case, so payment-service appears as PAYMENT-SERVICE on the dashboard and in the REST API.
Lookups are not case-sensitive, so your code can keep using the lower-case name from spring.application.name.
Q13. How does the registry handle many instances on the same host?
Each instance needs a unique instance ID and its own port. With Spring Cloud you can use a random port and a random ID:
server:
port: 0
eureka:
instance:
instance-id: ${spring.application.name}:${random.value}
Without unique IDs, instances on the same host replace each other’s entries, and some instances never receive traffic.
Q14. How do I secure communication with the registry?
- Keep the registry on a private network.
- Require authentication, for example HTTP Basic with Spring Security for Eureka, or ACL tokens for Consul.
- Use TLS for all registry traffic.
- Store registry credentials as secrets, never in Git.
An open registry lets an attacker register a fake instance and receive other services’ traffic.
Q15. What are EndpointSlices in Kubernetes?
EndpointSlices are the Kubernetes objects that hold the list of ready pod addresses behind a Service. Kubernetes updates them automatically as pods start, stop or fail readiness checks.
They are effectively the registry entries for each service. Kube-proxy and service meshes read them to route traffic, and Spring Cloud Kubernetes can expose them through the DiscoveryClient API.
Q16. How do I monitor a service registry?
- Number of instances per service, with alerts when it drops to zero.
- Expired leases or failing health checks.
- Replication errors between registry nodes.
- Registry availability and response times.
- For Eureka, whether self-preservation mode is active.
Q17. Can a service registry support blue-green or canary deployments?
Yes, with metadata. Register new instances with, for example, version=2.1. A gateway or load balancer can then send a small share of traffic, or only test users, to instances with the new version.
Once the new version proves stable, shift all traffic to it and remove the old instances. Kubernetes and service meshes offer similar features with labels and traffic rules.
Q18. Is a DNS server a service registry?
In a simple sense, yes: DNS maps names to addresses. But a classic DNS server lacks key registry features: automatic registration, health checks and fast removal of failed instances. DNS answers are also cached, so changes spread slowly.
Modern registries such as Consul and Kubernetes therefore combine a real registry with a DNS interface, giving you both dynamic updates and easy lookups.
Q19. How do I test services that depend on a registry?
- In unit and slice tests, disable discovery with
spring.cloud.discovery.enabled=false. - In integration tests, configure a fixed list of instances, or start a real registry with Testcontainers, such as a Consul container.
- In a local environment, run the registry and services together with Docker Compose.
Q20. Is Netflix Eureka still maintained?
Yes. Although Netflix stopped developing some of its other open-source libraries, Eureka is still maintained, and Spring Cloud Netflix Eureka remains part of current Spring Cloud releases.
Other Netflix projects that used to be paired with it, such as Ribbon and Zuul 1, have been replaced in Spring Cloud by Spring Cloud LoadBalancer and Spring Cloud Gateway.