Spring Cloud Microservices in Action Part 2: Implementing Service Registration and Discovery with Nacos
After splitting a monolithic blog into independent services, this article explains how to solve the core problem of locating services by introducing Nacos as a registration center, detailing its installation, configuration, service registration, discovery, load balancing, health‑checking, common pitfalls, and a complete hands‑on example.
Problem: Service discovery after splitting the blog system
After decomposing the monolith into user-service (http://localhost:8081), article-service (http://localhost:8082) and comment-service (http://localhost:8083), the article service must call the user service to obtain author information. Hard‑coded URLs cause address changes, port changes, inability to detect service up/down, and no load‑balancing across multiple instances.
Core concepts of service registration and discovery
Service registration : When a service starts, it reports its IP and port to a registration center.
Service discovery : When a service needs to call another, it queries the registration center for the target’s address list.
Heartbeat check : The registration center periodically checks whether a service instance is alive and automatically removes it when it goes offline.
Nacos introduction and installation
Why choose Nacos
Officially recommended by Spring Cloud Alibaba and backed by Alibaba.
Provides both service discovery and configuration management in one solution.
Powerful out‑of‑the‑box console.
Installation
Download, extract and start Nacos in standalone mode:
wget https://github.com/alibaba/nacos/releases/download/2.2.3/nacos-server-2.2.3.tar.gz
tar -zxvf nacos-server-2.2.3.tar.gz
cd nacos/bin
sh startup.sh -m standalone
# console: http://localhost:8848/nacos (default user/password: nacos/nacos)Docker Compose (recommended):
version: '3'
services:
nacos:
image: nacos/nacos-server:latest
container_name: nacos
environment:
- MODE=standalone
- PREFER_HOST_MODE=hostname
ports:
- "8848:8848"
- "9848:9848"
restart: always docker-compose up -dRegister services with Nacos
1. Add Maven dependencies
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.5.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>2. Configure Nacos address (application.yml example)
server:
port: 8081
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: dev # optional, for environment isolation
group: BLOG_GROUP # optional3. Enable registration
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}4. Verify registration
Start the service and open the Nacos console ( http://localhost:8848/nacos). The service list should show entries such as user-service and article-service with a healthy instance count of 1.
Service discovery (calling other services)
1. RestTemplate + @LoadBalanced
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced // enables client‑side load balancing
public RestTemplate restTemplate() {
return new RestTemplate();
}
} @Service
public class ArticleService {
@Autowired
private RestTemplate restTemplate;
public ArticleDetailVO getArticleWithAuthor(Long articleId, Long authorId) {
String url = "http://user-service/user/" + authorId; // service name instead of IP+port
User user = restTemplate.getForObject(url, User.class);
// business logic …
return articleDetail;
}
}2. OpenFeign (more concise)
Add the Feign starter:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>Declare a Feign client:
@FeignClient(name = "user-service")
public interface UserFeignClient {
@GetMapping("/user/{id}")
Result<User> getUser(@PathVariable("id") Long id);
@GetMapping("/user/batch")
List<User> getUsers(@RequestParam("ids") List<Long> ids);
}Use it like a local method:
@Service
public class ArticleService {
@Autowired
private UserFeignClient userFeignClient;
public ArticleDetailVO getArticleWithAuthor(Long articleId, Long authorId) {
User user = userFeignClient.getUser(authorId).getData();
// …
return articleDetail;
}
}Enable Feign in the application:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // enables Feign
public class ArticleServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ArticleServiceApplication.class, args);
}
}Load balancing across multiple instances
1. Start multiple instances
# First instance (default 8081)
java -jar user-service.jar
# Second instance (custom port 8085)
java -jar user-service.jar --server.port=8085The Nacos console will display both instances as healthy.
2. Load‑balancing strategy
Spring Cloud Ribbon defaults to Round‑Robin:
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRuleSwitch to a random rule by defining a bean:
@Bean
@LoadBalanced
public IRule ribbonRule() {
return new RandomRule(); // alternatives: WeightedResponseTimeRule, BestAvailableRule
}Service health check
1. Default health check
Client sends a heartbeat every 5 seconds.
If no heartbeat for 15 seconds, the instance is marked unhealthy.
If no heartbeat for 30 seconds, the instance is removed.
2. Custom health check
spring:
cloud:
nacos:
discovery:
health-check-url: /actuator/health
heart-beat-interval: 5000 # ms
heart-beat-timeout: 15000 # ms
ip-delete-timeout: 30000 # ms3. Proactive offline (graceful shutdown)
@RestController
public class HealthController {
@Autowired
private NacosDiscoveryProperties nacosProperties;
@Autowired
private NacosServiceManager nacosServiceManager;
@PostMapping("/offline")
public String offline() {
nacosServiceManager.getNacosDiscover()
.removeInstance(nacosProperties.getService(),
nacosProperties.getIp(),
nacosProperties.getPort(),
nacosProperties.getClusterName());
return "offline success";
}
}Hands‑on example: Blog system service registration
1. Project structure
blog-micro/
├── user-service/ # port 8081
│ ├── pom.xml
│ └── application.yml
├── article-service/ # port 8082
│ ├── pom.xml
│ └── application.yml
├── comment-service/ # port 8083
│ ├── pom.xml
│ └── application.yml
└── pom.xml2. Service configuration (user‑service example)
server:
port: 8081
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: ${NACOS_HOST:localhost}:8848
namespace: blog-dev3. Inter‑service calls (Feign)
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/api/user/{id}")
UserDTO getUser(@PathVariable("id") Long id);
}
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/api/user/batch")
List<UserDTO> batchGetUsers(@RequestParam("ids") List<Long> ids);
}4. Start and verify
# Start Nacos
docker-compose up -d
# Build services
mvn clean package
# Run each service
java -jar user-service/target/user-service.jar
java -jar article-service/target/article-service.jar
java -jar comment-service/target/comment-service.jar
# Open console
open http://localhost:8848/nacosCommon issues and troubleshooting
Issue 1: Service not registered
Symptom : Service starts but does not appear in the Nacos console.
Check that spring.cloud.nacos.discovery.server-addr points to the correct Nacos host.
Verify network connectivity (e.g., telnet localhost 8848).
Inspect logs for messages such as “No service to register” or “Connection refused”.
Issue 2: Service call fails (UnknownHostException)
Symptom : java.net.UnknownHostException: user-service Cause : RestTemplate is not annotated with @LoadBalanced.
Fix :
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}Issue 3: Frequent up/down flapping
Symptom : Service alternates between healthy and unhealthy.
Cause : Heartbeat interval or timeout is too aggressive, or the service processes requests too slowly.
Fix (adjust Nacos discovery settings):
spring:
cloud:
nacos:
discovery:
heart-beat-interval: 2000 # shorten interval
heart-beat-timeout: 6000 # relax timeoutIssue 4: Cross‑environment service mixing
Symptom : Development services call test‑environment instances.
Solution : Use separate namespaces for isolation.
spring:
cloud:
nacos:
discovery:
namespace: dev # development
# namespace: test # test environmentSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Coder Trainee
Experienced in Java and Python, we share and learn together. For submissions or collaborations, DM us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
