Spring Cloud 就是微服务系统架构的一站式解决方案。
提供服务发现注册 、配置中心 、消息总线 、负载均衡 、断路器 、数据监控 等操作。
微服务组件
服务注册发现,统一配置管理,服务远程调用,统一网关路由,服务链路监控,流控,降级,保护
创建微服务项目步骤
1.聚合项目的pom文件
<packaging>pom</packaging>
springboot的<parent>,微服务的版本,alibaba的版本,版本存在冲突的问题。
<modules> 将子服务加入进来。
<properties>定义依赖的版本信息
<dependencyManagement> 管理依赖的版本信息,子服务按需导入即可
<dependencies>引入全部服务所需的依赖
2.子项目(子服务)的pom文件
子项目的打包方式不能为pom。
需要引入构建依赖
服务的注册发现
1.Eureka服务注册发现
创建启动Eureka服务端项目
将消费者注册到服务端项目中,每30s进行心跳续约
每个服务都是服务的客户端(eureka-client),eureka-server服务端只有一个(@EnableEurekaServe)。
2.Nacos注册中心
下载启动nacos服务端
将消费者注册到acos服务端中,每30s进行心跳续约
集群:一个服务可以包含多个集群,如杭州、上海,每个集群下可以有多个实例,形成分级模型
配置文件添加:cluster-name: HZ # 集群名称
同集群优先的负载均衡:
ribbon:NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
权重配置:性能好的机器承担更多的用户请求。在nacos控制台,找到user-service的实例列表,点击编辑,即可修改权重
环境隔离:namespace>Group>Service
服务实例:
临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型
非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。 ephemeral: false # 设置为非临时实例
3.Nacos与Eureka的区别
都支持服务注册和服务拉取
都支持服务提供者心跳方式做健康检测
Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式,临时实例心跳不正常会被剔除,非临时实例则不会被剔除
Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
服务的配置管理
1.Config+Bus
Spring Cloud 配置管理——Config
Spring Cloud Bus 的作用就是管理和广播分布式系统中的消息
2.Nacos配置管理
配置文件需要加上后缀名
读取配置文件:@Value(“${}”)+{@RefreshScope}
多环境配置文件:本地指明profile。服务名-profile.yaml>服务名.yaml>本地配置
服务远程调用
1.RestTemplate+LoadBalanced
RestTemplate是Spring提供的一个访问 Http 服务的客户端类
Ribbon是负载均衡器,在消费者端,在返回RestTemplate添加了@LoadBalanced注解
SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载均衡功能的
LoadBalancerInterceptor这个类会在对RestTemplate的请求进行拦截,然后LoadBalancerClient从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。
负载均衡策略:
RoundRobinRule:轮询策略
RandomRule: 随机策略,
WeightedResponseTimeRule:权重值
RetryRule: 重试策略。
自定义负载均衡策略:
第一种方式:
@Bean
public IRule randomRule(){
return new RandomRule();
}
第二种方式:
providerName:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
2.Open Feign
调用原来代码一样进行各个服务间的调用。OpenFeign 也是运行在消费者端的,使用 Ribbon 进行负载均衡,所以 OpenFeign 直接内置了 Ribbon。
使用:
① 引入依赖
② 添加@EnableFeignClients注解
③ 编写FeignClient接口
④ 使用FeignClient中定义的方法代替RestTemplate
自定义配置:
feign.Logger.Level 修改日志级别
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据
feign.codec.Encoder 将请求参数编码,便于通过http请求发送
feign.Retryer 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试
Feign使用优化:使用连接池代替默认的URLConnection
1)引入依赖 feign-httpclient
2)配置:
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
单独创建一个独立模块抽离出来,子服务需要引用的时候,用依赖进行引用,此时需要指定Feign应该扫描的包:@EnableFeignClients(basePackages = “cn.itcast.feign.clients”)
微服务网关
1.Zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
@EnableZuulProxy
网关是系统唯一对外的入口,介于客户端与服务器端之间,用于对请求进行鉴权、限流、 路由、监控等功能。
路由策略配置;服务名屏蔽;路径屏蔽;敏感请求头屏蔽;过滤功能;令牌桶限流;
2.Gateway服务网关
网关搭建步骤:
创建项目,引入nacos服务发现和gateway依赖
配置application.yml,包括服务基本信息、nacos地址、路由
路由配置包括:
路由id:路由的唯一标示
路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
路由断言(predicates):判断路由的规则,
路由过滤器(filters):对请求或响应做处理
路由规则:
cloud:
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
filters: # 过滤器
- AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
default-filters: # 默认过滤项
- AddRequestHeader=Truth, Itcast is freaking awesome!
在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
断言工厂:
After:是某个时间点后的请求。- After=2037-01-20T17:42:47.789-07:00
Header:请求必须包含某些header。- Header=X-Request-Id, \d+
Method:请求方式必须是指定方式。- Method=GET,POST
Path:请求路径必须符合指定规则。- Path=/red/{segment},/blue/**
过滤器工厂:配置文件
AddRequestHeader:给当前请求添加一个请求头
RequestRateLimiter:限制请求的流量
全局过滤器:拦截请求,做自己的业务逻辑。自定义全局过滤器实现GlobalFilter接口
order值越小,优先级越高,执行顺序越靠前。
@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
MultiValueMap<String, String> params = exchange.getRequest().getQueryParams(); // 1.获取请求参数
String auth = params.getFirst("authorization"); // 2.获取authorization参数
。。。 // 逻辑处理
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); 4.1.禁止访问,设置状态码
return exchange.getResponse().setComplete();// 4.2.结束处理
}
}
过滤器执行顺序:当前路由的过滤器、DefaultFilter、GlobalFilter
服务链路监控,流控,降级,保护
1.Hystrix
一个能进行 熔断 和 降级 的库,通过使用它能提高整个系统的弹性。
@HystrixCommand:熔断 就是服务雪崩的一种有效解决方案。当指定时间窗内的请求失败率达到设定阈值时,系统将通过 断路器 直接将此请求链路断开。
降级是为了更好的用户体验,当一个方法调用异常时,通过执行另一种代码逻辑来给用户友好的回复。这也就对应着 Hystrix 的 后备处理 模式。你可以通过设置 fallbackMethod 来给一个方法设置备用的代码逻辑。
2.Sentinel
解决雪崩问题的常见方式有四种:
超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待
仓壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离
断路器模式:由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。
流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。
限流是对服务的保护,避免因瞬间高并发流量而导致服务故障,进而避免雪崩。是一种预防措施。
超时处理、线程隔离、降级熔断**是在部分服务故障时,将故障控制在一定范围,避免雪崩。是一种补救措施。
SpringBoot整合Sentinel
引入依赖:
1.spring-cloud-starter-alibaba-sentinel
2.配置信息
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
Sentinel簇点链路
一个调用链,可以进行流控,降级,热点,授权
流控
QPS:
单机阈值:每秒只允许1次请求,超出的请求会被拦截并报错。
流控模式:断路器统计的对象不同
- 直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式
- 关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
当/write资源访问量触发阈值时,就会对/read资源限流,避免影响/write资源。 - 链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流
流控效果:
- 快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。QPS超过阈值时,拒绝新的请求
- warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。: QPS超过阈值时,拒绝新的请求;QPS阈值是逐渐提升的,可以避免冷启动时高并发导致服务宕机。
- 排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长。请求会进入队列,按照阈值允许的时间间隔依次执行请求;如果请求预期等待时长大于超时时间,直接拒绝
线程数:
基于线程池模式,有额外开销,但隔离控制更强
降级
熔断降级
熔断机制
慢调用,异常比例或异常数
慢调用
业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断
异常比例或异常数
统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断。
断路器
断路器控制熔断和放行是通过状态机来完成的:断路器熔断策略有三种:慢调用、异常比例、异常数
状态机包括三个状态(动态切换):
- closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
- open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态5秒后会进入half-open状态
- half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。
- 请求成功:则切换到closed状态
- 请求失败:则切换到open状态
FeignClient整合Sentinel
1.配置开启sentinel功能
feign:
sentinel:
enabled: true # 开启feign对sentinel的支持
2.编写失败降级逻辑
业务失败后,不能直接报错,而应该返回用户一个友好提示或者默认结果,这个就是失败降级逻辑。
给FeignClient编写失败后的降级逻辑
①方式一:FallbackClass,无法对远程调用的异常做处理
②方式二:FallbackFactory,可以对远程调用的异常做处理,我们选择这种
3.在feing-api项目中定义类,实现FallbackFactory
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {}
4.在feing-api项目中的DefaultFeignConfiguration类中将UserClientFallbackFactory注册为一个Bean
5.在feing-api项目中的UserClient接口中使用UserClientFallbackFactory:
@FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class)
热点
热点参数限流,是限流的一种。分别统计参数值相同的请求,判断是否超过QPS阈值
授权
请求的权限控制
授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式。
- 白名单:来源(origin)在白名单内的调用者允许访问
- 黑名单:来源(origin)在黑名单内的调用者不允许访问
Sentinel是通过RequestOriginParser这个接口的parseOrigin来获取请求的来源的。
既然获取请求origin的方式是从reques-header中获取origin值,我们必须让所有从gateway路由到微服务的请求都带上origin头。
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=origin,gateway
routes:
Hystrix和Sentinel区别
Sentine:信号量隔离,基于慢调用比例或异常比例,滑动窗口
Hystrix:线程池隔离/信号量隔离,基于失败比率
规则持久化
原始模式:Sentinel的默认模式,将规则保存在内存,重启服务会丢失。
pull模式:控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则。
push模式:控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新。