文章目录
- [CAP 理论基础](#CAP 理论基础)
- 核心概念
- 组件对比
- [Eureka 详细说明](#Eureka 详细说明)
- [Consul 详细说明](#Consul 详细说明)
- [Nacos 详细说明](#Nacos 详细说明)
- 选型建议
- 实战代码示例
-
- [Eureka 实战](#Eureka 实战)
- [Nacos 实战](#Nacos 实战)
-
- 依赖配置
- 配置文件(bootstrap.yml)
- 动态配置刷新
- [服务调用(OpenFeign 方式)](#服务调用(OpenFeign 方式))
- [Consul 实战](#Consul 实战)
CAP 理论基础
在分布式系统中,CAP 定理指出一个分布式系统不可能同时满足以下三个特性:
| 特性 | 说明 |
|---|---|
| C (Consistency) | 一致性,所有节点在同一时间看到的数据是一致的 |
| A (Availability) | 可用性,每个请求都能在合理时间内得到响应(不保证是最新数据) |
| P (Partition Tolerance) | 分区容错性,系统在网络分区发生时仍能继续运行 |
根据 CAP 定理,分布式系统只能同时满足三项中的两项:
CA 系统 - 无分区容错
如:单机 MySQL
CP 系统 - 牺牲可用性
如:Zookeeper, Consul
AP 系统 - 牺牲一致性
如:Eureka, Nacos
各组件的 CAP 定位:
| 组件 | CAP 组合 | 说明 |
|---|---|---|
| Eureka | AP | 优先保证可用性,允许短暂的数据不一致,适合追求高可用的场景 |
| Consul | CP | 基于 Raft 协议保证强一致性,网络分区时可能拒绝服务 |
| Nacos | AP/CP 可切换 | 默认 AP 模式,可通过配置切换为 CP 模式,灵活性更高 |
| Zookeeper | CP | 强一致性保证,但网络分区时可能不可用 |
选择建议:
- AP 模式(Eureka、Nacos-AP):适合对服务可用性要求高的场景,如电商、支付等业务系统
- CP 模式(Consul、Nacos-CP、Zookeeper):适合对数据一致性要求高的场景,如配置中心、分布式锁
核心概念
1. 服务注册(Service Registration)
服务注册是指服务提供者在启动时,将自己的网络信息(IP 地址、端口、服务名等)注册到服务注册中心的过程。注册中心维护着一个服务注册表,记录所有可用服务的位置信息。
2. 服务发现(Service Discovery)
服务发现是指服务消费者从服务注册中心获取可用服务列表,并根据负载均衡策略选择一个服务实例进行调用的过程。服务发现机制使得服务消费者无需知道具体的服务实例地址。
3. 健康检查(Health Check)
健康检查是注册中心定期检查服务实例可用性的机制。通过心跳检测、HTTP 检查等方式,确保只有健康的服务实例才会被包含在服务发现结果中。
4. 故障转移(Failover)
故障转移是指当某个服务实例不可用时,自动将流量转移到其他可用实例的机制。这是服务注册与发现组件提供的重要可靠性保证。
组件对比
| 特性 | Eureka | Consul | Nacos |
|---|---|---|---|
| 开发者 | Netflix | HashiCorp | Alibaba |
| 语言 | Java | Go | Java |
| CAP 模型 | AP | CP | AP/CP 可切换 |
| 一致性协议 | 无(最终一致性) | Raft | Raft(CP)/ Distro(AP) |
| 配置管理 | 不支持 | 支持 | 支持 |
| 多数据中心 | 不支持 | 支持 | 支持 |
| 服务网格 | 不支持 | 支持 | 计划支持 |
| UI 界面 | 简单 | 功能丰富 | 功能丰富 |
| 集群部署 | 简单 | 简单 | 支持集群 |
| 社区活跃度 | 低 | 高 | 高 |
| 健康检查方式 | 心跳(客户端) | TCP/HTTP/Script | 心跳(客户端)/ 服务端主动探测 |
| 服务发现方式 | 客户端发现 | 客户端发现 + DNS | 客户端发现 |
| Spring Cloud 集成 | 原生支持 | Spring Cloud Consul | Spring Cloud Alibaba |
组件状态说明
| 组件 | 状态 | 说明 |
|---|---|---|
| Eureka | 维护模式 | Netflix 已停止 2.x 开源分支开发,1.x 进入维护状态,不建议新项目使用 |
| Consul | 活跃开发 | HashiCorp 持续维护,功能不断完善 |
| Nacos | 活跃开发 | 阿里巴巴开源,国内社区活跃,适合国内技术栈 |
服务注册与发现是微服务架构的核心基础设施。Eureka、Consul、Nacos 各有特点,适用于不同的场景。在实际应用中,需要根据业务需求、技术栈、团队经验等因素选择合适的组件,并做好监控和故障处理机制,确保系统的稳定运行。
Eureka 详细说明
架构设计
Eureka 采用 C-S(Client-Server)架构模式:
- Eureka Server:注册中心,维护服务注册表
- Eureka Client:服务提供者和消费者,负责注册和发现
工作原理
-
服务注册:
- 服务启动时向 Eureka Server 发送注册请求
- Eureka Server 将服务信息添加到注册表
- 服务实例开始定期发送心跳(默认30秒一次)
-
服务发现:
- 服务消费者向 Eureka Server 请求服务注册信息
- Eureka Server 返回可用服务实例列表
- 服务消费者缓存服务信息(默认30秒刷新一次)
-
服务下线:
- 服务正常关闭时发送下线请求
- Eureka Server 将服务从注册表移除
服务注册时序图
Service Registry Eureka Server Service Provider Service Registry Eureka Server Service Provider 服务启动 开始定期发送心跳 loop [每30秒] 注册请求 (POST /eureka/apps/{appName}) 添加服务实例 注册成功 200 OK 心跳请求 (PUT /eureka/apps/{appName}/{instanceId}) 更新心跳时间戳 更新成功 200 OK
服务发现时序图
Service Registry Eureka Server Service Consumer Service Registry Eureka Server Service Consumer 查询服务 缓存服务信息 每30秒刷新 loop [每30秒] 获取注册信息 (GET /eureka/apps/{appName}) 读取服务实例 返回服务列表 服务实例列表 (JSON) 获取注册信息 读取服务实例 返回服务列表 服务实例列表
服务下线时序图
Service Registry Eureka Server Service Provider Service Registry Eureka Server Service Provider 服务关闭 停止接收该实例请求 心跳超时(90秒)后从缓存移除 下线请求 (DELETE /eureka/apps/{appName}/{instanceId}) 移除服务实例 移除成功 200 OK
核心配置
Eureka、Consul、Nacos 的配置说明如下:
1. Eureka Server 配置
yaml
# Eureka Server 基础配置
server:
port: 8761
# Eureka Server 相关配置
eureka:
# 实例配置(当前服务实例信息)
instance:
hostname: localhost # 服务实例的主机名
# 客户端配置(作为客户端的行为)
client:
# 不将自己注册到 Eureka Server
# Server 模式不需要注册自己
register-with-eureka: false
# 不从 Eureka Server 获取注册信息
# Server 模式不需要获取其他服务信息
fetch-registry: false
# 服务注册中心地址
# 由于是单机部署,指向自己
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
配置说明:
| 配置项 | 参数 | 默认值 | 说明 |
|---|---|---|---|
| 服务器端口 | server.port |
8761 | Eureka Server 的默认端口 |
| 自身注册 | register-with-eureka |
false | Server 模式不需要将自己注册 |
| 获取注册信息 | fetch-registry |
false | Server 模式不需要从其他 Server 获取注册信息 |
| 集群地址 | defaultZone |
- | 注册中心的集群地址,单机部署时指向自己 |
2. Eureka Client 配置
yaml
# 客户端应用基础配置
spring:
application:
name: user-service # 应用名称,会作为服务名注册到 Eureka
# Eureka Client 相关配置
eureka:
# 客户端配置(作为客户端的行为)
client:
# 服务注册中心地址
# 指向 Eureka Server 的地址
service-url:
defaultZone: http://localhost:8761/eureka/
# 从注册中心获取服务信息的间隔时间(秒)
# 默认30秒,可根据需求调整
registry-fetch-interval-seconds: 30
# 实例配置(当前服务实例信息)
instance:
# 实例 ID,确保唯一性
# 通常使用服务名+端口号的组合
instance-id: ${spring.application.name}:${server.port}
# 租约续租间隔(秒)
# 服务发送心跳的间隔时间,默认30秒
lease-renewal-interval-seconds: 30
# 租约过期时间(秒)
# Server 等待心跳的超时时间,默认90秒
# 超过这个时间没有收到心跳,Server 会将实例标记为下线
lease-expiration-duration-in-seconds: 90
配置说明:
| 配置项 | 参数 | 默认值 | 说明 |
|---|---|---|---|
| 应用名称 | spring.application.name |
- | 应用的唯一标识,服务注册时会使用此名称 |
| 注册中心地址 | defaultZone |
- | Eureka Server 的集群地址,客户端需要连接此处注册服务 |
| 服务列表刷新间隔 | registry-fetch-interval-seconds |
30 | 从 Server 获取服务列表的刷新间隔(秒) |
| 心跳间隔 | lease-renewal-interval-seconds |
30 | 客户端发送心跳的频率,保持服务状态活跃(秒) |
| 心跳超时 | lease-expiration-duration-in-seconds |
90 | Server 端判断服务是否可用的心跳超时时间(秒) |
| 实例 ID | instance-id |
- | 服务实例的唯一标识,通常使用服务名+端口号 |
关键配置参数总结:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
registry-fetch-interval-seconds |
客户端配置 | 30 | 从 Eureka Server 获取服务列表的间隔时间 |
lease-renewal-interval-seconds |
客户端配置 | 30 | 客户端发送心跳的间隔时间 |
lease-expiration-duration-in-seconds |
客户端配置 | 90 | Server 端的心跳超时时间 |
register-with-eureka |
服务端配置 | true | 是否将自身注册到 Eureka |
fetch-registry |
服务端配置 | true | 是否从 Eureka 获取服务注册信息 |
高级特性
自我保护机制
当 Eureka Server 在短时间内丢失过多客户端心跳时,会进入自我保护模式。此时,Eureka Server 会保护注册表中的信息,不会因为心跳失败而注销任何服务实例。
yaml
eureka:
server:
enable-self-preservation: true
renewal-percent-threshold: 0.85
集群部署
yaml
# eureka-server1.yml
eureka:
client:
service-url:
defaultZone: http://eureka-server2:8761/eureka/,http://eureka-server3:8761/eureka/
Consul 详细说明
架构设计
Consul 集群由多个 Server 节点和多个 Client 节点组成:
- Server 节点:负责维护集群状态,处理 Raft 协议,持久化数据
- Client 节点:转发请求到 Server,不持久化数据
工作原理
-
服务注册:
- 服务实例向 Consul Agent 发送注册请求
- Agent 将注册信息转发给 Server
- Server 使用 Raft 协议同步数据
-
服务发现:
- 客户端通过 DNS 或 HTTP API 查询服务
- Consul 返回可用服务实例列表
- 客户端缓存查询结果
服务注册时序图
Service Registry Consul Server Consul Agent Service Provider Service Registry Consul Server Consul Agent Service Provider 服务启动 开始定期发送心跳 loop [每10秒] 注册请求 (PUT /v1/agent/service/register) 转发注册请求 使用 Raft 协议同步数据 注册成功 200 OK 200 OK 心跳请求 (PUT /v1/agent/check/pass/{serviceId}) 转发心跳 更新心跳时间戳 更新成功 200 OK 200 OK
服务发现时序图
Service Registry Consul Server Service Consumer Service Registry Consul Server Service Consumer 查询服务 缓存服务信息 定期刷新 loop [定期刷新] 查询请求 (GET /v1/health/service/{serviceName}) 读取服务实例 返回服务列表 服务实例列表 (JSON) 查询请求 读取服务实例 返回服务列表 服务实例列表
核心配置
yaml
# Consul Server 配置
server:
port: 8500
spring:
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
port: ${server.port}
health-check-path: /actuator/health
health-check-interval: 10s
tags: version=1.0, environment=dev
配置说明:
| 配置项 | 参数 | 默认值 | 说明 |
|---|---|---|---|
| Consul 主机 | host |
localhost | Consul Server 的主机地址 |
| Consul 端口 | port |
8500 | Consul Server 的端口 |
| 服务名称 | service-name |
- | 服务注册时的名称 |
| 服务端口 | port |
- | 服务暴露的端口 |
| 健康检查路径 | health-check-path |
/actuator/health | 健康检查的 HTTP 路径 |
| 健康检查间隔 | health-check-interval |
10s | 健康检查的时间间隔 |
| 标签 | tags |
- | 服务的标签信息,用于分类和过滤 |
高级特性
多数据中心支持
Consul 原生支持多数据中心部署:
yaml
spring:
cloud:
consul:
datacenter: dc1
discovery:
prefer-agent-address: true
配置管理
yaml
spring:
cloud:
consul:
config:
prefix: config
format: YAML
profile-separator: '::'
enabled: true
Nacos 详细说明
架构设计
Nacos 采用架构模式:
- Nacos Server:核心服务端,提供服务注册、发现、配置管理功能
- Nacos Client:客户端库,集成到应用中
- 数据存储:支持嵌入式数据库或外部 MySQL
工作原理
-
服务注册:
- 服务启动时向 Nacos Server 注册
- Nacos Server 将信息存储到数据存储
- 服务实例发送心跳保持活跃状态
-
服务发现:
- 客户端向 Nacos Server 查询服务列表
- Nacos Server 返回可用实例
- 客户端缓存并定期刷新
-
配置管理:
- 配置变更推送到客户端
- 客户端实时更新本地配置
- 支持灰度发布和蓝绿发布
服务注册时序图
Service Registry Nacos Server Service Provider Service Registry Nacos Server Service Provider 服务启动 开始定期发送心跳 loop [每5秒] 注册请求 (POST /nacos/v1/ns/instance) 存储服务信息到数据库 存储成功 200 OK 心跳请求 (PUT /nacos/v1/ns/instance/beat) 更新心跳时间戳 更新成功 200 OK
服务发现时序图
Service Registry Nacos Server Service Consumer Service Registry Nacos Server Service Consumer 查询服务 缓存服务信息 定期刷新 loop [定期刷新] 查询请求 (GET /nacos/v1/ns/instance/list) 读取服务实例 返回服务列表 服务实例列表 (JSON) 查询请求 读取服务实例 返回服务列表 服务实例列表
配置管理时序图
Configuration Nacos Server Nacos Client Configuration Nacos Server Nacos Client 初始化配置 监听配置变更 获取配置 (GET /nacos/v1/cs/configs) 读取配置数据 返回配置内容 配置内容 (JSON) 加载配置 推送配置变更 (长连接) 更新本地配置
核心配置
yaml
# Nacos Server 配置
server:
port: 8848
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
namespace: dev
group: DEFAULT_GROUP
cluster-name: DEFAULT
register-enabled: true
metadata:
version: 1.0.0
weight: 1
config:
server-addr: localhost:8848
namespace: dev
group: DEFAULT_GROUP
data-id: user-service.yaml
refresh: true
配置项说明:
| 配置项 | 参数 | 默认值 | 说明 |
|---|---|---|---|
| Nacos 地址 | server-addr |
localhost:8848 | Nacos Server 的地址和端口,支持多个地址用逗号分隔 |
| 命名空间 | namespace |
dev | 命名空间,用于隔离不同环境(开发、测试、生产)的服务注册信息 |
| 分组 | group |
DEFAULT_GROUP | 服务分组,将服务划分到不同分组,便于管理和隔离 |
| 集群名称 | cluster-name |
DEFAULT | 服务集群名称,用于标识同一服务在不同机房或集群的实例 |
| 注册开关 | register-enabled |
true | 是否启用服务注册功能,可用于临时禁用注册 |
| 元数据 | metadata |
- | 服务元数据,包含版本、权重等自定义信息,用于服务治理 |
| 配置 ID | data-id |
- | 配置的唯一标识,格式通常为服务名.后缀,如user-service.yaml |
| 配置刷新 | refresh |
true | 是否启用配置自动刷新,当 Nacos 配置变更时自动更新到应用 |
配置项关系说明:
| 关系类型 | 说明 |
|---|---|
| 命名空间一致性 | discovery 和 config 的 namespace 通常保持一致,确保服务和配置在同一环境 |
| 分组灵活性 | discovery 和 config 的 group 可以不同,实现服务和配置的独立管理 |
| 地址分离 | server-addr 可以分别配置,支持注册中心和配置中心独立部署 |
| 元数据扩展 | metadata 可以包含更多自定义信息,如环境、标签等,用于高级服务治理 |
这些配置共同构成了 Nacos 在 Spring Cloud 中的完整集成,实现了服务注册发现和动态配置管理的核心功能。
高级特性
集群配置
Nacos 支持集群部署,通过多节点实现高可用和负载均衡。
yaml
spring:
cloud:
nacos:
discovery:
server-addr: nacos1:8848,nacos2:8848,nacos3:8848 # 集群地址,逗号分隔
namespace: public
group: DEFAULT_GROUP
选型建议
场景化选型指南
是
否
阿里系/Spring Cloud Alibaba
HashiCorp 生态
高可用优先 AP
强一致性优先 CP
新项目
老项目维护
选择注册中心
是否需要配置管理?
技术栈倾向?
CAP 优先级?
Nacos
AP/CP 可切换
配置+注册一体化
Consul
CP 模型
服务网格支持
项目阶段?
Consul 或 Nacos-CP
Nacos
社区活跃
Eureka
但需注意已维护模式
详细选型对比
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 新项目启动 | Nacos | 社区活跃、功能全面、AP/CP 可切换 |
| Spring Cloud Alibaba 技术栈 | Nacos | 原生集成、配置中心一体化 |
| 传统 Spring Cloud 技术栈 | Eureka(老项目)或迁移到 Nacos | 历史兼容性好,但新项目不推荐 |
| HashiCorp 生态 | Consul | 与 Terraform、Vault 等工具集成良好 |
| 多数据中心部署 | Consul 或 Nacos | 原生支持多数据中心 |
| 服务网格(Istio/Envoy) | Consul | 原生支持服务网格 |
| 国内团队 | Nacos | 中文文档完善、社区活跃 |
| 强一致性要求 | Consul 或 Nacos-CP | Raft 协议保证一致性 |
| 高可用要求 | Nacos-AP 或 Eureka | 允许短暂不一致,保证服务可用 |
迁移建议
| 迁移路径 | 难度 | 建议 |
|---|---|---|
| Eureka → Nacos | 中 | 使用 Spring Cloud Alibaba 替换 Netflix 组件 |
| Consul → Nacos | 中 | 需调整配置结构,服务数据可平滑迁移 |
| Zookeeper → Nacos | 高 | 数据模型差异大,需重新设计 |
实战代码示例
Eureka 实战
依赖配置
xml
<!-- Eureka Server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- Eureka Client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Eureka Server 启动类
java
@SpringBootApplication
@EnableEurekaServer // 开启 Eureka Server 功能
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
服务提供者
java
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现功能
@RestController
public class ProviderApplication {
@Value("${server.port}")
private String port;
@GetMapping("/hello")
public String hello() {
return "Hello from port: " + port;
}
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
服务消费者(RestTemplate 方式)
java
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class ConsumerApplication {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@Bean
@LoadBalanced // 开启负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/consumer/hello")
public String hello() {
// 使用服务名调用,自动负载均衡
return restTemplate.getForObject("http://user-service/hello", String.class);
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
Nacos 实战
依赖配置
xml
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Nacos 配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
配置文件(bootstrap.yml)
yaml
spring:
application:
name: user-service
cloud:
nacos:
# 服务发现配置
discovery:
server-addr: ${NACOS_SERVER:localhost:8848}
namespace: ${NACOS_NAMESPACE:dev}
group: DEFAULT_GROUP
# 配置中心配置
config:
server-addr: ${NACOS_SERVER:localhost:8848}
namespace: ${NACOS_NAMESPACE:dev}
group: DEFAULT_GROUP
file-extension: yaml
refresh-enabled: true
动态配置刷新
java
@RestController
@RefreshScope // 支持配置动态刷新
public class ConfigController {
@Value("${app.config.value:default}")
private String configValue;
@GetMapping("/config")
public String getConfig() {
return "Current config: " + configValue;
}
}
服务调用(OpenFeign 方式)
java
// Feign 客户端接口
@FeignClient(name = "user-service", path = "/user")
public interface UserClient {
@GetMapping("/{id}")
UserDTO getUser(@PathVariable("id") Long id);
}
// 服务消费者
@RestController
@RequiredArgsConstructor
public class OrderController {
private final UserClient userClient;
@GetMapping("/order/{userId}")
public OrderDTO getOrder(@PathVariable Long userId) {
UserDTO user = userClient.getUser(userId);
return new OrderDTO(userId, user.getName());
}
}
Consul 实战
依赖配置
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
配置文件
yaml
spring:
application:
name: user-service
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
health-check-path: /actuator/health
health-check-interval: 10s
instance-id: ${spring.application.name}:${server.port}
服务提供者
java
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现功能
@RestController
public class ProviderApplication {
@Value("${server.port}")
private String port;
@GetMapping("/hello")
public String hello() {
return "Hello from Consul provider, port: " + port;
}
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
服务消费者(RestTemplate 方式)
java
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class ConsumerApplication {
@Bean
@LoadBalanced // 开启负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/consumer/hello")
public String hello() {
// 使用服务名调用,自动负载均衡
return restTemplate().getForObject("http://user-service/hello", String.class);
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
服务消费者(OpenFeign 方式)
java
// Feign 客户端接口
@FeignClient(name = "user-service")
public interface UserServiceClient {
@GetMapping("/hello")
String hello();
}
// 服务消费者
@RestController
@RequiredArgsConstructor
public class ConsumerController {
private final UserServiceClient userServiceClient;
@GetMapping("/consumer/feign-hello")
public String feignHello() {
return userServiceClient.hello();
}
}
Consul 配置中心
Consul 也可以作为配置中心使用:
yaml
spring:
application:
name: user-service
cloud:
consul:
host: localhost
port: 8500
config:
enabled: true
prefix: config
default-context: application
profile-separator: ','
data-key: data
format: YAML
discovery:
service-name: ${spring.application.name}
配置动态刷新示例:
java
@RestController
@RefreshScope // 支持配置动态刷新
public class ConfigController {
@Value("${app.message:default}")
private String message;
@GetMapping("/message")
public String getMessage() {
return "Current message: " + message;
}
}
注意:Consul Server 需要独立部署,与 Eureka 不同,Consul 不需要在 Spring Boot 项目中创建 Server 端。Consul Agent 作为独立进程运行,负责服务注册、发现和健康检查。