一、基本概念
Spring Cloud 被称为构建分布式微服务系统的“全家桶”,它并不是某一门技术,而是一系列微服务解决方案或框架的有序集合。它将市面上成熟的、经过验证的微服务框架整合起来,并通过 Spring Boot 的思想进行再封装,屏蔽调其中复杂的配置和实现原理,最终为开发人员提供了一套简单易懂、易部署和易维护的分布式系统开发工具包。
二、版本对应
在使用 Spring Boot + Spring Cloud 进行微服务开发时,我们需要根据项目中 Spring Boot 的版本来决定 Spring Cloud 版本,否则会出现许多意想不到的错误。Spring Boot 与 Spring Cloud 的版本对应关系如下表:
Spring Cloud Alibaba Version | Spring Cloud Version | Spring Boot Version |
---|---|---|
2022.0.0.0-RC* | Spring Cloud 2022.0.0 | 3.0.0 |
2021.0.4.0* | Spring Cloud 2021.0.4 | 2.6.11 |
2021.0.1.0 | Spring Cloud 2021.0.1 | 2.6.3 |
2021.1 | Spring Cloud 2020.0.1 | 2.4.2 |
2.2.9.RELEASE* | Spring Cloud Hoxton.SR12 | 2.3.12.RELEASE |
2.2.8.RELEASE | Spring Cloud Hoxton.SR12 | 2.3.12.RELEASE |
2.2.7.RELEASE | Spring Cloud Hoxton.SR12 | 2.3.12.RELEASE |
2.2.6.RELEASE | Spring Cloud Hoxton.SR9 | 2.3.2.RELEASE |
2.1.4.RELEASE | Spring Cloud Greenwich.SR6 | 2.1.13.RELEASE |
2.2.1.RELEASE | Spring Cloud Hoxton.SR3 | 2.2.5.RELEASE |
2.2.0.RELEASE | Spring Cloud Hoxton.RELEASE | 2.2.X.RELEASE |
2.1.2.RELEASE | Spring Cloud Greenwich | 2.1.X.RELEASE |
三、SpringCloud Netflix
<dependencyManagement>
<dependencies>
<!--在主工程中使用 dependencyManagement 声明 Spring Cloud 的版本,
这样工程内的 Module 中引入 Spring Cloud 组件依赖时,就不必在声明组件的版本信息
保证 Spring Cloud 各个组件一致性-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
1.Eureka:Eureka 是 Netflix 公司开发的一款开源的服务注册与发现组件。
服务注册中心:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
server:
port: 8080 #该 Module 的端口号
eureka:
instance:
hostname: localhost #eureka服务端的实例名称,
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: #将自己注册到其他注册中心(集群)
在主启动类上使用 @EnableEurekaServer 注解开启服务注册中心功能,接受其他服务的注册。
服务提供者/消费者:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
server:
port: 8081 #服务端口号
spring:
application:
name: microServiceCloudProviderDept #微服务名称,对外暴漏的微服务名称,十分重要
eureka:
client:
service-url:
defaultZone: ##将自己注册到其他注册中心(集群)
instance:
instance-id: spring-cloud-provider-8001 #自定义服务名称信息
prefer-ip-address: true #显示访问路径的 ip 地址
在主启动类上,使用 @EnableEurekaClient 注解开启 Eureka 客户端功能,将服务注册到服务注册中心。
2.Ribbon:Netflix Ribbon 是 Netflix 公司发布的开源组件,其主要功能是提供客户端的负载均衡算法和服务调用。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
@Bean //将 RestTemplate 注入到容器中
@LoadBalanced //在客户端使用 RestTemplate 请求服务端时,开启负载均衡(Ribbon)
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean //切换负载均衡策略
public IRule iRule() {
return new RandomRule();
}
3.OpenFeign:OpenFeign 全称 Spring Cloud OpenFeign,它是 Spring 官方推出的一种声明式服务调用与负载均衡组件,且内部集成了 Ribbon,是为了替代 RestTemplete 进行远程调用。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
//服务提供者提供的服务名称,即 application.name
@FeignClient(value = "")
public interface UserService {
//接口内部的定义与被调用服务的接口一致
}
在主启动类上添加 @EnableFeignClients 注解开启 OpenFeign 功能。
4.Hystrix:Spring Cloud Hystrix 是基于 Netflix 公司的开源组件 Hystrix 实现的,它提供了熔断器功能,能够有效地阻止分布式微服务系统中出现联动故障,以提高微服务系统的弹性。Spring Cloud Hystrix 具有服务降级、服务熔断、线程隔离、请求缓存、请求合并以及实时故障监控等强大功能。
服务降级:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
//一旦该方法失败并抛出了异常信息后,会自动调用fallbackMethod指定的方法
//规定 5 秒钟以内就不报错,正常运行,超过 5 秒就报错,调用指定的方法
@HystrixCommand(fallbackMethod = "exceptionHandler",
commandProperties =
{@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "5000")})
在主启动类上添加 @EnableCircuitBreaker 注解开启功能。
如果是客户端服务需要降级,需要在主启动类上添加 @EnableHystrix 注解,还需要配置:
feign:
hystrix:
enabled: true #开启客户端 hystrix
服务熔断:
@HystrixCommand(fallbackMethod = "deptCircuitBreaker_fallback", commandProperties = {
//以下参数在 HystrixCommandProperties 类中有默认配置
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启熔断器
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "1000"), //统计时间窗
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //统计时间窗内请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //休眠时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), //在统计时间窗口期以内,请求失败率达到 60% 时进入熔断状态
})
参数 | 描述 |
---|---|
metrics.rollingStats.timeInMilliseconds | 统计时间窗。 |
circuitBreaker.sleepWindowInMilliseconds | 休眠时间窗,熔断开启状态持续一段时间后,熔断器会自动进入半熔断状态,这段时间就被称为休眠窗口期。 |
circuitBreaker.requestVolumeThreshold | 请求总数阀值。 在统计时间窗内,请求总数必须到达一定的数量级,Hystrix 才可能会将熔断器打开进入熔断开启转态,而这个请求数量级就是 请求总数阀值。Hystrix 请求总数阈值默认为 20,这就意味着在统计时间窗内,如果服务调用次数不足 20 次,即使所有的请求都调用出错,熔断器也不会打开。 |
circuitBreaker.errorThresholdPercentage | 错误百分比阈值。 当请求总数在统计时间窗内超过了请求总数阀值,且请求调用出错率超过一定的比例,熔断器才会打开进入熔断开启转态,而这个比例就是错误百分比阈值。错误百分比阈值设置为 50,就表示错误百分比为 50%,如果服务发生了 30 次调用,其中有 15 次发生了错误,即超过了 50% 的错误百分比,这时候将熔断器就会打开。 |
5.Gateway:Spring Cloud Gateway 是 Spring Cloud 团队基于 Spring 5.0、Spring Boot 2.0 和 Project Reactor 等技术开发的高性能 API 网关组件。
网关服务不能导入spring-web 依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
spring:
cloud:
gateway: #网关路由配置,将服务器提供的服务隐藏起来,不暴露给客户端,只给客户端暴露 API 网关的地址
routes:
#可配置多个路由
- id: #路由id,没有固定规则,但唯一,建议与服务名对应
uri:lb://service-name #路由匹配后提供服务的服务名
predicates:
#以下是断言条件,必选全部符合条件
- Path= #断言,路径匹配 注意:Path 中 P 为大写
- Method=GET #只能时 GET 请求时,才能访问
filters:
- AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名称为 X-Request-Id 值为 1024
- PrefixPath=/prefix #在请求路径前面加上 /prefix
常用断言:
断言 | 示例 | 说明 |
---|---|---|
Path | - Path=/dept/list/** | 当请求路径与 /dept/list/** 匹配时,该请求才能被转发到 http://localhost:8001 上。 |
Before | - Before=2021-10-20T11:47:34.255+08:00[Asia/Shanghai] | 在 2021 年 10 月 20 日 11 时 47 分 34.255 秒之前的请求,才会被转发到 http://localhost:8001 上。 |
After | - After=2021-10-20T11:47:34.255+08:00[Asia/Shanghai] | 在 2021 年 10 月 20 日 11 时 47 分 34.255 秒之后的请求,才会被转发到 http://localhost:8001 上。 |
Between | - Between=2021-10-20T15:18:33.226+08:00[Asia/Shanghai],2021-10-20T15:23:33.226+08:00[Asia/Shanghai] | 在 2021 年 10 月 20 日 15 时 18 分 33.226 秒 到 2021 年 10 月 20 日 15 时 23 分 33.226 秒之间的请求,才会被转发到 http://localhost:8001 服务器上。 |
Cookie | - Cookie=name,c.biancheng.net | 携带 Cookie 且 Cookie 的内容为 name=c.biancheng.net 的请求,才会被转发到 http://localhost:8001 上。 |
Header | - Header=X-Request-Id,\d+ | 请求头上携带属性 X-Request-Id 且属性值为整数的请求,才会被转发到 http://localhost:8001 上。 |
Method | - Method=GET | 只有 GET 请求才会被转发到 http://localhost:8001 上。 |
常用过滤:
路由过滤器 | 描述 | 参数 | 使用示例 |
---|---|---|---|
AddRequestHeader | 拦截传入的请求,并在请求上添加一个指定的请求头参数。 | name:需要添加的请求头参数的 key; value:需要添加的请求头参数的 value。 | - AddRequestHeader=my-request-header,1024 |
AddRequestParameter | 拦截传入的请求,并在请求上添加一个指定的请求参数。 | name:需要添加的请求参数的 key; value:需要添加的请求参数的 value。 | - AddRequestParameter=my-request-param,c.biancheng.net |
AddResponseHeader | 拦截响应,并在响应上添加一个指定的响应头参数。 | name:需要添加的响应头的 key; value:需要添加的响应头的 value。 | - AddResponseHeader=my-response-header,c.biancheng.net |
PrefixPath | 拦截传入的请求,并在请求路径增加一个指定的前缀。 | prefix:需要增加的路径前缀。 | - PrefixPath=/consumer |
PreserveHostHeader | 转发请求时,保持客户端的 Host 信息不变,然后将它传递到提供具体服务的微服务中。 | 无 | - PreserveHostHeader |
RemoveRequestHeader | 移除请求头中指定的参数。 | name:需要移除的请求头的 key。 | - RemoveRequestHeader=my-request-header |
RemoveResponseHeader | 移除响应头中指定的参数。 | name:需要移除的响应头。 | - RemoveResponseHeader=my-response-header |
RemoveRequestParameter | 移除指定的请求参数。 | name:需要移除的请求参数。 | - RemoveRequestParameter=my-request-param |
RequestSize | 配置请求体的大小,当请求体过大时,将会返回 413 Payload Too Large。 | maxSize:请求体的大小。 | - name: RequestSize args: maxSize: 5000000 |
全局过滤器:
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return null;
}
@Override
public int getOrder() {
//过滤器的顺序,0 表示第一个
return 0;
}
}
四、SpringCloud Alibaba
<dependencyManagement>
<dependencies>
<!--Spring Cloud Alibaba 的版本信息-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring Cloud 的版本信息-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
1.Nacos:Nacos 服务注册中心和配置中心的组合体,它可以替换 Eureka 作为服务注册中心,实现服务的注册与发现;还可以替换 SpringCloud Config 作为配置中心,实现配置的动态刷新。先在官网下载 Nacos Server 并运行。
注册中心:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
spring:
cloud:
nacos:
discovery:
cluster-name: BJ #设置集群
namespace: public #命名空间
ephemeral: false #设置非临时实例
server-addr: localhost:8848 #注册中心地址
在主启动类上,使用 @EnableDiscoveryClient 注解开启 Nacos 服务发现功能。
配置中心:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
在 /resources 目录下,添加一个 bootstrap.yml文件:
#启动时获取远程配置
spring:
application:
name: book #应用名称
profiles:
active: public #应用环境
cloud:
nacos:
config:
file-extension: yaml #文件名后缀
server-addr: localhost:8848 #配置中心地址
group: #配置分组
在 Nacos 控制台新建配置文件,并进行配置,文件名:
${application.name}-${spring.profiles.active}.${file-extension}
在 Controller 类上使用 @RefreshScope 注解实现配置的自动更新。
集群:在 mysql 执行 conf 中的 mysql-schema.sql 文件,并在 application.properties 文件中添加数据库信息。
2.Sentinel:Sentinel 是由阿里巴巴中间件团队开发的开源项目,是一种面向分布式微服务架构的轻量级高可用流量控制组件。先在官网下载 jar 包并运行。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
spring:
cloud:
sentinel:
transport:
#配置 Sentinel dashboard 地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
限流:可以通过 Sentinel 控制台,直接对资源定义流控规则。
属性 | 说明 | 默认值 |
---|---|---|
资源名 | 流控规则的作用对象。 | - |
阈值 | 流控的阈值。 | - |
阈值类型 | 流控阈值的类型,包括 QPS 或并发线程数。 | QPS |
针对来源 | 流控针对的调用来源。 | default,表示不区分调用来源 |
流控模式 | 调用关系限流策略,包括直接、链路和关联。 | 直接 |
流控效果 | 流控效果(直接拒绝、预热、匀速排队),不支持按调用关系限流。 | 直接拒绝 |
在服务代码中使用 @SentinelResource 注解定义资源名称,并在 blockHandler 属性指定一个限流函数或 blockHandlerClass 限流类,自定义服务限流信息。使用 @SentinelResource 注解的 blockHandler 属性时,需要注意以下事项:
- blockHandler 函数访问范围需要是 public;
- 返回类型需要与原方法相匹配;
- 参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException;
- blockHandler 函数默认需要和原方法在同一个类中,若希望使用其他类的函数,则可以指定 blockHandler 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
熔断降级: 可以通过 Sentinel 控制台直接对资源定义熔断降级规则。
熔断策略 | 说明 |
---|---|
慢调用比例 (SLOW_REQUEST_RATIO) | 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大响应时间),若请求的响应时间大于该值则统计为慢调用。 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则再次被熔断。 |
异常比例 (ERROR_RATIO) | 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目且异常的比例大于阈值,则在接下来的熔断时长内请求会自动被熔断。 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。 |
异常数 (ERROR_COUNT) | 当单位统计时长内的异常数目超过阈值之后会自动进行熔断。 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。 |
规则持久化:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
spring:
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: #微服务名称
groupId: #分组名称
data-type: json
rule-type: flow #流控规则
在 nacos 控制台添加配置:
[
{
"resource":"/persistent",//资源名称
"limitApp":"default",//来源应用
"grade":1,//阈值类型,0线程数,1QPS
"count":1,//单机阈值
"strategy":0,//流控模式,0表示直接,1表示关联,2表示链路
"controlBehavior":0,//流控效果 ,0表示快速失败,1表示warm up,2表示排队等待
"clusterMode":false //是否集群
}
]
3.Seata:Seata 是一个分布式事务处理框架,它是由阿里巴巴和蚂蚁金服共同开源的分布式事务解决方案,能够在微服务架构下提供高性能且简单易用的分布式事务服务。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
在事务方法上添加 @GlobalTransactional