Spring Boot High Availability: Nacos Service Discovery, OpenFeign & Sentinel Resilience
This article details how to build highly available Spring Boot microservices using Nacos for service discovery and configuration, OpenFeign for declarative REST calls with load balancing, timeouts, and retries, and Sentinel for circuit breaking and fallback handling, including multi-environment isolation via namespaces and groups.
Why a Registry Center?
After splitting microservices, the biggest headache is how services find each other. With few services, hard‑coding IPs in config files works, but elastic scaling (Pods destroyed/recreated, VMs migrated) makes static addresses impossible. A registry center lets services register themselves on startup and consumers query the list.
What Does a Registry Center Do?
Service Registration: On startup, push IP, port, health status to the registry.
Service Discovery: Consumers pull target service instance lists and pick a healthy one.
Health Checks: The registry monitors instances and removes unhealthy ones.
Selection: Why Nacos?
Eureka (Netflix) is AP‑model, guarantees availability but may return stale data; development stopped at 2.x, Spring Cloud Netflix is in maintenance mode. It only does service discovery, requiring a separate config center.
Consul uses CP (Raft) for strong consistency, but sacrifices availability during network partitions. Its active health checks (HTTP/TCP/gRPC) are thorough, and it integrates with Consul Template and Vault for dynamic config/secrets. However, config management isn’t its core strength and adds operational complexity.
Nacos combines service discovery and config management in one system. It supports both AP (ephemeral instances via client heartbeats) and CP (persistent instances via server‑side probes) modes. If you use Spring Cloud Alibaba, Nacos is the default choice; it also works well standalone.
Setting Up Nacos Server
Standalone (Docker)
docker run -d --name nacos-server \
-p 8848:8848 -p 9848:9848 \
-e MODE=standalone \
nacos/nacos-server:v2.3.2Note: Port 9848 is the gRPC port used by Nacos 2.x clients; omitting it prevents registration. After startup, open http://localhost:8848/nacos (default user/pass: nacos / nacos).
Production Cluster with MySQL
Use MySQL for config/metadata storage and run at least three nodes. Configure conf/application.properties:
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://xxx:3306/nacos?characterEncoding=utf8&serverTimezone=UTC
db.user=root
db.password=xxxStart each node with MODE=cluster and NACOS_SERVERS listing all node addresses:
docker run -d --name nacos-server \
-p 8848:8848 -p 9848:9848 \
-e MODE=cluster \
-e NACOS_SERVERS=10.0.0.1:8848,10.0.0.2:8848,10.0.0.3:8848 \
nacos/nacos-server:v2.3.2Spring Boot Integration: Registration & Discovery
Dependency Versions
Used Spring Boot 2.7.18, Spring Cloud Alibaba 2021.0.5.0. Two BOMs manage versions:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>Both provider and consumer need spring-cloud-starter-alibaba-nacos-discovery and spring-boot-starter-web.
Registration Configuration
In application.yml:
spring:
application:
name: product-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: public
group: DEFAULT_GROUP
metadata:
version: v1.0
author: dev-team
# Multi‑NIC machines may register wrong IP; specify manually
ip: 192.168.1.100
port: 8080 metadatais useful for version, environment, owner — later used for gray routing or monitoring.
Health Check Modes
Nacos uses two modes:
- Ephemeral instances (default): Client heartbeats every 5 s; 15 s missed → unhealthy, 30 s → removed. Suits dynamic scaling (e.g., K8s Pods).
- Persistent instances: Set ephemeral: false; server actively probes via HTTP/TCP. For long‑lived services like DB proxies.
Service Discovery Usage
Spring Cloud’s DiscoveryClient is the standard interface:
@RestController
public class DiscoveryController {
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/instances")
public List<ServiceInstance> instances(@RequestParam String serviceId) {
return discoveryClient.getInstances(serviceId);
}
}But this is only for inspection; actual calls should use OpenFeign.
OpenFeign Declarative Calls
Dependencies
Consumer adds:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>Add @EnableFeignClients on the main class.
Writing a FeignClient
@FeignClient(name = "product-service", fallback = ProductFallback.class)
public interface ProductClient {
@GetMapping("/product/{id}")
ProductDTO getProduct(@PathVariable("id") Long id);
}The name matches the target service name; OpenFeign asks Nacos for instances and LoadBalancer picks one.
Load Balancing
Since Spring Cloud 2020, Ribbon is retired; default is Spring Cloud LoadBalancer (round‑robin). Custom strategies via ServiceInstanceListSupplier, e.g., weighted:
@Bean
public ServiceInstanceListSupplier serviceInstanceListSupplier(
ObjectProvider<LoadBalancerClientFactory> factory) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withWeighted()
.build(factory.getIfUnique());
}Most scenarios round‑robin suffices; avoid over‑engineering.
Timeouts & Retries
Feign defaults: connect 10 s, read 60 s — too long for production. Shorten per service:
spring:
cloud:
openfeign:
client:
config:
default:
connect-timeout: 2000
read-timeout: 3000
product-service:
connect-timeout: 1000
read-timeout: 5000Retries are off by default (risk of duplicate requests unless idempotent). If needed, define a Retryer bean:
@Bean
public Retryer feignRetryer() {
// interval 100ms, max 1000ms, max 3 attempts
return new Retryer.Default(100, 1000, 3);
}Warning: Retries must pair with circuit breaking; otherwise a failing service gets hammered (retry storm).
Sentinel for Circuit Breaking & Fallback
Enable Sentinel Adapter
Add dependency:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>Configure:
feign:
sentinel:
enabled: trueThen specify fallback or fallbackFactory on @FeignClient.
Fallback vs FallbackFactory
Fallback — simple, no exception details:
@Component
public class ProductFallback implements ProductClient {
@Override
public ProductDTO getProduct(Long id) {
return ProductDTO.builder()
.id(id)
.name("默认商品")
.price(0.0)
.build();
}
}Must be a Spring bean ( @Component) so Feign can find it.
FallbackFactory — access to the cause for logging/differentiated handling:
@Slf4j
@Component
public class ProductFallbackFactory implements FallbackFactory<ProductClient> {
@Override
public ProductClient create(Throwable cause) {
return new ProductClient() {
@Override
public ProductDTO getProduct(Long id) {
log.error("调用 product-service 失败,降级", cause);
return ProductDTO.builder().id(id).name("降级商品").build();
}
};
}
}Then use fallbackFactory = ProductFallbackFactory.class.
Circuit Breaker Rules
Define a slow‑call ratio rule in code (or via console):
@PostConstruct
public void initDegradeRule() {
DegradeRule rule = new DegradeRule();
rule.setResource("GET:http://product-service/product/{id}");
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
rule.setCount(500); // max RT 500ms
rule.setTimeWindow(10); // break for 10s
rule.setSlowRatioThreshold(0.5); // slow call ratio > 50%
DegradeRuleManager.loadRules(Collections.singletonList(rule));
}When slow‑call ratio exceeds 50% in a statistical window, Sentinel trips for 10 s, routing directly to fallback — isolating the fault.
Nacos Multi‑Environment Isolation & Service List Management
Namespaces
Simplest isolation: create separate namespaces (dev, test, prod). Each service registers with its namespace:
spring:
cloud:
nacos:
discovery:
namespace: dev-namespace-idGroups
Within a namespace, groups further separate services (e.g., two teams using order-service). Consumers must match the group; OpenFeign defaults to DEFAULT_GROUP.
Console Operations
Instance Online/Offline: Bring an instance online without traffic (graceful deploy), or drain traffic before offline.
Weight: Control traffic proportion; start new version at weight 1, increase after validation.
Protection Threshold: Default 0; set 0.6–0.8. When healthy instance ratio drops below, Nacos returns unhealthy instances too — prevents avalanche on few healthy nodes.
Cluster: Set cluster-name (e.g., SH) on both provider and consumer; Nacos discovery layer returns only same‑cluster instances, enforcing locality without LoadBalancer filtering.
Metadata should include version, Git commit, owner — speeds up incident diagnosis.
Compared to Spring Cloud Kubernetes: How to Choose?
If running on Kubernetes, K8s Service + DNS already provides service discovery; Pods have probes, ConfigMap handles config. Spring Cloud Kubernetes adapts DiscoveryClient and LoadBalancer, so you can skip Nacos entirely — less infrastructure to maintain. However, K8s native discovery is low‑level; fine‑grained traffic management (gray, weights) needs a service mesh like Istio, and config is scattered across ConfigMaps.
For traditional VM deployments or when you need rich service governance (multi‑env config, gray release, weight control), Nacos shines — it’s built for service governance and bundles config center, giving a unified dev experience.
Hybrid approaches exist: registration via Nacos, config via ConfigMap, or vice versa. No absolute right answer; choose what reduces operational burden.
Final Thoughts
The combo (Nacos + OpenFeign + Sentinel) isn’t a silver bullet, but it’s the most cohesive stack in Spring Cloud Alibaba. Registry solves "findability", load balancing solves "distribution", timeouts/retries solve "resilience", circuit breaking solves "fault isolation". Each layer done right gives a baseline of high availability.
Remember: this is just the foundation. Production HA also demands monitoring, alerting, rate limiting, and degradation strategies. Don’t assume Nacos alone guarantees peace of mind.
Signed-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.
Xiaolin Talks Programming
Focuses on sharing original technical insights. Senior architect at a top tech company with years of experience in technical architecture and management, and extensive interview experience. Offers one-on-one technical coaching, guiding you from beginner to architecture design to technical management. Follow for free learning resources. Free one-on-one interview coaching to help you land offers quickly.
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.
