Nacos注册中心实战笔记:从入门到精通
在微服务架构中,服务注册与发现是基础核心组件。Nacos作为阿里巴巴开源的服务发现、配置管理和服务管理平台,已经成为Spring Cloud生态中的重要成员。本文将详细介绍Nacos的使用方法,帮助你快速掌握这一强大的服务治理工具。
什么是Nacos?
Nacos(Dynamic Naming and Configuration Service)是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它提供了一组简单易用的特性,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos的核心功能:
- 服务发现与服务健康监测
- 动态配置管理
- 动态DNS服务
- 服务及其元数据管理
- 负载均衡
Nacos vs Eureka vs Consul
在选择微服务注册中心时,我们通常会考虑Nacos、Eureka和Consul这三种主流方案。下面是它们的简要对比:
特性 | Nacos | Eureka | Consul |
---|---|---|---|
一致性协议 | CP+AP | AP | CP |
健康检查 | TCP/HTTP/MYSQL/Client Beat | Client Beat | TCP/HTTP/gRPC/Cmd |
负载均衡 | 权重/metadata/Selector | Ribbon | Fabio |
雪崩保护 | 有 | 有 | 无 |
自动注销实例 | 支持 | 支持,但实例需要等待3个心跳周期才能被清除 | 支持 |
访问协议 | HTTP/DNS/RPC | HTTP | HTTP/DNS |
监听支持 | 支持 | 支持 | 支持 |
多数据中心 | 支持 | 支持 | 支持 |
跨注册中心 | 支持 | 不支持 | 支持 |
SpringCloud集成 | 支持 | 支持 | 支持 |
Dubbo集成 | 支持 | 不支持 | 不支持 |
K8S集成 | 支持 | 不支持 | 支持 |
Nacos的优势在于:
- 同时支持CP和AP模式切换
- 支持服务注册与发现和配置管理
- 支持多语言客户端
- 支持Dubbo和Spring Cloud生态
- 界面友好,操作简单
安装与启动Nacos Server
下载安装
- 从Nacos GitHub Release下载最新稳定版
- 解压到指定目录,如
D:\nacos
单机模式启动
进入bin
目录,执行以下命令启动Nacos:
Windows:
startup.cmd -m standalone
Linux/Mac:
sh startup.sh -m standalone
访问控制台
启动成功后,通过浏览器访问:http://localhost:8848/nacos
默认账号密码:nacos/nacos
Docker方式启动
docker run --name nacos-standalone -e MODE=standalone -p 8848:8848 -d nacos/nacos-server:latest
Nacos集群部署
在生产环境,为保证高可用,通常需要部署Nacos集群。以下是简要步骤:
准备3台及以上服务器
配置cluster.conf
在conf
目录下创建cluster.conf
文件,添加以下内容:192.168.16.101:8848 192.168.16.102:8848 192.168.16.103:8848
配置数据库
默认情况下,Nacos使用内嵌数据库Derby存储数据,集群模式下需要使用MySQL。- 创建数据库,执行
conf/nacos-mysql.sql
脚本 - 修改
conf/application.properties
文件:spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user=root db.password=password
- 创建数据库,执行
启动集群
在每台服务器上启动Nacos:sh startup.sh
Spring Cloud集成Nacos
1. 添加依赖
在pom.xml
中添加依赖:
<dependencies>
<!-- Spring Cloud Alibaba Nacos Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Spring Cloud Alibaba Nacos Config (如需配置中心) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. 配置服务注册
在application.yml
中配置:
spring:
application:
name: service-provider
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
# 以下是可选配置
namespace: public # 命名空间ID
group: DEFAULT_GROUP # 分组
cluster-name: DEFAULT # 集群名称
weight: 1 # 权重
metadata:
version: v1 # 版本
env: dev # 环境
3. 启用服务注册与发现
在启动类上添加注解:
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
4. 服务发现与负载均衡
使用@LoadBalanced
注解,整合RestTemplate实现负载均衡:
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
使用示例:
@RestController
public class TestController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/test")
public String test() {
// 直接使用服务名调用
return restTemplate.getForObject("http://service-provider/api/hello", String.class);
}
}
Nacos作为配置中心
Nacos不仅可以作为注册中心,还能作为配置中心使用。
1. 添加配置中心依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2. 创建bootstrap.yml
从Spring Cloud 2020版本开始,bootstrap.yml不会自动加载,需要添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
然后创建bootstrap.yml
:
spring:
application:
name: service-provider
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml # 配置文件格式
# 以下是可选配置
namespace: public # 命名空间ID
group: DEFAULT_GROUP # 分组
refresh-enabled: true # 是否开启自动刷新
# 扩展配置
extension-configs:
- data-id: common-mysql.yaml # 配置文件名
group: COMMON_GROUP # 所在分组
refresh: true # 是否动态刷新
- data-id: common-redis.yaml
group: COMMON_GROUP
refresh: true
3. 在Nacos控制台添加配置
- 登录Nacos控制台
- 进入”配置管理” -> “配置列表”
- 点击”+”按钮添加配置
- Data ID: service-provider.yaml (与spring.application.name和file-extension组合)
- Group: DEFAULT_GROUP
- 配置内容:
server: port: 8081 user: name: nacos-user age: 18
4. 读取配置
使用@RefreshScope
注解实现配置自动刷新:
@RestController
@RequestMapping("/config")
@RefreshScope
public class ConfigController {
@Value("${user.name}")
private String name;
@Value("${user.age}")
private Integer age;
@GetMapping("/info")
public Map<String, Object> getConfig() {
Map<String, Object> map = new HashMap<>();
map.put("name", name);
map.put("age", age);
return map;
}
}
也可以使用@ConfigurationProperties
绑定配置:
@Component
@ConfigurationProperties(prefix = "user")
@RefreshScope
@Data
public class UserConfig {
private String name;
private Integer age;
}
Nacos高级特性
1. 命名空间和分组
Nacos提供了命名空间(Namespace)和分组(Group)的概念,用于隔离不同环境或业务线的配置和服务。
- Namespace:用于环境隔离,如开发、测试、生产环境
- Group:用于业务隔离,如不同的业务模块
创建新的命名空间:
- 在Nacos控制台点击”命名空间”
- 点击”新建命名空间”,填写ID、名称和描述
- 点击”确定”
在配置中指定命名空间和分组:
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: dev # 命名空间ID,非名称
group: SHOPPING_SERVICE # 分组名称
config:
server-addr: 127.0.0.1:8848
namespace: dev
group: SHOPPING_SERVICE
2. 服务权重和保护阈值
Nacos支持设置服务实例的权重,用于控制负载均衡比例:
spring:
cloud:
nacos:
discovery:
weight: 2 # 权重值,默认为1
保护阈值是一个0到1之间的浮点数:
- 当健康实例占总实例的比例小于保护阈值时,无论实例是否健康,都会将其返回给客户端,这样可以保证服务的可用性
- 在Nacos控制台可以为每个服务设置保护阈值
3. 元数据管理
可以为服务添加自定义元数据,用于服务治理:
spring:
cloud:
nacos:
discovery:
metadata:
version: v1
env: dev
region: cn-shanghai
4. Nacos的数据模型
Nacos的数据模型由三元组(Namespace, Group, Service/DataId)组成,提供了高度的配置和服务隔离能力:
- Namespace:租户/环境隔离
- Group:分组隔离
- Service/DataId:服务/配置标识
5. 配置加密与安全
对于敏感配置,可以结合Jasypt等工具进行加密:
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
配置示例:
jasypt:
encryptor:
password: your-secret-key
spring:
datasource:
password: ENC(encrypted-password)
Nacos监控与管理
1. Nacos自带监控
Nacos自带的控制台提供了基本的监控功能:
- 服务列表与健康状态
- 服务实例详情
- 配置管理与版本历史
2. 对接Prometheus和Grafana
Nacos可以通过Actuator暴露监控指标,结合Prometheus和Grafana实现更强大的监控:
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
配置Actuator:
management:
endpoints:
web:
exposure:
include: '*'
metrics:
export:
prometheus:
enabled: true
然后配置Prometheus抓取这些指标,并在Grafana中创建仪表盘进行可视化。
实战案例:商品服务与订单服务
以下是一个实际案例,演示如何使用Nacos实现服务注册发现和配置管理:
1. 公共模块 (common-api)
// 商品实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private Long id;
private String name;
private BigDecimal price;
private Integer stock;
}
// 订单实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Long id;
private Long productId;
private Integer quantity;
private BigDecimal amount;
private String address;
private Date createTime;
}
2. 商品服务 (product-service)
// 启动类
@SpringBootApplication
@EnableDiscoveryClient
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
// 控制器
@RestController
@RequestMapping("/api/products")
public class ProductController {
private static final Map<Long, Product> PRODUCT_DB = new ConcurrentHashMap<>();
static {
PRODUCT_DB.put(1L, new Product(1L, "iPhone 13", new BigDecimal("5999"), 100));
PRODUCT_DB.put(2L, new Product(2L, "MacBook Pro", new BigDecimal("12999"), 50));
PRODUCT_DB.put(3L, new Product(3L, "iPad Pro", new BigDecimal("5999"), 80));
}
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return PRODUCT_DB.get(id);
}
@GetMapping
public List<Product> getAllProducts() {
return new ArrayList<>(PRODUCT_DB.values());
}
@PutMapping("/{id}/stock")
public Product updateStock(@PathVariable Long id, @RequestParam Integer quantity) {
Product product = PRODUCT_DB.get(id);
if (product == null) {
throw new RuntimeException("Product not found");
}
if (product.getStock() < quantity) {
throw new RuntimeException("Insufficient stock");
}
product.setStock(product.getStock() - quantity);
return product;
}
}
3. 订单服务 (order-service)
// 启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
// Feign客户端
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("/api/products/{id}")
Product getProductById(@PathVariable("id") Long id);
@PutMapping("/api/products/{id}/stock")
Product updateStock(@PathVariable("id") Long id, @RequestParam("quantity") Integer quantity);
}
// 配置类(从Nacos读取配置)
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "order")
@Data
public class OrderConfig {
private BigDecimal taxRate;
private BigDecimal discountRate;
private boolean enableExpress;
}
// 控制器
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private ProductClient productClient;
@Autowired
private OrderConfig orderConfig;
private AtomicLong orderIdGenerator = new AtomicLong(1);
@PostMapping
public Order createOrder(@RequestBody CreateOrderRequest request) {
// 1. 查询商品信息
Product product = productClient.getProductById(request.getProductId());
if (product == null) {
throw new RuntimeException("Product not found");
}
// 2. 计算订单金额(考虑税率和折扣)
BigDecimal amount = product.getPrice()
.multiply(new BigDecimal(request.getQuantity()))
.multiply(BigDecimal.ONE.subtract(orderConfig.getDiscountRate()))
.multiply(BigDecimal.ONE.add(orderConfig.getTaxRate()));
// 3. 扣减库存
productClient.updateStock(product.getId(), request.getQuantity());
// 4. 创建订单
Order order = new Order();
order.setId(orderIdGenerator.getAndIncrement());
order.setProductId(request.getProductId());
order.setQuantity(request.getQuantity());
order.setAmount(amount);
order.setAddress(request.getAddress());
order.setCreateTime(new Date());
return order;
}
}
Nacos配置示例(order-service.yaml):
order:
tax-rate: 0.06
discount-rate: 0.1
enable-express: true
常见问题与解决方案
1. 服务注册失败
问题:服务无法注册到Nacos
解决方案:
- 检查Nacos服务器是否正常运行
- 确认服务的配置(server-addr, namespace, group)是否正确
- 检查网络连接,确保可以访问Nacos服务
- 查看应用日志,分析具体错误信息
2. 配置无法更新
问题:修改了Nacos配置,但服务未生效
解决方案:
- 确认配置项是否使用了@RefreshScope注解
- 检查配置的DataId、Group是否正确
- 验证命名空间是否匹配
- 检查refresh-enabled是否设置为true
- 调用/actuator/refresh端点手动刷新
3. 服务发现延迟
问题:新注册的服务需要等待较长时间才能被发现
解决方案:
- 调整客户端的缓存刷新时间
- 检查健康检查间隔时间配置
- 优化集群网络环境
4. 集群同步问题
问题:Nacos集群节点数据不同步
解决方案:
- 确保集群配置正确
- 检查MySQL数据库连接是否正常
- 验证网络连通性
- 检查JDK版本兼容性
总结
Nacos作为一站式服务发现、配置管理和服务治理平台,为微服务架构提供了强大的基础支持。