回顾:上篇讲了什么
上一篇我们聊了微服务的核心思想:拆分、自治、解耦、独立演进。理解了这些,再看 Spring Cloud 就不是一套面目模糊的组件清单,而是一套把微服务思想落地的工具集。
但思想终究要在代码里体现。微服务拆开之后,第一个要解决的问题就是:服务之间怎么找到彼此?
这篇就从注册中心入手,用 Nacos 3.x 搭出一个可运行的最小调用链路。
没有注册中心的世界
假如你有两个 Spring Boot 服务:
order-service(订单服务)payment-service(支付服务)
订单服务在创建订单时需要调用支付服务来完成扣款。
最直接的做法:在 order-service 的配置里写死 payment-service 的地址。
payment:
url: http://192.168.1.100:8081
一开始还好,但问题很快就来了:
- 支付服务扩容到三台机器,
order-service怎么知道另外两台在哪? - 某台支付服务挂了,
order-service还在往死地址发请求 - 支付服务迁移到新服务器,所有调用方配置都得改一轮
归根结底一句话:调用方不应该手动管理被调用方的地址。
注册中心就是来解决这个问题的。
注册中心解决什么
注册中心在整个微服务架构里扮演通信枢纽的角色,核心职责只有三个:
服务注册
服务启动时主动向注册中心报到,告诉它「我是谁、我在哪」。比如 payment-service 启动后向 Nacos 注册自己的 IP 和端口。
服务发现
调用方不再写死地址,而是向注册中心查询「谁叫 payment-service」。注册中心返回当前可用的实例列表,调用方从中选一个发起请求。
健康检查
注册中心持续检测每个服务实例是否存活。如果某台 payment-service 挂了,注册中心把它从可用列表中摘掉,调用方自然不会请求到这个死实例。
这三个动作构成一个闭环:注册 → 发现 → 健康检查 → 摘除不健康的 → 继续发现健康的。整个过程中,调用方和被调用方完全解耦。
为什么选 Nacos
Spring Cloud 生态里注册中心的选择不少,但现状是这样的:
- Eureka 是 Spring Cloud Netflix 时代的默认选择,但 Netflix 已于 2018 年宣布 Eureka 进入维护模式,不再开发新功能
- Consul 功能完整但偏重 HashiCorp 生态,与 Spring Cloud 的集成相比 Nacos 少一些「原生感」
- ZooKeeper 是分布式协调老将,但早期设计目标不是服务发现,使用体验不如专用方案
Nacos(Dynamic Naming and Configuration Service)由阿里巴巴开源,同时覆盖注册中心和配置中心两个场景。它的优势在于:
- 对 Spring Cloud 生态的原生支持:
spring-cloud-starter-alibaba-nacos-discovery一行依赖搞定 - 兼顾配置中心:后续讲配置管理时不用再引入新组件
- 社区活跃:3.x 版本持续迭代,是当前 Spring Cloud Alibaba 的推荐版本
一句话:对 Spring Cloud 初学者来说,Nacos 是当前「投入产出比」最高的选择。
环境准备
Docker Compose 启动 Nacos
创建一个 docker-compose.yml:
version: "3.8"
services:
nacos:
image: nacos/nacos-server:v3.2
container_name: nacos-standalone
environment:
- MODE=standalone
- NACOS_AUTH_TOKEN=${your_nacos_auth_secret_token}
- NACOS_AUTH_IDENTITY_KEY=${your_nacos_server_identity_key}
- NACOS_AUTH_IDENTITY_VALUE=${your_nacos_server_identity_value}
ports:
- "8080:8080"
- "8848:8848"
- "9848:9848"
NACOS_AUTH_TOKEN: Nacos 用于生成JWT Token的密钥,使用长度大于32字符的字符串,再经过Base64编码。
NACOS_AUTH_IDENTITY_KEY: Nacos Server端之间 Inner API的身份标识的Key,必填。
NACOS_AUTH_IDENTITY_VALUE: Nacos Server端之间 Inner API的身份标识的Value,必填。
注意 MODE=standalone。Nacos 有两种运行模式:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| standalone | 单节点运行,数据存内嵌 Derby 数据库 | 本地开发、学习 |
| cluster | 多节点组成集群,数据存外部 MySQL | 生产环境 |
集群模式需要至少三个 Nacos 节点配合 MySQL 做数据持久化,才能保证高可用。对我们学习注册中心来说,standalone 完全够用,启动快、无外部依赖、一台机器就能跑。
启动:
docker compose up -d
启动后访问 http://localhost:8848/nacos,默认用户名密码都是 nacos,看到控制台就说明注册中心已在运行。
Java 与 Maven
假定你本地已有 JDK 17+ 和 Maven,不再赘述安装步骤。
动手:两个服务注册到 Nacos
服务提供者:payment-service
创建一个 Spring Boot 项目,引入依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在 application.yml 中配置 Nacos 地址和服务名:
spring:
application:
name: payment-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
server:
port: 8081
暴露一个简单的接口:
@RestController
public class PaymentController {
@GetMapping("/pay")
public String pay() {
return "Payment successful";
}
}
启动类上别忘了加 @EnableDiscoveryClient:
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentServiceApplication {
public static void main(String[] args) {
SpringApplication.run(PaymentServiceApplication.class, args);
}
}
服务消费者:order-service
同样引入 Nacos Discovery 依赖,配置文件:
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
server:
port: 8082
通过 RestTemplate + 服务名调用 payment-service:
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/order")
public String createOrder() {
// 直接用服务名,不用写 IP:Port
String result = restTemplate.getForObject(
"http://payment-service/pay", String.class);
return "Order created. " + result;
}
}
注意 @LoadBalanced 注解——它让 RestTemplate 具备客户端负载均衡能力。当 payment-service 有多个实例时,它会自动选择一个可用的来调用。
验证与观察
顺序启动:
# 先确保 Nacos 已在运行
docker compose up -d
# 启动 payment-service
cd payment-service && mvn spring-boot:run
# 启动 order-service
cd order-service && mvn spring-boot:run
打开 Nacos 控制台 http://localhost:8848/nacos,进入「服务管理 → 服务列表」,应该能看到 payment-service 和 order-service 两个服务都已注册。
浏览器访问 http://localhost:8082/order,返回:
Order created. Payment successful
这条调用链路的完整流程:
order-service收到/order请求- 通过
RestTemplate向http://payment-service/pay发起调用 @LoadBalanced拦截请求,从 Nacos 查询payment-service的实例列表- 选出一个可用实例(目前只有一个,就是
8081),转发请求 payment-service处理/pay并返回结果
你还可以做个验证:停掉 payment-service,观察 Nacos 控制台——十几秒后该实例会被标记为不健康,order-service 的调用会返回错误。这直观展示了健康检查如何保护调用方。
小结与下篇预告
这一篇我们做了三件事:
- 理解注册中心在微服务体系中的角色——服务注册、发现、健康检查
- 用 Docker Compose 启动了 Nacos 3.x,并说清了 standalone vs cluster 的选择
- 实现了一个完整的最小调用链路:
order-service通过 Nacos 发现payment-service并远程调用
现在你手上有一个能跑的微服务雏形。但如果你仔细观察会发现一个问题:@LoadBalanced 目前只有一个实例可选,没有真正发挥负载均衡的价值。
下一篇,我们让 payment-service 跑多个实例,把负载均衡这块讲透。