Introduction to Nacos
Nacos is a comprehensive platform designed for building cloud-native applications, offering dynamic service discovery, configuration management, and service governance capabilities.
Evolution of Service Discovery
Hardcoded HTTP Invocations
Directly invoking remote endpoints using HTTP clients requires hardcoded URLs. Any changes on the server side, such as endpoint paths or request parameters, demand synchronous modifications in the client code, leading to tight coupling and maintenance overhead.
@SpringBootTest
class RemoteCallTest {
@Autowired
private RestTemplate restTemplate;
@Test
void invokeRemote() {
String endpoint = "http://api.corp.com/employee/update";
Employee emp = new Employee();
emp.setId(101);
emp.setName("TechNova");
emp.setRole("Engineer");
Employee response = restTemplate.postForObject(endpoint, emp, Employee.class);
System.out.println(response);
}
}
Reverse Proxy Aggregation
Using a reverse proxy like Nginx to maintain an upstream server list centralizes routing. However, as the number of services grows, managing the Nginx configuration file becomes increasingly complex and cumbersome.
Centralized Registry Approach
A service registry like Nacos allows instances to register themselves. Consumers query the registry to obtain available endpoints before executing calls. However, this raises resilience concerns: what happens if the registry itself crashes, or if a target service fails immediately after the consumer retrieves its address?
Heartbeat-Based Resilient Registry
To address these issues, Nacos implements a heartbeat mechanism. Registered services send periodic heartbeats (typically every 5 seconds) to the Nacos server to indicate they are alive. If Nacos does not receive a heartbeat within 15 seconds, the instance is marked as unhealthy and becomes invisible to consumers. If no heartbeat arrives within 30 seconds, the instance is permanently evicted from the registry. Services can also gracefully deregister upon shutdown.
When a consumer invokes a provider, it periodically fetches the list of healthy instances from Nacos, caches them locally, and utilizes a client-side load balancer to distribute requests, eliminating the need for server-side load balancing via Nginx.
Integrating Nacos Discovery
By including the Nacos Discovery starter in a Spring Boot application, services automatically register with the Nacos server. The integration dynamically senses service state changes and refreshes the local service list, registering host, port, and URL metadata.
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
Core Mechanisms
Service Registration
The Nacos client sends a REST request to the Nacos server upon startup, submitting its metadata (host, port, context path). The server stores this information in an in-memory double-layered map structure.
Service Heartbeats
After registration, the client maintains a scheduled heartbeat task to continuously notify the server of its active status, preventing accidental eviction.
Cluster Synchronization
In a clustered Nacos deployment, server nodes synchronize registered service data among themselves to ensure consistency across the registry cluster.
Service Discovery
Consumers request the list of healthy providers from the Nacos server via REST calls. The retrieved list is cached locally, and a scheduled task periodically queries the server to update the cache, ensuring the consumer always targets viable instances.
Health Monitoring
The Nacos server runs scheduled tasks to monitor instance health. Missing 15 seconds of heartbeats marks an instance as unhealthy (blocking consumer access). Missing 30 seconds results in outright eviction from the registry.
Comparison as a Service Registry
Nacos currently offers the most extensive feature set and is widely adopted. Eureka, which has ceased active development, is being phased out in many organizations. Zookeeper is predominantly paired with Dubbo but lacks built-in load balancing. Consul also provides robust registry capabilities.
Considering the CAP theorem (Consistency, Availability, Partition Tolerance), the characteristics of these registries differ:
| Feature | Nacos | Eureka | Zookeeper | Consul |
|---|---|---|---|---|
| Consistency Protocol | CP + AP | AP | CP | CP |
| Access Protocol | HTTP/DNS | HTTP | TCP | HTTP/DNS |
| Health Check | TCP/HTTP/MYSQL/Client Beat | Client Beat | Keep Alive | TCP/HTTP/gRPC/Cmd |
| Load Balancing | Weight/Metadata/Selector | Ribbon | - | Fabio |
| Snowflake Protection | Yes | Yes | No | No |
| Auto Deregistration | Yes | Yes | Yes | Yes |
| Listening | Yes | Yes | Yes | Yes |
| Multi-Datacenter | Yes | Yes | Yes | No |
| Cross-Registry Sync | Yes | No | No | Yes |
| Spring Cloud Integration | Yes | Yes | Yes | Yes |
| Dubbo Integration | Yes | No | Yes | Yes |
| Kubernetes Integration | Yes | No | Yes | No |
Nacos as a Configuration Center
Spring Boot Integration
Nacos manages configurations using a key-value format, providing externalized configuration support for distributed systems.
Maven Dependency:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
Configuration Properties:
spring.application.name=config-client-app
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
app.info.title=EngineeringHub
app.info.stack=Java
Application Bootstrap:
@SpringBootApplication
public class ConfigClientApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ConfigClientApp.class, args);
String title = context.getEnvironment().getProperty("app.info.title");
String stack = context.getEnvironment().getProperty("app.info.stack");
System.err.println("Platform: " + title + " | Stack: " + stack);
}
}
Dynamic Configuration Refresh
Nacos supports near-real-time configuration updates. The client polls for changes, refreshing the local environment dynamically.
@SpringBootApplication
public class DynamicConfigApp {
public static void main(String[] args) throws InterruptedException {
ConfigurableApplicationContext context = SpringApplication.run(DynamicConfigApp.class, args);
while(true) {
String title = context.getEnvironment().getProperty("app.info.title");
String stack = context.getEnvironment().getProperty("app.info.stack");
System.err.println("Platform: " + title + " | Stack: " + stack);
TimeUnit.SECONDS.sleep(1);
}
}
}
Profile-Specific Configuration
Configurations can be granularly managed based on Spring profiles, allowing distinct settings for different environments.
Namespace Isolation
Custom namespaces facilitate resource isolation, such as separating development and production environments (e.g., dev vs. prod).
Custom Group Configuration
By default, configurations reside in the DEFAULT_GROUP. Custom groups can be specified to organize configurations logically:
spring.cloud.nacos.config.group=DEVELOPMENT_GROUP
Configuration Priority
The priority order for loading configurations is: profile-specific > default configuration > extension-configs (higher index equals higher priority) > shared-configs (higher index equals higher priority).
Dynamic Refresh with @RefreshScope
While @Value annotations traditionally inject static configuration values, combining them with @RefreshScope enables beans to dynamically reflect configuration changes without restarting the application.
Comparison with Spring Cloud Config
Spring Cloud Config relies on Git for storage and requires Spring Cloud Bus to broadcast configuration changes to clients. It also lacks a built-in management UI. Conversely, Nacos utilizes a long-pulling mechanism for instant configuration updates, outperforming Spring Cloud Config in responsiveness and offering an intuitive visual console.