第33集SpringCloudAlibaba全网最全讲解之Nacos
|字数总计:4.4k|阅读时长:20分钟|阅读量:
引言
在微服务架构中,服务注册与发现是一个核心问题。随着服务数量的增加,服务间的依赖关系变得复杂,如何管理服务的注册、发现、健康检查等问题成为微服务架构的关键挑战。SpringCloudAlibaba Nacos作为阿里巴巴开源的动态服务发现、配置管理和服务管理平台,为微服务架构提供了完整的解决方案。
Nacos不仅提供传统的服务注册与发现功能,还集成了配置管理、服务管理、元数据管理等功能,是一个功能强大的微服务治理平台。通过Nacos,开发者可以轻松构建和管理微服务系统。
本文将深入讲解Nacos的核心概念、配置方式、服务治理机制以及实际应用场景,帮助开发者掌握微服务注册与发现的设计与实现。
Nacos核心概念
1. 什么是服务注册与发现
服务注册与发现是微服务架构中的核心机制,主要包括:
- 服务注册:服务启动时向注册中心注册自己的信息
- 服务发现:客户端从注册中心获取服务实例列表
- 健康检查:注册中心定期检查服务实例的健康状态
- 服务治理:提供服务管理、配置管理、元数据管理等功能
2. Nacos架构特点
graph TB
A[服务提供者] --> B[Nacos Server]
C[服务消费者] --> B
D[配置中心] --> B
E[管理控制台] --> B
B --> F[服务注册表]
B --> G[配置存储]
B --> H[元数据存储]
I[MySQL] --> B
J[集群节点1] --> B
K[集群节点2] --> B
L[集群节点3] --> B
核心特性:
- 服务注册与发现:支持服务的注册、发现和健康检查
- 配置管理:提供动态配置管理和配置推送功能
- 服务管理:提供服务实例管理、权重管理、元数据管理
- 集群部署:支持集群部署,保证高可用性
- 多环境支持:支持多环境、多命名空间管理
3. Nacos与其他注册中心对比
| 特性 |
Nacos |
Eureka |
Consul |
Zookeeper |
| 服务注册与发现 |
✅ |
✅ |
✅ |
✅ |
| 配置管理 |
✅ |
❌ |
✅ |
❌ |
| 健康检查 |
✅ |
✅ |
✅ |
✅ |
| 集群部署 |
✅ |
✅ |
✅ |
✅ |
| 管理界面 |
✅ |
✅ |
✅ |
❌ |
| 性能 |
高 |
中 |
高 |
高 |
| 易用性 |
高 |
高 |
中 |
低 |
Nacos Server安装与配置
1. 环境准备
系统要求:
- JDK 1.8+
- 内存:2GB+
- 存储:根据数据量确定
- 网络:需要访问MySQL等数据库
下载Nacos:
1 2 3 4 5 6
| wget https://github.com/alibaba/nacos/releases/download/2.2.0/nacos-server-2.2.0.tar.gz
tar -xzf nacos-server-2.2.0.tar.gz cd nacos
|
2. 数据库配置
创建数据库:
1 2 3 4 5 6 7 8
| CREATE DATABASE nacos DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE nacos;
source /path/to/nacos/conf/nacos-mysql.sql;
|
配置数据库连接:
1 2 3 4 5 6
| spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=root db.password.0=password
|
3. 启动Nacos Server
单机模式启动:
1 2 3 4 5 6 7 8 9 10 11 12
| sh bin/startup.sh -m standalone
docker run -d -p 8848:8848 \ -e MODE=standalone \ -e SPRING_DATASOURCE_PLATFORM=mysql \ -e MYSQL_SERVICE_HOST=localhost \ -e MYSQL_SERVICE_DB_NAME=nacos \ -e MYSQL_SERVICE_USER=root \ -e MYSQL_SERVICE_PASSWORD=password \ nacos/nacos-server:latest
|
集群模式启动:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| sh bin/startup.sh
version: '3.8' services: nacos1: image: nacos/nacos-server:latest container_name: nacos1 environment: - MODE=cluster - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=mysql - MYSQL_SERVICE_DB_NAME=nacos - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=password - NACOS_SERVERS=nacos1:8848,nacos2:8848,nacos3:8848 ports: - "8848:8848" depends_on: - mysql
nacos2: image: nacos/nacos-server:latest container_name: nacos2 environment: - MODE=cluster - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=mysql - MYSQL_SERVICE_DB_NAME=nacos - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=password - NACOS_SERVERS=nacos1:8848,nacos2:8848,nacos3:8848 ports: - "8849:8848" depends_on: - mysql
nacos3: image: nacos/nacos-server:latest container_name: nacos3 environment: - MODE=cluster - SPRING_DATASOURCE_PLATFORM=mysql - MYSQL_SERVICE_HOST=mysql - MYSQL_SERVICE_DB_NAME=nacos - MYSQL_SERVICE_USER=root - MYSQL_SERVICE_PASSWORD=password - NACOS_SERVERS=nacos1:8848,nacos2:8848,nacos3:8848 ports: - "8850:8848" depends_on: - mysql
mysql: image: mysql:8.0 container_name: mysql environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_DATABASE=nacos ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql
volumes: mysql_data:
|
4. 访问控制台
访问地址:
主要功能:
- 服务管理:查看和管理服务实例
- 配置管理:管理应用配置
- 集群管理:管理Nacos集群
- 权限管理:管理用户和权限
Spring Boot集成Nacos
1. 项目依赖配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2022.0.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
|
2. 配置文件设置
bootstrap.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| spring: application: name: nacos-demo-service cloud: nacos: discovery: server-addr: localhost:8848 namespace: dev group: DEFAULT_GROUP cluster-name: default metadata: version: 1.0.0 region: beijing zone: zone1 config: server-addr: localhost:8848 namespace: dev group: DEFAULT_GROUP file-extension: yaml shared-configs: - data-id: common-config.yaml group: COMMON_GROUP refresh: true extension-configs: - data-id: database-config.yaml group: COMMON_GROUP refresh: true
|
application.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server: port: 8080
app: name: nacos-demo-service version: 1.0.0 description: Nacos Demo Service
logging: level: com.alibaba.nacos: DEBUG com.alibaba.cloud.nacos: DEBUG
|
3. 启动类配置
1 2 3 4 5 6 7
| @SpringBootApplication @EnableDiscoveryClient public class NacosDemoApplication { public static void main(String[] args) { SpringApplication.run(NacosDemoApplication.class, args); } }
|
服务注册与发现
1. 服务提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| @RestController @RequestMapping("/api") @Slf4j public class UserController {
@Autowired private UserService userService;
@GetMapping("/users/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { log.info("获取用户信息,用户ID: {}", id);
User user = userService.findById(id); return ResponseEntity.ok(user); }
@GetMapping("/users") public ResponseEntity<List<User>> getAllUsers() { log.info("获取所有用户");
List<User> users = userService.findAll(); return ResponseEntity.ok(users); }
@PostMapping("/users") public ResponseEntity<User> createUser(@RequestBody User user) { log.info("创建用户: {}", user.getName());
User createdUser = userService.create(user); return ResponseEntity.ok(createdUser); }
@GetMapping("/health") public ResponseEntity<String> health() { return ResponseEntity.ok("OK"); } }
|
2. 服务消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| @Service @Slf4j public class UserService {
@Autowired private DiscoveryClient discoveryClient;
@Autowired private RestTemplate restTemplate;
public User getUserById(Long id) { try { log.info("调用用户服务获取用户信息: {}", id);
List<ServiceInstance> instances = discoveryClient.getInstances("user-service"); if (instances.isEmpty()) { throw new ServiceException("用户服务不可用"); }
ServiceInstance instance = instances.get(0); String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/api/users/" + id;
User user = restTemplate.getForObject(url, User.class); log.info("用户服务调用成功: {}", user);
return user; } catch (Exception e) { log.error("用户服务调用失败: {}", e.getMessage(), e); throw new ServiceException("获取用户信息失败", e); } }
public List<User> getAllUsers() { try { log.info("调用用户服务获取所有用户");
List<ServiceInstance> instances = discoveryClient.getInstances("user-service"); if (instances.isEmpty()) { throw new ServiceException("用户服务不可用"); }
ServiceInstance instance = instances.get(0); String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/api/users";
List<User> users = restTemplate.getForObject(url, List.class); log.info("用户服务调用成功,用户数量: {}", users.size());
return users; } catch (Exception e) { log.error("用户服务调用失败: {}", e.getMessage(), e); throw new ServiceException("获取用户列表失败", e); } } }
|
3. 使用Feign进行服务调用
1 2 3 4 5 6 7 8 9 10 11 12
| @FeignClient(name = "user-service") public interface UserServiceClient {
@GetMapping("/api/users/{id}") User getUserById(@PathVariable("id") Long id);
@GetMapping("/api/users") List<User> getAllUsers();
@PostMapping("/api/users") User createUser(@RequestBody User user); }
|
服务治理功能
1. 服务实例管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| @RestController @RequestMapping("/api/admin") @Slf4j public class ServiceManagementController {
@Autowired private NacosDiscoveryProperties nacosDiscoveryProperties;
@Autowired private NacosServiceManager nacosServiceManager;
@GetMapping("/services/{serviceName}/instances") public ResponseEntity<List<Instance>> getServiceInstances(@PathVariable String serviceName) { try { List<Instance> instances = nacosServiceManager.getInstances(serviceName); return ResponseEntity.ok(instances); } catch (Exception e) { log.error("获取服务实例失败: {}", e.getMessage(), e); return ResponseEntity.status(500).body(null); } }
@PutMapping("/services/{serviceName}/instances/{instanceId}/weight") public ResponseEntity<String> updateInstanceWeight( @PathVariable String serviceName, @PathVariable String instanceId, @RequestParam double weight) { try { nacosServiceManager.updateInstanceWeight(serviceName, instanceId, weight); return ResponseEntity.ok("权重更新成功"); } catch (Exception e) { log.error("更新实例权重失败: {}", e.getMessage(), e); return ResponseEntity.status(500).body("权重更新失败"); } }
@PutMapping("/services/{serviceName}/instances/{instanceId}/enabled") public ResponseEntity<String> updateInstanceEnabled( @PathVariable String serviceName, @PathVariable String instanceId, @RequestParam boolean enabled) { try { nacosServiceManager.updateInstanceEnabled(serviceName, instanceId, enabled); return ResponseEntity.ok("实例状态更新成功"); } catch (Exception e) { log.error("更新实例状态失败: {}", e.getMessage(), e); return ResponseEntity.status(500).body("实例状态更新失败"); } } }
|
2. 服务元数据管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Service @Slf4j public class ServiceMetadataService {
@Autowired private NacosServiceManager nacosServiceManager;
public void updateServiceMetadata(String serviceName, Map<String, String> metadata) { try { nacosServiceManager.updateServiceMetadata(serviceName, metadata); log.info("服务元数据更新成功: {}", serviceName); } catch (Exception e) { log.error("服务元数据更新失败: {}", e.getMessage(), e); throw new ServiceException("服务元数据更新失败", e); } }
public Map<String, String> getServiceMetadata(String serviceName) { try { return nacosServiceManager.getServiceMetadata(serviceName); } catch (Exception e) { log.error("获取服务元数据失败: {}", e.getMessage(), e); throw new ServiceException("获取服务元数据失败", e); } } }
|
3. 服务健康检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @Component @Slf4j public class ServiceHealthChecker {
@Autowired private DiscoveryClient discoveryClient;
@Scheduled(fixedRate = 30000) public void checkServiceHealth() { try { List<String> services = discoveryClient.getServices();
for (String serviceName : services) { List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
for (ServiceInstance instance : instances) { boolean isHealthy = checkInstanceHealth(instance); log.info("服务实例健康检查: {} - {} - {}", serviceName, instance.getHost() + ":" + instance.getPort(), isHealthy); } } } catch (Exception e) { log.error("服务健康检查失败: {}", e.getMessage(), e); } }
private boolean checkInstanceHealth(ServiceInstance instance) { try { String healthUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/actuator/health";
RestTemplate restTemplate = new RestTemplate(); restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
ResponseEntity<String> response = restTemplate.getForEntity(healthUrl, String.class); return response.getStatusCode().is2xxSuccessful(); } catch (Exception e) { log.warn("实例健康检查失败: {} - {}", instance.getHost() + ":" + instance.getPort(), e.getMessage()); return false; } } }
|
配置管理
1. 动态配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @RestController @RequestMapping("/api/config") @Slf4j @RefreshScope public class ConfigController {
@Value("${app.name:default}") private String appName;
@Value("${app.version:1.0.0}") private String appVersion;
@Value("${app.timeout:5000}") private Integer timeout;
@GetMapping("/info") public ResponseEntity<Map<String, Object>> getConfigInfo() { Map<String, Object> config = new HashMap<>(); config.put("appName", appName); config.put("appVersion", appVersion); config.put("timeout", timeout);
return ResponseEntity.ok(config); } }
|
2. 配置监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Component @Slf4j public class ConfigChangeListener {
@NacosConfigListener(dataId = "nacos-demo-service-dev.yaml", groupId = "DEFAULT_GROUP") public void onConfigChange(String configInfo) { log.info("配置发生变更: {}", configInfo);
try { Yaml yaml = new Yaml(); Map<String, Object> config = yaml.load(configInfo);
handleConfigChange(config);
} catch (Exception e) { log.error("配置解析失败", e); } }
private void handleConfigChange(Map<String, Object> config) { log.info("处理配置变更: {}", config); } }
|
3. 配置管理服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| @Service @Slf4j public class ConfigManagementService {
@Autowired private ConfigService configService;
public boolean publishConfig(String dataId, String group, String content) { try { boolean result = configService.publishConfig(dataId, group, content); log.info("配置发布成功: dataId={}, group={}", dataId, group); return result; } catch (Exception e) { log.error("配置发布失败: {}", e.getMessage(), e); return false; } }
public String getConfig(String dataId, String group) { try { String config = configService.getConfig(dataId, group, 5000); log.info("配置获取成功: dataId={}, group={}", dataId, group); return config; } catch (Exception e) { log.error("配置获取失败: {}", e.getMessage(), e); return null; } }
public boolean removeConfig(String dataId, String group) { try { boolean result = configService.removeConfig(dataId, group); log.info("配置删除成功: dataId={}, group={}", dataId, group); return result; } catch (Exception e) { log.error("配置删除失败: {}", e.getMessage(), e); return false; } } }
|
集群管理
1. 集群配置
1 2 3 4
| 192.168.1.10:8848 192.168.1.11:8848 192.168.1.12:8848
|
2. 集群监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Component @Slf4j public class ClusterMonitor {
@Autowired private NacosServiceManager nacosServiceManager;
@Scheduled(fixedRate = 60000) public void monitorCluster() { try { ClusterInfo clusterInfo = nacosServiceManager.getClusterInfo();
log.info("集群状态: {}", clusterInfo);
boolean isHealthy = checkClusterHealth(clusterInfo);
if (!isHealthy) { log.warn("集群健康检查失败"); sendClusterAlert(clusterInfo); }
} catch (Exception e) { log.error("集群监控失败: {}", e.getMessage(), e); } }
private boolean checkClusterHealth(ClusterInfo clusterInfo) { return true; }
private void sendClusterAlert(ClusterInfo clusterInfo) { log.warn("发送集群告警: {}", clusterInfo); } }
|
监控与运维
1. 指标监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Component @Slf4j public class NacosMetrics {
private final MeterRegistry meterRegistry; private final Counter serviceCounter; private final Timer serviceTimer;
public NacosMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; this.serviceCounter = Counter.builder("nacos.services.total") .description("Total number of services") .register(meterRegistry); this.serviceTimer = Timer.builder("nacos.service.duration") .description("Service discovery duration") .register(meterRegistry); }
public void recordService(String serviceName, String operation) { serviceCounter.increment( Tags.of( "service", serviceName, "operation", operation ) ); }
public Timer.Sample startTimer() { return Timer.start(meterRegistry); } }
|
2. 健康检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Component public class NacosHealthIndicator implements HealthIndicator {
@Autowired private DiscoveryClient discoveryClient;
@Override public Health health() { try { List<String> services = discoveryClient.getServices();
return Health.up() .withDetail("nacos", "connected") .withDetail("services", services.size()) .build();
} catch (Exception e) { return Health.down() .withDetail("nacos", "disconnected") .withDetail("error", e.getMessage()) .build(); } } }
|
3. 服务监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Component @Slf4j public class ServiceMonitor {
@Autowired private DiscoveryClient discoveryClient;
@Scheduled(fixedRate = 30000) public void monitorServices() { try { List<String> services = discoveryClient.getServices();
for (String serviceName : services) { List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
log.info("服务监控: {} - 实例数量: {}", serviceName, instances.size());
recordServiceMetrics(serviceName, instances); }
} catch (Exception e) { log.error("服务监控失败: {}", e.getMessage(), e); } }
private void recordServiceMetrics(String serviceName, List<ServiceInstance> instances) { log.debug("记录服务指标: {} - {}", serviceName, instances.size()); } }
|
常见问题与解决方案
1. 服务注册失败
问题描述: 服务无法注册到Nacos
解决方案:
1 2 3 4 5 6 7 8 9
| spring: cloud: nacos: discovery: server-addr: localhost:8848 namespace: dev group: DEFAULT_GROUP enabled: true
|
2. 服务发现失败
问题描述: 无法发现服务实例
解决方案:
1 2 3 4 5 6 7 8 9
| spring: cloud: nacos: discovery: server-addr: localhost:8848 namespace: dev group: DEFAULT_GROUP cluster-name: default
|
3. 配置不生效
问题描述: 配置变更后不生效
解决方案:
1 2 3 4 5 6 7
| spring: cloud: nacos: config: refresh-enabled: true refresh-timeout: 3000
|
4. 集群连接问题
问题描述: 集群节点连接失败
解决方案:
1 2 3 4 5 6
| spring: cloud: nacos: discovery: server-addr: 192.168.1.10:8848,192.168.1.11:8848,192.168.1.12:8848
|
最佳实践总结
1. 服务设计原则
- 单一职责:每个服务只负责一个业务功能
- 无状态设计:服务实例应该是无状态的
- 健康检查:实现完善的健康检查机制
- 优雅关闭:支持服务的优雅关闭
2. 配置管理
- 环境隔离:使用命名空间进行环境隔离
- 配置分组:合理使用配置分组
- 配置加密:敏感配置进行加密存储
- 配置版本:重要配置变更要有版本记录
3. 监控运维
- 服务监控:监控服务的健康状态和性能指标
- 配置监控:监控配置的变更和生效情况
- 集群监控:监控Nacos集群的健康状态
- 告警机制:建立完善的告警体系
总结
SpringCloudAlibaba Nacos为微服务架构提供了完整的服务注册与发现解决方案。通过本文的详细讲解,我们了解了:
- 核心概念:服务注册与发现的基本原理和Nacos的架构特点
- 安装配置:Nacos Server的安装和配置方法
- 集成使用:Spring Boot与Nacos的集成配置
- 服务治理:服务实例管理、元数据管理、健康检查
- 配置管理:动态配置、配置监听、配置管理服务
- 集群管理:集群配置、集群监控
- 监控运维:指标监控、健康检查、服务监控
- 问题解决:常见问题的排查和解决方案
- 最佳实践:服务设计、配置管理、监控运维
在实际应用中,建议:
- 合理设计服务架构,保持服务的单一职责
- 建立完善的监控和告警机制
- 定期检查服务的健康状态
- 注意配置的安全性和版本管理
通过掌握这些知识和技能,开发者可以构建稳定、高效的微服务系统,实现服务的自动注册与发现。
参考资料
- Nacos官方文档
- SpringCloudAlibaba官方文档
- Nacos服务注册与发现
- 微服务架构最佳实践
- Nacos示例代码