Backend Development 20 min read

Deep Dive into Nacos Service Registration and Discovery Mechanisms

This article explains the underlying principles of Nacos as a service registry, covering registration flow, health‑checking, dynamic service awareness, the architecture diagram, key source‑code components, and how service discovery works in Spring Cloud micro‑service environments.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Deep Dive into Nacos Service Registration and Discovery Mechanisms

1. Nacos Overview

Before discussing Nacos, we introduce the problems of service registration and discovery in micro‑service architectures. Consumers need to know the addresses of provider instances, and providers must keep their address lists up to date, which is solved by a service registry offering address management, registration, and dynamic awareness.

Key Features of Nacos

Service discovery and health monitoring (supports DNS and RPC)

Dynamic configuration management

Dynamic DNS routing with weight‑based load balancing

Service and metadata management

2. Nacos Registration Center Implementation

2.1 Architecture Diagram

The Nacos ecosystem consists of the following modules:

Provider APP : Service provider.

Consumer APP : Service consumer.

Name Server : Provides high‑availability routing via Virtual IP or DNS.

Nacos Server : Core Nacos service. OpenAPI – entry point for functionality. Config Service & Naming Service – configuration and naming modules. Consistency Protocol – Raft‑based data synchronization.

Nacos Console : Management UI.

Summary : Providers register through the VIP to the Nacos cluster, using OpenAPI; Nacos Server synchronizes data across nodes via Raft.

2.2 Registration Principle

Registration involves three steps: the instance registers on startup, health checking (heartbeat) is performed, and finally the instance is recorded in the registry.

public interface ServiceRegistry
{
    void register(R registration);
    void deregister(R registration);
    void close();
    void setStatus(R registration, String status);
T getStatus(R registration);
}

In Nacos, NacosServiceRegistry implements this interface. The Spring Cloud auto‑configuration loads AutoServiceRegistrationAutoConfiguration , which injects AutoServiceRegistration . The concrete class NacosAutoServiceRegistration listens for WebServerInitializedEvent and triggers registration.

public void register(Registration registration) {
    if (StringUtils.isEmpty(registration.getServiceId())) {
        log.warn("No service to register for nacos client...");
    } else {
        String serviceId = registration.getServiceId();
        String group = this.nacosDiscoveryProperties.getGroup();
        Instance instance = getNacosInstanceFromRegistration(registration);
        try {
            this.namingService.registerInstance(serviceId, group, instance);
            log.info("nacos registry, {} {} {}:{} register finished", group, serviceId, instance.getIp(), instance.getPort());
        } catch (Exception e) {
            log.error("nacos registry, {} register failed...", serviceId, e);
            ReflectionUtils.rethrowRuntimeException(e);
        }
    }
}

The registerInstance method creates a BeatInfo for heartbeat monitoring and then calls serverProxy.registerService to send an OpenAPI request.

public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    if (instance.isEphemeral()) {
        BeatInfo beatInfo = new BeatInfo();
        beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
        beatInfo.setIp(instance.getIp());
        beatInfo.setPort(instance.getPort());
        beatInfo.setCluster(instance.getClusterName());
        beatInfo.setWeight(instance.getWeight());
        beatInfo.setMetadata(instance.getMetadata());
        beatInfo.setScheduled(false);
        long interval = instance.getInstanceHeartBeatInterval();
        beatInfo.setPeriod(interval == 0L ? DEFAULT_HEART_BEAT_INTERVAL : interval);
        this.beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);
    }
    this.serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
}

Heartbeat registration ( addBeatInfo ) schedules a periodic task that sends a ping to the server; if the server does not respond, the instance is considered unhealthy.

public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
    LogUtils.NAMING_LOGGER.info("[BEAT] adding beat: {} to beat map.", beatInfo);
    String key = buildKey(serviceName, beatInfo.getIp(), beatInfo.getPort());
    BeatInfo existBeat = dom2Beat.remove(key);
    if (existBeat != null) {
        existBeat.setStopped(true);
    }
    dom2Beat.put(key, beatInfo);
    executorService.schedule(new BeatReactor.BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
    MetricsMonitor.getDom2BeatSizeMonitor().set((double) dom2Beat.size());
}

3. Nacos Source Code Analysis

The analysis focuses on two aspects: service registration and service discovery.

3.1 Service Registration

The registration flow starts with AbstractAutoServiceRegistration listening to WebServerInitializedEvent . When the event fires, NacosAutoServiceRegistration calls super.register() , which ultimately invokes NacosServiceRegistry.register() . This method delegates to the Nacos client SDK's NamingService.registerInstance() .

3.2 Service Discovery

Discovery is triggered when a consumer (e.g., a Feign client) calls a remote interface. The Feign client uses NacosServerList.getServers() , which calls NacosNamingService.selectInstances() to obtain a list of healthy Instance objects.

public List
selectInstances(String serviceName, String groupName, boolean healthy) throws NacosException {
    return this.selectInstances(serviceName, groupName, healthy, true);
}

The HostReactor maintains three maps to cache service information:

serviceInfoMap – local cache of service metadata.

updatingMap – tracks services currently being refreshed.

futureMap – stores scheduled update tasks.

When a service is first requested, getServiceInfo() creates a ServiceInfo object, stores it in the cache, and triggers an immediate update via updateServiceNow() . It also schedules periodic updates with scheduleUpdateIfAbsent() , which creates a UpdateTask that runs every 10 seconds.

public void scheduleUpdateIfAbsent(String serviceName, String clusters) {
    if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) == null) {
        synchronized (futureMap) {
            if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) == null) {
                ScheduledFuture
future = addTask(new HostReactor.UpdateTask(serviceName, clusters));
                futureMap.put(ServiceInfo.getKey(serviceName, clusters), future);
            }
        }
    }
}

Thus, discovery either reads from the local cache (when subscribe=true ) or queries the Nacos server directly (when subscribe=false ).

4. Summary

Nacos integrates registration and discovery into Spring Cloud via the ServiceRegistry interface. Registration occurs automatically after the web server starts, performing health checks and sending an OpenAPI registration request. Discovery retrieves instances through NacosNamingService , caching results locally and refreshing them periodically to ensure high availability.

JavaMicroservicesservice discoveryNacosservice registrationSpring Cloud
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.