Cloud Native 17 min read

How Nacos Registers Services: Deep Dive into AP/CP Modes and Source Code

This article dissects Nacos's service registration mechanism from both client and server perspectives, explaining how it supports both AP and CP consistency models, the core classes involved, and practical debugging steps for developers working with Spring Cloud Alibaba.

Ops Development Stories
Ops Development Stories
Ops Development Stories
How Nacos Registers Services: Deep Dive into AP/CP Modes and Source Code

In this article we analyze Nacos's service registration process from a source‑code perspective, covering both the server side and the client side that uses spring-cloud-alibaba as the core client component.

Environment

JDK 1.8
nacos-server-1.4.2
spring-boot-2.3.5.RELEASE
spring-cloud-Hoxton.SR8
spring-cloud-alibaba-2.2.5.RELEASE

Nacos Architecture

When built on Spring Boot, Nacos sits in the service architecture as shown below.

Middlewares with similar functionality include Eureka, Zookeeper, Consul, and Etcd. Nacos’s unique feature is its ability to support both AP and CP modes, using the Raft protocol for strong consistency.

Nacos Client

Service Registration Client

Adding Dependency

Import the dependency:

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

The client initiates registration via Spring events. The core auto‑configuration class is NacosServiceRegistryAutoConfiguration, which defines three beans:

NacosServiceRegistry
NacosRegistration
NacosAutoServiceRegistration

NacosAutoServiceRegistration

This class extends AbstractAutoServiceRegistration and implements ApplicationContextAware and ApplicationListener<WebServerInitializedEvent>. After the container starts, onApplicationEvent triggers bind(event), which eventually calls start() and then register() to invoke serviceRegistry.register().

public void onApplicationEvent(WebServerInitializedEvent event) {
    bind(event);
}

public void bind(WebServerInitializedEvent event) {
    // omitted context checks
    this.port.compareAndSet(0, event.getWebServer().getPort());
    this.start();
}

public void start() {
    if (!isEnabled()) {
        return;
    }
    if (!this.running.get()) {
        this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));
        register();
        if (shouldRegisterManagement()) {
            registerManagement();
        }
        this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));
        this.running.compareAndSet(false, true);
    }
}

private void register() {
    this.serviceRegistry.register(getRegistration());
}

NacosServiceRegistry

The register method creates a NamingService instance, builds an Instance from the registration data, and calls namingService.registerInstance.

public void register(Registration registration) {
    if (StringUtils.isEmpty(registration.getServiceId())) {
        log.warn("No service to register for nacos client...");
        return;
    }
    NamingService namingService = namingService();
    String serviceId = registration.getServiceId();
    String group = nacosDiscoveryProperties.getGroup();
    Instance instance = getNacosInstanceFromRegistration(registration);
    try {
        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,
                registration.toString(), e);
        rethrowRuntimeException(e);
    }
}

Service Registration on the Server

Nacos can operate in both AP and CP modes. The server stores instances via InstanceController#register, which parses the request and calls serviceManager.registerInstance. The underlying ConsistencyService decides which consistency protocol to use.

@CanDistro
@PostMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {
    String namespaceId = WebUtils.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
    String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
    NamingUtils.checkServiceNameFormat(serviceName);
    Instance instance = parseInstance(request);
    serviceManager.registerInstance(namespaceId, serviceName, instance);
    return "ok";
}

The ConsistencyService implementation is selected by mapConsistencyService(key):

private ConsistencyService mapConsistencyService(String key) {
    return KeyBuilder.matchEphemeralKey(key) ? ephemeralConsistencyService : persistentConsistencyService;
}

AP Mode

AP mode uses the Distro protocol via EphemeralConsistencyService. The put method persists data and notifies other nodes.

public void put(String key, Record value) throws NacosException {
    onPut(key, value);
    distroProtocol.sync(new DistroKey(key, KeyBuilder.INSTANCE_LIST_KEY_PREFIX), DataOperation.CHANGE,
            globalConfig.getTaskDispatchPeriod() / 2);
}

CP Mode

CP mode relies on Raft via PersistentConsistencyServiceDelegateImpl. Its put method forwards the update to the Raft core.

public void put(String key, Record value) throws NacosException {
    checkIsStopWork();
    try {
        raftCore.signalPublish(key, value);
    } catch (Exception e) {
        Loggers.RAFT.error("Raft put failed.", e);
        throw new NacosException(NacosException.SERVER_ERROR, "Raft put failed, key:" + key + ", value:" + value, e);
    }
}

During signalPublish, the leader node persists the datum, notifies peers, and waits for a majority of acknowledgments before confirming success.

public void signalPublish(String key, Record value) throws Exception {
    if (!isLeader()) {
        // forward to leader
        return;
    }
    OPERATE_LOCK.lock();
    try {
        // build datum and publish
        CountDownLatch latch = new CountDownLatch(peers.majorityCount());
        // async post to peers
        // await majority
        if (!latch.await(UtilsAndCommons.RAFT_PUBLISH_TIMEOUT, TimeUnit.MILLISECONDS)) {
            throw new IllegalStateException("data publish failed, caused failed to notify majority, key=" + key);
        }
    } finally {
        OPERATE_LOCK.unlock();
    }
}

Whether a client instance is stored in AP or CP mode depends on the ephemeral flag during registration: ephemeral=true uses AP (Distro), while ephemeral=false uses CP (Raft).

Nacos Source Debugging

Nacos Startup Files

Locate the Nacos startup JAR ( target/nacos-server.jar) and extract it:

# Extract the JAR
tar -zxvf nacos-server.jar

# View MANIFEST.MF
cat META-INF/MANIFEST.MF

The Start-Class entry reveals the Spring Boot entry point com.alibaba.nacos.Nacos, which can be run directly from an IDE for debugging.

References

http://nacos.io

https://github.com/alibaba/nacos/issues/3000

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

source-code-analysisNacosService RegistrationSpring Cloud AlibabaAP/CP
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

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.