Spring Cloud 学习 —— 简单了解
Spring Cloud 简介
官方文档:https://docs.spring.io/spring-cloud-release/reference/index.html
在学习 Spring Cloud 之前,先了解一下什么是分布式系统?
分布式系统
分布式系统是由多个独立计算机(节点)通过网络连接组成的系统,这些计算机协同工作,对用户表现为一个统一的整体。每个节点可以分布在不同的地理位置,通过消息传递(如 HTTP、RPC)完成通信,共同完成一个任务。其核心特征包括:
- 资源共享:整合分散的资源(计算、存储、服务)。
- 高可用性:通过冗余避免单点故障。
- 可扩展性:通过水平扩展(增加节点)提升系统性能。
- 透明性:用户无需感知系统内部的分布性(如访问一个网站时,用户不知道背后有多少服务器)。
这样分布式系统具有很大的容错优势。
分布式系统的作用
核心作用 | 技术实现示例 |
---|---|
服务解耦 | 微服务拆分 |
配置统一管理 | 动态配置中心 |
流量控制 | 熔断降级机制 |
服务发现 | 注册中心动态路由 |
分布式系统的痛点
- 服务发现与治理:分布式系统中节点动态变化(如扩容、宕机)会导致服务定位困难。
- 服务间通信优化:跨服务调用需处理序列化、负载均衡等问题。
- API 网关与流量控制:网络不可靠性可能导致请求堆积或服务过载。
- 熔断与故障恢复:服务雪崩效应是分布式系统的常见风险。
- 分布式事务管理:跨服务事务一致性是核心挑战。
- 统一配置管理:多节点配置分散会增加运维复杂度。
- 分布式链路追踪:请求可能经过多个服务(如用户请求 → 订单服务 → 支付服务 → 库存服务),如何追踪完整链路?
Spring Cloud 是什么
为了解决分布式系统的痛点,Spring Cloud 应运而生。
Spring Cloud 是一个基于 Spring Boot 的微服务架构开发工具集,提供了一系列组件和框架,用于简化分布式系统的构建、部署和治理。它整合了 Netflix、Alibaba 等开源生态的成熟解决方案(如 Eureka、Sentinel、Nacos),帮助开发者快速实现服务发现、负载均衡、熔断降级等分布式系统核心功能。
核心定位:
- 微服务全家桶:提供微服务架构中常见问题的标准化解决方案。
- 开箱即用:基于 Spring Boot 的约定优于配置原则,简化开发。
- 模块化设计:按需引入组件(如仅需服务发现时引入
spring-cloud-starter-netflix-eureka-client
)。
Spring Cloud 解决的核心问题
分布式系统痛点 | Spring Cloud 解决方案 | 核心组件 |
---|---|---|
服务发现与注册 | 动态管理服务实例的地址和状态 | Consul、Nacos |
服务间通信 | 简化 HTTP/RPC 调用,处理负载均衡和容错 | LoadBalancer、OpenFeign |
配置管理 | 集中管理分布式配置,支持动态刷新 | Consul、Nacos |
熔断与降级 | 防止服务雪崩,提供故障隔离和降级逻辑 | Resilience4j、Sentinel |
API 网关 | 统一入口,处理路由、鉴权、限流等跨横切面关注点 | Gateway |
分布式追踪 | 追踪请求链路,定位性能瓶颈 | Micrometer、Zipkin |
分布式事务 | 解决跨服务数据一致性问题 | Seata |
Spring Cloud 与 Spring Cloud Alibaba 关系
Spring Cloud Alibaba 是 阿里巴巴 开源的 Spring Cloud 子项目,属于 Spring Cloud 生态的一部分。它在 Spring Cloud 标准组件的基础上,替换或增强了部分功能,并深度集成了阿里云的中间件(如 Nacos、Sentinel、RocketMQ)。
组件生态差异
功能 | Spring Cloud | Spring Cloud Alibaba |
---|---|---|
服务注册中心、配置中心 | Consul | Nacos |
熔断限流 | Resilience4j | Sentinel |
分布式事务 | 无原生支持(依赖第三方) | Seata(AT/TCC 模式) |
消息中间件 | 无原生支持 | RocketMQ(阿里自研) |
Consul 服务注册与发现、配置管理
官网:https://www.consul.io/
github 地址:https://github.com/hashicorp/consul
Spring Cloud Consul github 地址:https://github.com/spring-cloud/spring-cloud-consul
Spring Cloud Consul 文档:https://docs.spring.io/spring-cloud-consul/reference/
什么是 Consul
Consul 是由 HashiCorp 公司推出的开源分布式工具,专为微服务架构设计,提供服务发现、配置管理、健康检查、多数据中心支持等核心功能。其架构基于分布式共识算法(Raft),具备高可用性和横向扩展能力。
核心功能
- 服务发现
- 服务注册:服务提供者(如 API 或 MySQL)通过 Consul 客户端将自身信息(IP、端口、元数据)注册到 Consul 集群。
- 服务查询:消费者通过 DNS 或 HTTP 接口查询服务列表,动态获取可用服务节点。
- 健康检查:
- 支持对服务进行主动探测(如 HTTP 状态码检查)或被动上报。
- 自动剔除不健康节点,避免流量路由到故障服务。
- 配置管理
- 键值存储:
- 支持动态配置存储,如功能开关、数据库连接字符串等。
- 通过 HTTP API 或 Consul 模板(Consul-Template)实现配置动态加载。
- 多环境支持:
- 通过命名空间或路径区分不同环境(开发/生产)的配置。
- 例如:
config/dev/db
和config/prod/db
存储不同环境的数据库配置。
- 键值存储:
- 多数据中心支持
- 可跨多个地理区域部署 Consul 集群,实现全局服务发现和跨数据中心配置同步。
- 通过 WAN 网络连接不同数据中心,支持灾备和流量调度。
- 安全特性
- 访问控制(ACL):限制客户端对服务或配置的读写权限。
- 通信加密:支持 TLS 加密服务间通信,确保数据传输安全。
- 服务网格(Service Mesh)
- 集成 Connect 功能,提供基于 mTLS 的服务间身份认证和流量加密。
- 支持细粒度流量策略(如路由规则、熔断策略)。
安装与启动
下载地址:https://developer.hashicorp.com/consul/install
Mac 安装时,需要配置环境变量。
验证是否安装成功:consul version
。
启动 consul:consul agent -dev
启动完成后访问:http://localhost:8500/
出现以下页面配置成功。
启动命令详解
核心命令结构
consul agent 参数
关键运行模式
参数 | 作用 | 适用场景 |
---|---|---|
-dev | 启动开发模式(单节点) | 本地测试 |
-server | 启动服务端模式 | 生产集群 |
-client | 指定客户端节点 | 集群客户端 |
常用参数说明
参数 | 示例 | 说明 |
---|---|---|
-data-dir | -data-dir=/tmp/consul | 数据存储目录(默认:/consul/data ) |
-config-dir | -config-dir=/etc/consul.d | 配置文件目录(支持 .json /.hcl ) |
-bind | -bind=0.0.0.0 | 绑定监听地址 |
-http-port | -http-port=8501 | 修改 Web UI 端口(默认 8500) |
-node | -node=web-server-1 | 自定义节点名称 |
-datacenter | -datacenter=dc2 | 指定数据中心名称 |
启动示例
-
开发模式(快速测试):
consul agent -dev -http-port=8501
输出包含
Consul agent running!
即启动成功。 -
生产模式(集群部署):
consul agent -server -bootstrap-expect=3 -data-dir=/var/consul -node=server-1 -bind=192.168.1.10
参数说明:
-bootstrap-expect=3
:预期集群有 3 个服务端节点。-bind
:绑定本机 IP。
Consul 服务注册代码示例
-
父工程导入依赖:
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2024.0.1</version><type>pom</type><scope>import</scope></dependency></dependencies> </dependencyManagement>
版本取决于 Spring Boot 的版本。
-
创建服务提供者:
-
导入依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
配置文件:
spring:application:name: service-producercloud:consul:host: localhostport: 8500discovery:health-check-path: /actuator/healthhealth-check-interval: 15s
-
主启动类:
@SpringBootApplication @EnableDiscoveryClient // 启用服务注册与发现 public class ProducerApplication {public static void main(String[] args) {SpringApplication.run(ProducerApplication.class, args);} }
-
接口:
@RestController @RequestMapping("/api") public class ProducerController {@GetMapping("/hello")public String hello() {return "Hello from Producer Service!";} }
-
-
创建服务消费者:
-
配置文件:
server:port: 8088 spring:application:name: service-consumercloud:consul:host: localhostport: 8500
-
通过 OpenFeign 调用服务:
-
导入依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
主启动类:
@EnableFeignClients @SpringBootApplication public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);} }
-
定义 Feign 接口:
@FeignClient(name = "service-producer") public interface ProducerClient {@GetMapping("/api/hello")String hello(); }
-
controller 层:
@RestController @RequestMapping("/feign-consumer") public class FeignConsumerController {@Autowiredprivate ProducerClient producerClient;@GetMapping("/call")public String call() {return producerClient.hello();} }
-
-
编写完成后,先运行服务提供者代码,查看 consul 是否成功注册服务:
成功注册后,运行服务消费者代码,访问 http://localhost:8088/feign-consumer/call。
返回 Hello from Producer Service!
代表成功。
Consul 配置中心代码示例
在 consul 管理页面配置信息,以 yaml 格式为例,首先创建 config 目录(官方推荐):
在 config 目录下再创建一个或多个目录(通常为微服务名字 + 不同环境,例如 order-service-dev
)
在对应环境的目录下配置信息,key 需要自己设定,value 就是 yaml 格式的配置信息。
配置完成后编写代码:
-
导入依赖:
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-config</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency> </dependencies>
-
主配置类:
package com.yigongsui;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient @SpringBootApplication public class Order {public static void main(String[] args) {SpringApplication.run(Order.class, args);} }
-
编写配置文件
bootstrap.yml
,官方推荐:server:port: 8888 spring:application:name: order-servicecloud:consul:host: localhostport: 8500discovery:service-name: ${spring.application.name}config:# 前缀,推荐为 configprefix: config# 服务名字default-context: order-serviceformat: yaml# 环境分隔符,如果为dev环境,匹配的就是order-service-dev目录profile-separator: '-'# key 的名字data-key: orderServicewatch:enabled: true # 动态配置更新监听[^1]delay: 1000 # 监听间隔(毫秒)fail-fast: true # 启动时若无法连接 Consul 则报错
-
controller 层:
package com.yigongsui.controller;import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;@RestController @RefreshScope public class OrderController {@Value("${mysql.root}")private String root;@Value("${mysql.password}")private String password;@GetMapping("/hello")public String hello(){return root + password;}}
运行成功,访问:http://localhost:8888/hello
LoadBalancer 服务调用和负载均衡
Spring Cloud Balancer 官方文档:https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html
什么是 LoadBalancer
LoadBalancer 是 Spring Cloud 生态中的客户端负载均衡组件,主要解决微服务架构中服务实例的动态选择问题。其核心功能包括:
-
服务实例选择
根据注册中心(如 Nacos、Consul)获取服务实例列表,自动选择目标实例。
-
负载均衡策略
提供轮询、随机等算法,支持自定义策略。
-
与 Spring Cloud 组件深度集成
无缝支持
RestTemplate
、WebClient
和OpenFeign
的负载均衡调用。
解决的问题
问题类型 | LoadBalancer 的解决方案 |
---|---|
客户端负载均衡 | 替代 Netflix Ribbon,提供轻量级、高性能的负载均衡实现 |
服务发现集成 | 通过 @LoadBalanced 注解自动注入服务发现能力,避免硬编码地址 |
策略扩展性 | 支持自定义负载均衡算法(如权重分配、区域优先) |
依赖维护 | 规避 Ribbon 的维护停滞风险,紧跟 Spring 生态更新 |
核心功能
-
注解驱动
通过
@LoadBalanced
注解快速启用负载均衡:@Bean @LoadBalanced // 启用负载均衡 public RestTemplate restTemplate() {return new RestTemplate(); }
(自动将普通 HTTP 请求转换为负载均衡调用)
-
策略配置
- 默认策略:轮询(
RoundRobinLoadBalancer
) - 自定义策略:继承
ReactorServiceInstanceLoadBalancer
接口实现:
public class WeightedLoadBalancer implements ReactorServiceInstanceLoadBalancer {// 实现权重选择逻辑 }
(通过
@LoadBalancerClient
注解指定策略) - 默认策略:轮询(
-
健康检查
自动过滤不可用实例,结合
HealthCheck
机制提升调用可靠性。
OpenFeign 服务接口调用
github 地址:https://github.com/spring-cloud/spring-cloud-openfeign
官方文档:https://docs.spring.io/spring-cloud-openfeign/reference/
什么是 OpenFeign
OpenFeign 是一个声明式的 HTTP 客户端框架,属于 Spring Cloud 生态中的服务调用组件。它通过定义接口和注解的方式,将 HTTP 请求抽象为本地方法调用,开发者无需手动处理底层网络通信细节。其核心设计目标是简化服务间通信,提升微服务架构下的开发效率。
核心功能
-
声明式HTTP客户端
OpenFeign 通过接口 + 注解定义 HTTP 请求,开发者无需手动处理底层 HTTP 通信,例如:
@FeignClient(name = "product-service") public interface ProductApi {@GetMapping("/products/{id}")Product getById(@PathVariable("id") Long id); }
动态代理会自动生成实现类,向
http://product-service/products/{id}
发送 GET 请求。 -
负载均衡集成
默认集成 Ribbon 实现客户端负载均衡,请求会自动分配到不同服务实例。配置示例:
ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
-
熔断降级支持
可与 Sentinel 集成实现服务熔断。配置示例:
feign:sentinel:enabled: true
代码实现关键步骤
-
Maven 依赖:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
超时控制
feign:client:config:default:connectTimeout: 2000 # 连接超时readTimeout: 5000 # 读取超时
-
重试机制
默认不启用重试,需自定义 Retryer:
public class CustomRetryer extends Retryer.Default {public CustomRetryer() {super(100, 1000, 3); // 间隔100ms,最大间隔1s,重试3次} }
Circuit Breaker 断路器
github:https://github.com/spring-cloud/spring-cloud-circuitbreaker
官方文档:https://docs.spring.io/spring-cloud-circuitbreaker/reference/
什么是 Circuit Breaker
Circuit Breaker 是一种容错设计模式,灵感来源于电路中的熔断器。其核心目标是隔离故障服务,防止级联故障扩散到整个系统。当服务调用频繁失败时,断路器会主动“熔断”,暂时阻止后续请求,并给予下游服务恢复时间。
核心状态
- Closed(闭合状态)
- 默认状态,所有请求正常通过。
- 持续监控失败率。
- 触发熔断条件:失败率超过阈值(例如 50%)或超时请求过多。
- Open(开放状态)
- 所有请求直接返回失败(快速失败)。
- 持续时间由
waitDurationInOpenState
参数控制(例如5秒)。 - 进入半开状态的过渡阶段。
- Half-Open(半开状态)
- 允许有限数量的“探针请求”通过(通过
permittedNumberOfCallsInHalfOpenState
配置)。 - 若探针请求成功率达标则恢复 Closed 状态,否则重回 Open 状态
- 允许有限数量的“探针请求”通过(通过
工作流程
[Closed] → (失败率超标) → [Open] ↑ ↓ (等待时间结束)← [Half-Open] → (探针成功)→ [Closed](探针失败)↗
Resilience4j 服务熔断与降级
Resilience4j 是 Spring Cloud Circuit Breaker 的官方推荐实现之一,专注于通过函数式编程实现轻量级容错控制。提供断路器、限流器等六大核心功能模块。
核心模块
- 断路器(Circuit Breaker):自动熔断异常服务。
- 限流器(Rate Limiter):控制请求速率,防止服务过载。
- 隔离机制(Bulkhead):通过线程池/信号量隔离资源。
- 重试策略(Retry):智能重试失败请求。
- 超时控制(Time Limiter):防止长时间阻塞。
- 结果缓存(Cache):减少重复计算。
与 Spring Cloud 集成
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
- 注解驱动开发:通过
@CircuitBreaker
等注解快速实现容错逻辑。 - 配置中心对接:支持通过
application.yml
动态调整参数。 - Feign 集成:与声明式 HTTP 客户端无缝协作实现服务限流。
核心功能实现示例
- 断路器配置
resilience4j.circuitbreaker:instances:backendA:failureRateThreshold: 50waitDurationInOpenState: 5sringBufferSizeInClosedState: 100
- 限流器使用
@RateLimiter(name = "apiLimiter", fallbackMethod = "rateLimitFallback")
public ResponseEntity<String> apiEndpoint() {// 业务逻辑
}
Micrometer 分布式链路追踪
github:https://github.com/micrometer-metrics/micrometer
官方文档:https://docs.micrometer.io/micrometer/reference/
什么是 Micrometer
Micrometer 是一个面向 JVM 应用的度量指标门面库(Metrics Facade),类似于日志领域的 SLF4J。它提供统一的 API 规范,允许开发者以供应商中立的方式记录应用指标,并支持将数据输出到多种监控系统(如 Prometheus、Datadog、InfluxDB 等)。
核心特性
- 统一度量接口
-
支持 12+ 种监控系统,包括:
Prometheus | Datadog | InfluxDB | Graphite | New Relic
-
通过简单配置切换监控后端,无需修改业务代码。
- 标签化维度分析(Tags)
-
使用键值对组合标识指标,增强数据分析能力:
// 统计不同支付方式的成功率 Counter.builder("payment.count").tag("method", "alipay") .tag("status", "success").register(registry).increment();
-
相比传统监控工具(如 dropwizard-metrics)的扁平化指标命名,支持多维度交叉分析。
- 丰富的度量类型
类型 | 功能描述 |
---|---|
Counter | 累加型指标(如请求总数) |
Timer | 耗时统计(如接口响应时间) |
Gauge | 瞬时值测量(如内存使用量) |
Distribution | 数据分布统计(如分位数计算) |
- 与 Spring Boot 深度集成
-
通过 Actuator 暴露指标端点:
# application.yml management:endpoints:web:exposure:include: health,metrics,prometheusmetrics:export:prometheus:enabled: true
-
访问
/actuator/prometheus
可直接获取 Prometheus 格式指标。
- 内存安全机制
-
对
Gauge
类指标采用弱引用策略,避免因对象未及时释放导致内存泄漏:Gauge.builder("cache.size", cache, Cache::size).strongReference(false) // 默认弱引用.register(registry);
-
自动处理被垃圾回收的对象,防止报告
NaN
或无效数据。
Gateway 服务网关
github:https://github.com/spring-cloud/spring-cloud-gateway
官方文档:https://docs.spring.io/spring-cloud-gateway/reference/
什么是 Gateway
Spring Cloud Gateway 是 Spring Cloud 生态中基于响应式编程模型的 API 网关,其核心作用可概括为:
流量管控中心 + 安全防护屏障 + 服务治理节点流量管控中心 + 安全防护屏障 + 服务治理节点
在微服务架构中,它处于客户端与后端服务之间,处理所有请求的路由、过滤和转换。
架构原理
-
核心组件:
- 路由(Route):定义请求转发规则,包含目标 URI、断言和过滤器链。
- 断言(Predicate):基于请求参数(路径、Header、时间等)的匹配条件。
- 过滤器(Filter):修改请求/响应的处理逻辑,分为全局过滤器和路由过滤器。
-
处理流程:
客户端请求 → 路由匹配 → 执行前置过滤器 → 转发到后端服务 → 执行后置过滤器 → 返回响应
-
数学模型示例(限流算法): 使用令牌桶算法实现限流时,设桶容量为 b,令牌生成速率为 r,则允许的最大突发请求量为:
突发流量 = b + r × t
当请求速率 λ > r 时触发限流。
关键特性与作用
功能模块 | 实现方式 | 典型场景示例 |
---|---|---|
动态路由 | 结合注册中心(如 Nacos)实现服务发现 | 灰度发布、AB 测试 |
限流熔断 | 集成 Resilience4j 或 Sentinel 组件 | 秒杀活动流量控制 |
安全认证 | 通过 JWT 验证过滤器实现 | OAuth2 鉴权 |
协议转换 | WebSocket 与 HTTP 协议互转 | 实时通信服务代理 |
监控日志 | 集成 Micrometer 输出指标到 Prometheus | 实时流量监控1 |
简单应用示例
- 路由配置(YAML)
spring:cloud:gateway:routes:- id: order_serviceuri: lb://order-servicepredicates:- Path=/api/orders/**filters:- StripPrefix=2- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 100 # 每秒令牌数redis-rate-limiter.burstCapacity: 200 # 桶容量
- 自定义全局过滤器
@Component
public class AuthFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String token = exchange.getRequest().getHeaders().getFirst("Authorization");if (!validateToken(token)) {exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}return chain.filter(exchange);}
}