Spring Cloud 微服务概述与 Nacos
一、微服务概述
单体 vs 微服务
┌─────────────────────────────────────────────────────────────────┐
│ 单体架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 单一应用 │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ 用户模块 │ │ 订单模块 │ │ 支付模块 │ │ 商品模块 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ 共用数据层 │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 问题: │
│ - 代码耦合,部署困难 │
│ - 扩展性差 │
│ - 单点故障 │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 微服务架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 用户服务 │ │ 订单服务 │ │ 支付服务 │ │ 商品服务 │ │
│ │ :8081 │ │ :8082 │ │ :8083 │ │ :8084 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ └──────────────┴──────────────┴──────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ 网关/注册中心 │ │
│ └─────────────┘ │
│ │
│ 优势:独立部署、独立扩展、技术异构 │
│ │
└─────────────────────────────────────────────────────────────────┘Spring Cloud 组件栈
┌─────────────────────────────────────────────────────────────────┐
│ Spring Cloud 组件栈 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 服务注册/发现 │
│ ├─ Eureka(Netflix,已停止维护) │
│ ├─ Consul(HashiCorp) │
│ └─ Nacos(阿里巴巴)⭐ 推荐 │
│ │
│ 服务调用 │
│ ├─ Ribbon(负载均衡,已停止维护) │
│ └─ OpenFeign(声明式 HTTP 客户端)⭐ │
│ │
│ 网关 │
│ ├─ Zuul(Netflix,已停止维护) │
│ └─ Gateway(响应式网关)⭐ │
│ │
│ 熔断限流 │
│ ├─ Hystrix(Netflix,已停止维护) │
│ └─ Sentinel(阿里巴巴)⭐ │
│ │
│ 配置中心 │
│ ├─ Config(Spring Cloud Config) │
│ └─ Nacos(同时支持配置中心)⭐ │
│ │
│ 消息队列 │
│ ├─ Stream(抽象层) │
│ └─ RocketMQ / Kafka / RabbitMQ │
│ │
│ 分布式事务 │
│ └─ Seata(阿里巴巴)⭐ │
│ │
└─────────────────────────────────────────────────────────────────┘二、Nacos 概述
Nacos 是什么
┌─────────────────────────────────────────────────────────────────┐
│ Nacos │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Nacos = Naming + Configuration + Service │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Nacos │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ 服务注册 │ │ 配置管理 │ │ 流量管理 │ │ │
│ │ │ & 发现 │ │ & 动态配置 │ │ (权重/限流) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 特性: │
│ - 易于部署(单机/集群) │
│ - 中文社区活跃 │
│ - 同时支持 AP 和 CP │
│ - 集成 Dubbo、Spring Cloud、K8s │
│ │
└─────────────────────────────────────────────────────────────────┘安装 Nacos
bash
# 下载
wget https://github.com/alibaba/nacos/releases/download/2.2.3/nacos-server-2.2.3.tar.gz
# 解压
tar -xzf nacos-server-2.2.3.tar.gz
cd nacos
# 单机启动
sh bin/startup.sh -m standalone
# 访问控制台
# http://localhost:8848/nacos
# 默认账号密码: nacos / nacosDocker 启动
bash
docker run --name nacos-standalone -e MODE=standalone \
-p 8848:8848 -p 9848:9848 \
-d nacos/nacos-server:v2.2.3三、服务注册与发现
服务提供者
xml
<dependencies>
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</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>配置
yaml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 # Nacos 地址
namespace: dev # 命名空间(隔离环境)
group: DEFAULT_GROUP # 分组
enabled: true # 启用发现
register-enabled: true # 是否注册自身
ip: 192.168.1.100 # 注册的 IP(省略则自动获取)
port: 8080 # 注册的端口
# 服务名/命名空间/分组 组合唯一标识一个服务实例
# ${spring.application.name}:${namespace}:${group}启动类
java
@SpringBootApplication
@EnableDiscoveryClient // 启用服务发现
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}健康检查
yaml
spring:
cloud:
nacos:
discovery:
# 心跳相关配置
heart-beat-interval: 5000 # 心跳间隔(默认 5000)
heart-beat-timeout: 15000 # 超时时间(默认 15000)
ip-delete-timeout: 30000 # 实例删除超时(默认 30000)四、服务消费者
RestTemplate 调用
java
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced // 启用负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
public Order getOrder(Long orderId) {
// 使用服务名而非 IP:Port
String url = "http://user-service/api/user/" + userId;
User user = restTemplate.getForObject(url, User.class);
// Nacos 会自动发现 user-service 的实例
// 并进行负载均衡
}
}OpenFeign 调用
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>yaml
spring:
cloud:
openfeign:
client:
config:
default: # 全局配置
logger-level: full
user-service: # 指定服务配置
logger-level: basic
circuitbreaker:
enabled: true # 启用熔断java
@EnableFeignClients // 启用 Feign
// 声明式接口
@FeignClient(name = "user-service", path = "/api/users")
public interface UserClient {
@GetMapping("/{id}")
User getUser(@PathVariable("id") Long id);
@PostMapping
User createUser(@RequestBody User user);
}
// 使用
@Service
public class OrderService {
@Autowired
private UserClient userClient;
public Order getOrderWithUser(Long orderId) {
Order order = orderRepository.findById(orderId);
User user = userClient.getUser(order.getUserId());
order.setUser(user);
return order;
}
}五、配置中心
Nacos 配置
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>bootstrap.yml
yaml
spring:
application:
name: order-service
profiles:
active: dev
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: dev
group: DEFAULT_GROUP
file-extension: yaml
refresh-enabled: true # 启用动态刷新
# 配置data-id: ${spring.application.name}-${spring.profiles.active}.${file-extension}
# order-service-dev.yaml注解方式获取配置
java
@RestController
public class ConfigController {
// 方式1:@Value
@Value("${app.name}")
private String appName;
// 方式2:@ConfigurationProperties
@Autowired
private AppConfig appConfig;
// 方式3:@NacosValue(支持动态刷新)
@NacosValue(value = "${app.version}", autoRefreshed = true)
private String version;
}@RefreshScope 动态刷新
java
@RestController
@RefreshScope // 支持动态刷新配置
public class ConfigController {
@Value("${app.config}")
private String config;
// 当 Nacos 配置变更时,config 会自动更新
}共享配置
yaml
spring:
cloud:
nacos:
config:
shared-configs:
- data-id: common.yaml
group: COMMON_GROUP
refresh: true
- data-id: redis.yaml
group: COMMON_GROUP
refresh: false六、命名空间与分组
命名空间(环境隔离)
Nacos
├── dev 命名空间
│ ├── DEFAULT_GROUP
│ │ ├── user-service
│ │ └── order-service
│ └── PAYMENT_GROUP
│ └── payment-service
│
├── test 命名空间
│ └── ...
│
└── prod 命名空间
└── ...yaml
spring:
cloud:
nacos:
discovery:
namespace: dev # 指定命名空间 ID分组(业务隔离)
yaml
spring:
cloud:
nacos:
discovery:
group: USER_GROUP # 指定分组七、服务集群
多实例注册
yaml
# 实例1
spring:
cloud:
nacos:
discovery:
ip: 192.168.1.101
port: 8080
cluster-name: HZ # 杭州集群
# 实例2
spring:
cloud:
nacos:
discovery:
ip: 192.168.1.102
port: 8080
cluster-name: HZ
# 实例3
spring:
cloud:
nacos:
discovery:
ip: 192.168.1.201
port: 8080
cluster-name: SH # 上海集群负载均衡
yaml
spring:
cloud:
nacos:
discovery:
# 优先调用同集群实例
cluster-name: HZ
# 权重配置(通过 Nacos 控制台设置)临时实例 vs 非临时实例
yaml
spring:
cloud:
nacos:
discovery:
# 临时实例:心跳检测,不存在则移除(默认)
# 非临时实例:Nacos 主动探测
ephemeral: false八、Nacos 集群
集群架构
┌─────────────────┐
│ Nginx │
│ (负载均衡) │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│ Nacos-1 │ │ Nacos-2 │ │ Nacos-3 │
│ :8848 │◀───────▶│ :8848 │◀───────▶│ :8848 │
└─────────┘ └─────────┘ └─────────┘
│ │ │
└────────────────────┼────────────────────┘
│
┌─────┴─────┐
│ MySQL │
│ (共享存储) │
└───────────┘cluster.conf
properties
# 192.168.1.101:8848
# 192.168.1.102:8848
# 192.168.1.103:8848高可用
选举机制:
1. 集群内选出一个 Leader
2. 所有写操作先同步到 Leader
3. 超过半数节点同步成功则操作成功
4. Leader 挂了重新选举九、面试高频问题
Q1: Nacos 和 Eureka 区别?
| 对比 | Nacos | Eureka |
|---|---|---|
| CAP | 支持 AP 和 CP | 只支持 AP |
| 健康检查 | 心跳/TCP/HTTP | 心跳 |
| 配置中心 | 支持 | 不支持 |
| 活跃度 | 活跃 | 已停止维护 |
| 部署 | 单机/集群 | 单机/集群 |
Q2: AP vs CP 如何选择?
- AP(可用性):优先保证服务可用,如用户下单
- CP(一致性):优先保证数据一致,如转账、扣款
Q3: Nacos 配置如何动态刷新?
@RefreshScope标注 Bean- Nacos 配置变更
- Spring Cloud 监听变更事件
- 刷新 Bean
Q4: 服务发现流程?
- 服务启动时向 Nacos 注册
- 定时发送心跳
- 消费者从 Nacos 获取服务列表
- 本地负载均衡选择实例
- 发起调用
十、下一章预告
下一章我们将学习 Gateway 网关:
- Gateway 路由配置
- 过滤器链
- 断言(Predicate)
- 全局过滤器