Cloud Native 14 min read

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.

Coder Trainee
Coder Trainee
Coder Trainee
Spring Cloud Microservices in Action Part 2: Implementing Service Registration and Discovery with Nacos

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 -d

Register 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      # optional

3. 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=8085

The 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.RoundRobinRule

Switch 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    # ms

3. 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.xml

2. Service configuration (user‑service example)

server:
  port: 8081

spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: ${NACOS_HOST:localhost}:8848
        namespace: blog-dev

3. 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/nacos

Common 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 timeout

Issue 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 environment
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.

microservicesload balancingService DiscoveryNacosService RegistrationSpring CloudHealth Check
Coder Trainee
Written by

Coder Trainee

Experienced in Java and Python, we share and learn together. For submissions or collaborations, DM us.

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.