第一部分:微服务与 Spring Cloud 概览
1. 什么是微服务架构?
微服务架构是一种将单一应用程序作为一套小型服务集合来开发的方法。每个服务都:
- 运行在自己的进程中:服务之间相互隔离。
- 围绕业务能力构建:例如,用户服务、订单服务、商品服务。
- 通过轻量级的通信机制进行交互:通常是 HTTP RESTful API 或消息队列。
- 可以独立部署、扩展和更新:修改一个服务无需重新部署整个应用。
- 拥有独立的数据库:实现数据自治,避免紧耦合。
痛点:微服务带来了很多好处,但也引入了新的复杂性:
- 服务发现:服务这么多,如何找到它们?
- 配置管理:成百上千个服务的配置如何集中管理?
- 服务容错:一个服务挂了,如何避免雪崩效应?
- API 网关:外部客户端如何调用内部复杂的服务?
- 分布式事务:如何保证跨多个服务的数据一致性?
2. 什么是 Spring Cloud?
Spring Cloud 是一套完整的微服务解决方案,它基于 Spring Boot 提供了快速构建分布式系统中常见模式的工具。
你可以把它看作是 Spring Boot 的“全家桶”。Spring Boot 让你能快速开发一个独立的微服务,而 Spring Cloud 则提供了协调和治理这些微服务所需的一切组件。
核心目标:简化分布式系统的开发,为开发人员提供一套简单、易用的工具来构建常见的分布式系统模式。
第二部分:Spring Cloud 核心组件详解
以下是 Spring Cloud 生态中最核心、最常用的组件。
1. 服务注册与发现 - Eureka / Nacos
问题:在微服务架构中,服务实例的网络地址是动态变化的(例如,扩容、缩容、故障重启)。客户端如何知道该调用哪个地址?
解决方案:引入一个“电话簿”中心,所有服务启动时都来这里注册,下线时注销。这个中心就是服务注册中心。
- Eureka Server(注册中心):一个独立的服务,负责维护所有可用服务实例的 registry(注册表)。
- Eureka Client:集成到每个微服务中。服务启动时,会向 Eureka Server 注册自己的信息(如 IP、端口、服务名)。同时,它会定期向 Eureka Server 发送心跳以续约。关闭时,会发送取消注册的请求。
- 服务发现:服务消费者(例如 OrderService)通过 Eureka Client 向 Eureka Server 拉取服务提供者(例如 UserService)的地址列表,然后通过客户端负载均衡(如 Ribbon)选择一个实例进行调用。
工作流程:
- 注册:
UserService
和OrderService
启动,向 Eureka Server 注册。 - 拉取注册表:
OrderService
想要调用UserService
,它先从 Eureka Server 拉取最新的服务列表。 - 调用:
OrderService
根据负载均衡策略,从列表中选择一个UserService
实例进行调用。 - 心跳:所有服务实例定期向 Eureka Server 发送心跳,告知自己还“活着”。
Nacos 是一个更强大的替代品,它不仅是注册中心,还是配置中心,在国内更为流行。
2. 负载均衡 - Ribbon / LoadBalancer
问题:一个服务通常有多个实例,消费者应该调用哪一个?
解决方案:客户端负载均衡。与服务端负载均衡(如 Nginx)不同,Ribbon 是一个在客户端进程内运行的负载均衡器。
- 原理:消费者服务(如 OrderService)从注册中心获取到所有
UserService
实例的列表后,Ribbon 会根据内置的负载均衡算法(如轮询、随机、根据响应时间加权等)在客户端选择一个具体的实例地址,然后发起调用。 - 用法:通常与
RestTemplate
或OpenFeign
无缝集成,只需一个@LoadBalanced
注解即可开启。
@Bean
@LoadBalanced // 开启客户端负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 使用时,直接使用服务名代替具体IP
String url = "http://USER-SERVICE/user/" + userId; // USER-SERVICE 是服务名
User user = restTemplate.getForObject(url, User.class);
Spring Cloud LoadBalancer 是 Spring Cloud 官方推出的新组件,旨在替代已进入维护模式的 Ribbon。
3. 服务调用 - OpenFeign
问题:使用 RestTemplate
进行远程调用依然比较繁琐,需要拼接 URL,解析结果。能否像调用本地方法一样调用远程服务?
解决方案:声明式的 REST 客户端 - OpenFeign。
- 原理:开发者只需定义一个 Java 接口,并使用注解(如
@FeignClient
)来描述需要调用的远程服务接口。Spring Cloud 会在运行时自动生成该接口的实现类,完成包括服务发现、负载均衡、请求发送、结果解析在内的所有工作。
// 1. 声明一个 Feign 客户端,指定要调用的服务名
@FeignClient(name = "user-service")
public interface UserServiceClient {
// 2. 定义的方法签名与远程服务的API完全一致
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id") Long id);
}
// 3. 在Controller或Service中,像注入普通Bean一样注入并使用
@Autowired
private UserServiceClient userServiceClient;
public OrderDTO getOrderWithUser(Long orderId) {
Order order = orderRepository.findById(orderId);
User user = userServiceClient.getUserById(order.getUserId()); // 像本地调用一样!
// ... 组装DTO返回
}
4. 服务容错 - Hystrix / Sentinel
问题:在服务链式中,如果下游服务 UserService
响应缓慢或宕机,会导致上游服务 OrderService
的线程大量阻塞等待,最终耗尽资源,自己也瘫痪掉。这就是服务雪崩。
解决方案:服务容错。提供“保险丝”机制,防止故障蔓延。
- 服务降级 (Fallback):当服务调用失败(超时、异常)时,不是直接抛出错误,而是提供一个备选方案(返回一个默认值、缓存数据等),保证主线业务可用。
- 熔断器 (Circuit Breaker):类似电路保险丝。统计一段时间内的失败请求比例,如果超过阈值,熔断器会“跳闸”。后续的请求会直接失败,不再访问故障服务。经过一段时间后,熔断器会进入“半开”状态,尝试放一个请求过去,如果成功则关闭熔断器,恢复调用。
Hystrix 工作流程:
- 所有对外部依赖的调用都通过 Hystrix 命令封装。
- Hystrix 监控这些调用的成功、失败、超时和线程拒绝情况。
- 当失败率达到阈值,熔断器打开,快速失败。
- 熔断器打开一段时间后,进入半开状态,尝试放行一个请求。
- 根据尝试请求的结果,决定是关闭熔断器(恢复)还是继续保持打开。
Sentinel 是阿里开源的更强大的流量控制组件,功能更丰富,性能更高,是目前的主流选择。
5. API 网关 - Spring Cloud Gateway
问题:外部客户端(如手机APP)需要调用多个微服务。如果直接对接内部服务,会非常复杂:
- 客户端需要知道所有服务的地址。
- 每个服务都需要独立处理鉴权、限流、日志等跨域问题。
- 服务协议可能不统一(HTTP, gRPC等)。
解决方案:API 网关。它是系统的唯一入口,扮演“门卫”和“路由器”的角色。
Spring Cloud Gateway 是基于 WebFlux 的响应式高性能网关。
- 核心概念:
- 路由 (Route):定义匹配规则和目标URI。如:将
/api/order/**
的请求路由到order-service
。 - 断言 (Predicate):定义匹配条件(如路径、方法、Header等)。使用 Java 8 的
Predicate
。 - 过滤器 (Filter):在请求发出前或响应返回后,对请求和响应进行修改(如添加Header、鉴权、记录日志、熔断)。
- 路由 (Route):定义匹配规则和目标URI。如:将
功能:
- 请求路由:将外部请求智能地路由到正确的内部微服务。
- 统一认证鉴权:在网关层进行权限校验,内部服务无需关心。
- 限流:限制每个用户或服务的请求频率。
- 日志监控:集中收集访问日志。
- 跨域处理:统一解决跨域问题。
6. 分布式配置中心 - Spring Cloud Config / Nacos
问题:微服务数量多,配置文件(如数据库连接、第三方API密钥)散落在各处。修改一个配置需要重启大量服务,难以管理。
解决方案:配置中心。将所有服务的配置集中到一个外部位置(如 Git 仓库)进行统一管理。
- Spring Cloud Config Server:一个专门的服务,从 Git/SVN 等仓库拉取配置。
- Spring Cloud Config Client:集成在每个微服务中。服务启动时,会向 Config Server 请求获取自己的配置。还可以通过
@RefreshScope
注解和 Spring Cloud Bus 实现配置的动态刷新,无需重启服务。
Nacos 同样是一个极佳的替代方案,它管理配置的UI和易用性通常比 Config Server 更好。
第三部分:总结与架构图
一个典型的 Spring Cloud 微服务集群架构如下所示:
核心流程:
- 所有微服务启动前,从配置中心拉取自己的配置。
- 微服务启动后,向注册中心注册自己的服务信息。
- API 网关也作为客户端,从注册中心拉取服务列表。
- 外部请求到达 API 网关。
- 网关根据路由规则,通过负载均衡找到一个目标服务实例,将请求转发过去。
- 服务之间调用(如 OrderService 调用 UserService)通过 Feign 完成,Feign 底层集成 Ribbon 进行负载均衡,并从注册中心获取服务地址列表。同时,Hystrix 提供容错保护。
通过这一套组件的协同工作,Spring Cloud 成功地解决了微服务架构中的各种共性难题,让开发者能够专注于业务逻辑的开发。