Appearance
第64课:Spring Cloud 基础
🎯 学习目标
- 理解单体架构和微服务架构的差异,以及微服务带来的收益和复杂度。
- 掌握服务注册发现、服务调用、负载均衡、配置中心和网关的基本作用。
- 能使用 Nacos、OpenFeign、Spring Cloud LoadBalancer、Gateway 搭建基本微服务调用链。
- 能识别微服务拆分过度、远程调用失败、配置漂移、网关职责膨胀等问题。
- 建立“先单体清晰,再微服务拆分”的工程判断。
📖 一、为什么需要微服务
单体应用:
text
用户、订单、库存、支付都在一个应用里。
统一部署,共享数据库,开发简单。微服务:
text
用户服务、订单服务、库存服务、支付服务独立部署。
服务之间通过 HTTP、RPC 或消息通信。微服务优点:
text
独立部署
独立扩展
团队边界清晰
故障隔离更容易
技术栈可局部演进微服务代价:
text
远程调用失败
分布式事务
链路追踪
配置管理
服务治理
部署和监控复杂度上升不要为了“架构高级”过早拆微服务。业务边界不清晰时,拆出来只会变成分布式单体。
📖 二、Spring Cloud 组件图
常见组合:
text
Nacos Discovery 服务注册发现
Nacos Config 配置中心
OpenFeign 声明式 HTTP 调用
LoadBalancer 客户端负载均衡
Spring Cloud Gateway API 网关
Sentinel/Resilience4j 限流熔断
Micrometer/Tracing 指标与链路追踪一个请求链路:
text
Client -> Gateway -> user-service -> order-service -> storage-service每一跳都可能失败,因此必须考虑超时、重试、降级和日志追踪。
📖 三、服务注册发现
依赖示例:
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>配置:
yaml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848启动类:
java
@SpringBootApplication
@EnableDiscoveryClient
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}服务启动后会把自己的地址注册到 Nacos。调用方通过服务名发现实例,而不是写死 IP。
📖 四、OpenFeign 服务调用
启用 Feign:
java
@SpringBootApplication
@EnableFeignClients
public class UserApplication {
}声明客户端:
java
@FeignClient(name = "order-service", path = "/api/orders")
public interface OrderClient {
@GetMapping("/users/{userId}")
List<OrderResponse> getByUserId(@PathVariable Long userId);
@PostMapping
OrderResponse create(@RequestBody OrderCreateRequest request);
}使用:
java
@Service
public class UserQueryService {
private final OrderClient orderClient;
public UserDetailResponse getUserDetail(Long userId) {
UserResponse user = userService.getById(userId);
List<OrderResponse> orders = orderClient.getByUserId(userId);
return UserDetailResponse.of(user, orders);
}
}Feign 的本质是声明式 HTTP 客户端。接口调用看起来像本地方法,实际是远程网络调用,必须设置超时和失败处理。
📖 五、负载均衡
当 order-service 有多个实例:
text
order-service 10.0.0.1:8080
order-service 10.0.0.2:8080
order-service 10.0.0.3:8080调用方通过服务名调用,LoadBalancer 选择一个实例。
常见配置:
yaml
spring:
cloud:
loadbalancer:
retry:
enabled: true注意:重试不是越多越好。写接口、下单接口、扣库存接口等非幂等操作不能随意重试。
📖 六、配置中心
Nacos Config 配置:
yaml
spring:
application:
name: user-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml配置中心价值:
text
集中管理多环境配置
动态调整部分配置
避免每个服务打包不同配置
配置变更有审计和回滚敏感配置仍要谨慎管理。配置中心不是密钥系统的完全替代品。
📖 七、Spring Cloud Gateway
Gateway 是微服务入口。
yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**常见职责:
text
统一路由
认证前置
限流
跨域
灰度
请求日志
协议转换不要把复杂业务逻辑写到网关。网关应该薄,业务规则留在服务内部。
⚠️ 八、常见陷阱
1. 拆分过早
团队还无法维护单体清晰边界时,拆微服务会放大复杂度。
2. Feign 当本地调用
远程调用会超时、失败、返回不一致。必须设置超时、降级和日志。
3. 重试导致重复写
非幂等接口随意重试可能创建重复订单或重复扣款。
4. 配置中心无权限控制
配置泄露可能导致数据库密码、密钥泄露。
5. 网关职责膨胀
网关不是业务聚合层。复杂业务编排应该在后端服务或 BFF 中完成。
🆚 九、Java vs C 对比
| 维度 | C 分布式服务 | Spring Cloud |
|---|---|---|
| 服务发现 | 手写注册或依赖外部库 | DiscoveryClient |
| 调用客户端 | 手写 HTTP/RPC | OpenFeign |
| 负载均衡 | 自定义策略 | LoadBalancer |
| 网关 | Nginx/自研网关 | Spring Cloud Gateway |
| 配置 | 文件/环境变量 | 配置中心 |
Spring Cloud 把微服务治理能力框架化,但分布式系统的失败模式不会消失。
💡 十、最佳实践
- 先把单体边界设计清楚,再拆微服务。
- 服务拆分按业务能力,而不是按数据库表。
- 所有远程调用必须有超时。
- 写接口必须考虑幂等。
- 网关只做入口治理,不承载复杂业务。
- 配置中心要有权限、审计和回滚机制。
- 服务间调用日志必须带 traceId。
- 微服务上线前必须有监控、告警和链路追踪。
🔍 十一、自测问题
text
微服务解决什么问题,又引入什么问题?
服务注册发现的作用是什么?
OpenFeign 为什么不是本地方法调用?
负载均衡和服务发现是什么关系?
配置中心适合管理哪些配置?
网关应该做什么,不应该做什么?
为什么非幂等接口不能随意重试?
什么情况下不应该拆微服务?🧭 十二、微服务拆分检查清单
拆服务前先确认:
text
业务边界是否清楚?
数据归属是否清楚?
团队是否能独立维护服务?
是否有自动化部署?
是否有链路追踪?
是否有统一日志和指标?
远程调用是否有超时和降级?
接口是否幂等?
是否能接受分布式一致性复杂度?如果这些基础设施都没有,优先改进单体结构,而不是直接拆服务。
🧪 十三、实战案例:用户详情聚合
一个典型聚合接口:
text
用户服务查询用户基本信息。
订单服务查询最近订单。
优惠券服务查询可用优惠券。
网关或 BFF 聚合返回给前端。风险:
text
任一下游慢都会拖慢聚合接口。
下游失败时要决定整体失败还是部分降级。
多个服务返回的数据可能不是同一时刻的一致快照。这说明微服务设计必须同时考虑接口语义和失败策略。
📌 十四、学习建议
建议用三个小服务练习:
text
user-service
order-service
gateway先跑通注册发现和 Feign 调用,再故意关闭 order-service,观察 user-service 如何失败。这个实验能帮助理解远程调用和本地调用的本质区别。
📚 十五、微服务基础术语
text
服务注册:服务启动后把地址上报注册中心。
服务发现:调用方从注册中心获取可用实例。
负载均衡:从多个实例中选择一个。
网关:统一入口和路由。
配置中心:集中管理配置。
熔断:下游异常时快速失败。
降级:返回兜底结果。
链路追踪:串起跨服务请求。这些术语不是孤立的,它们共同解决“服务变多后如何治理”的问题。
📌 十六、接口设计建议
微服务接口要明确:
text
是否幂等。
超时时间。
错误码。
是否允许重试。
是否有降级结果。
数据是否最终一致。远程接口不是本地方法,接口契约必须更严格。
接口文档中应写明错误码、超时语义和是否可重试。调用方不能靠猜测处理失败。
服务之间的契约越明确,故障时越容易快速定位责任边界。
微服务接口还应记录负责人。 核心接口应有变更公告。 废弃接口要保留兼容窗口。
🎓 小结
Spring Cloud 基础不是几个注解和配置,而是一套服务治理模型。服务注册、调用、负载均衡、配置中心和网关构成了微服务基础链路。真正难点是处理远程调用失败、配置一致性、链路追踪和服务边界。