内容概述

spring cloud的各种组件

Feign 声明式服务调用【掌握】
Hystrix 熔断器【掌握】
Gateway 网关【掌握】

每个组件都是为了解决微服务系统中的问题的。

一、Feign-概述

疑问: spring cloud远程调用还是让人觉得不好用,能不能像dubbo那样,直接调用远程的方法?

• Feign 是一个声明式的 REST 客户端,它用了基于接口的注解方式,很方便实现客户端配置。

• Feign 最初由 Netflix 公司提供。eureka也是Netflix 公司

二、Feign-快速入门

疑问: 如何使用feign客户端进行远程调用?

操作步骤:

  1. 在消费端feign-consumer 引入 open-feign 依赖
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. Feign是基于ribbon负载均衡的,使用前必须有ribbon配置。编写Feign调用接口
@Configuration
public class RestTemplateConfig {


@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}




/**
*
* feign声明式接口。发起远程调用的。
*
String url = "http://FEIGN-PROVIDER/goods/findOne/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
*
* 1. 定义接口
* 2. 接口上添加注解 @FeignClient,设置value属性为 服务提供者的 应用名称
* 3. 编写调用接口,接口的声明规则 和 提供方接口保持一致。
* 4. 注入该接口对象,调用接口方法完成远程调用
*
*/

@FeignClient(value = "FEIGN-PROVIDER")
public interface GoodsFeignClient {


@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);

}

  1. 在启动类 添加 @EnableFeignClients 注解,开启Feign功能
@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication

@EnableFeignClients //开启Feign的功能
public class ConsumerApp {


public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}

  1. controller 调用
@RestController
@RequestMapping("/order")
public class OrderController {

@Autowired
private GoodsFeignClient goodsFeignClient;

@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){

Goods goods = goodsFeignClient.findGoodsById(id);

return goods;
}

}
  1. 测试调用

http://localhost:9000/order/goods/1

三、Feign-超时配置 先配置熔断才行

疑问:远程调用,连接或者业务处理慢,超时了会有什么现象?

• Feign 底层依赖于 Ribbon 实现负载均衡和远程调用。
• Ribbon默认1秒超时。

超时会报错ReadTimeout,我们可以根据业务进行设置。
配置方式:


#配置熔断的时间监听
hystrix:
  command:
    default:
      execution:
          isolation:
            thread:
              timeoutInMilliseconds: 3000


# 设置Ribbon的超时时间
ribbon:
  ConnectTimeout: 1000 # 连接超时时间 默认1s
  ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s

四、Feign-日志记录

疑问:远程调用都被feign给封装了,如何才能看到请求,响应的细节,数据?

分析:
配置feign的日志记录

操作步骤:

  1. 设置当前日志的级别为debug
# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
level:
cn.kinggm520: debug     #调用了feign客户端所在代码的包名
  1. 定义Feign日志级别Bean
@Configuration
public class FeignLogConfig {


/*
NONE,不记录
BASIC,记录基本的请求行,响应状态码数据
HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
FULL;记录完成的请求 响应数据


*/

@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
  1. 启动Feign日志级别Bean
@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)
public interface GoodsFeignClient {


@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);

}
  1. 测试

http://localhost:9000/order/goods/1

五、Hystrix 熔断器-概述

• Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。
• 雪崩:一个服务失败,导致整条链路的服务都失败的情形。

Hystix 主要功能
• 隔离

  1. 线程池隔离

  2. 信号量隔离

• 降级:异常,超时

• 熔断

• 限流

总结: 主要解决服务器出现意外以后,应用该如何处理。

六、Hystrix 降级-服务提供方

疑问: 服务提供方何时会降级,如何编写代码?
分析:

服务提供方何时会降级?

两种情况:

  1. 服务端代码抛异常

  2. 服务端代码超时(默认1秒钟)

Hystrix 降级 – 服务提供方

操作步骤:

  1. 在服务提供方,引入 hystrix 依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  1. 在启动类上开启Hystrix功能:@EnableCircuitBreaker
/**
* 启动类
*/

@EnableEurekaClient 
@SpringBootApplication
@EnableCircuitBreaker // 开启Hystrix功能
public class ProviderApp {
  1. 定义降级方法
/**
* 定义降级方法:
*  1. 方法的返回值需要和原方法一样
*  2. 方法的参数需要和原方法一样
*  3. 就是只有方法名不同
*/
public Goods findOne_fallback(int id){
Goods goods = new Goods();
goods.setTitle("降级了~~~");

return goods;
}
  1. 使用 @HystrixCommand 注解配置降级方法
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback")
public Goods findOne(@PathVariable("id") int id){
。。。
}
  1. 如果要设置降级配置的属性,可以通过@HystrixCommand注解的commandProperties属性进行配置,配置的信息在HystrixCommandProperties类中定义。了解常用设置即可。
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")

})
public Goods findOne(@PathVariable("id") int id){

总结:

​ 定义的降级方法要和controller方法完全一致,除了方法名。通过fallbackMethod指定降级方法,只需要设置方法名即可,不要带括号什么的。

七、Hystrix 降级 – 服务消费方

疑问:那要是网络有问题,都不能连上提供方,还能降级吗?

分析:

Hystrix 降级 – 服务消费方

操作步骤:

  1. feign 组件已经集成了 hystrix 组件。

SpringCloud(二、服务组件Eureka、ribbon、feign、Hystrix、Gateway)_spring

  1. 在application.yml中配置开启 feign.hystrix.enabled = true
# 开启feign对hystrix的支持
feign:
hystrix:
enabled: true
  1. 定义feign 调用接口实现类,复写方法,即 降级方法
/**
* Feign 客户端的降级处理类
* 1. 定义类 实现 Feign 客户端接口
* 2. 使用@Component注解将该类的Bean加入SpringIOC容器
*/
@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {
@Override
public Goods findGoodsById(int id) {
Goods goods = new Goods();
goods.setTitle("又被降级了~~~");
return goods;
}
}

  1. 在 @FeignClient 注解中使用 fallback 属性设置降级处理类。
@FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class)
public interface GoodsFeignClient {


@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);

}

总结:

​ 注意编写的调用方降级类需要实现Feign客户端的接口,还要添加@Component注解交给spring容器管理。

问题:如果服务器端程序抛出异常,那么提供方还是消费方的降级方法生效?

​ 提供方生效,因为提供方降级后,将会给消费方返回了正常的结果,所以消费方就不会生效。

问题

服务处理的时间过长,但是不想因为超时降级,还需要得到服务器的结果,如何配置?

配置两个方面:

  1. feign客户端调用的时候 先配置熔断超时

#配置熔断的时间监听
hystrix:
  command:
    default:
      execution:
          isolation:
            thread:
              timeoutInMilliseconds: 3000


# 设置Ribbon的超时时间
ribbon:
  ConnectTimeout: 1000 # 连接超时时间 默认1s
  ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s
  1. 服务提供方降级的时间
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public Goods findOne(@PathVariable("id") int id){

八、Hystrix 熔断-概念

Hystrix 熔断机制,用于监控微服务调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。

SpringCloud(二、服务组件Eureka、ribbon、feign、Hystrix、Gateway)_客户端_02

总结:

熔断的目的是为了保护系统。全自动,不需要干预。

​ 三种状态之间的切换

  1. 关闭到打开。失败降级的次数达到阈值。默认5秒失败20次。
  2. 打开到半开。持续5秒钟。半开:(允许一半的请求通过)
  3. 半开到关闭。通过的请求成功超过80%

九、Hystrix 熔断-代码演示

分析:

​ 熔断是Hystrix 自动的机制,只要使用了Hystrix ,就可以进行系统的熔断保护。

所以我们做这个实验,只需要让我们的代码发生降级就可以。

需求: 让我们的请求ID为1的时候抛出异常,引发降级。

hystrix-provider的GoodsController中进行设置:

public Goods findOne(@PathVariable("id") int id){

//如果id == 1 ,则出现异常,id != 1 则正常访问
if(id == 1){
//1.造个异常
int i = 3/0;
}

可以通过@HystrixCommand注解的commandProperties属性进行配置:

@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//监控时间 默认5000 毫秒
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失败次数。默认20次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
//失败率 默认50%
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")

})
public Goods findOne(@PathVariable("id") int id){

十、Hystrix -熔断监控

分析:

Hystrix 熔断监控
• Hystrix 提供了 Hystrix-dashboard 功能,用于实时监控微服务运行状态。
• 但是Hystrix-dashboard只能监控一个微服务。
• Netflix 还提供了 Turbine ,进行聚合监控。

搭建Turbine 聚合监控的步骤:

SpringCloud-资料\day02\资料\1. turbine 搭建\Turbine搭建步骤.md

SpringCloud(二、服务组件Eureka、ribbon、feign、Hystrix、Gateway)_微服务_03

总结: 了解内容,面试能把Turbine 名字说出来就可以。

十一、Gateway 网关-概述

疑问: 什么是网关?干什么用的?

分析:

​ 定义:

• 网关旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。

• 在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。

• 存在的问题:
• 客户端多次请求不同的微服务,增加客户端的复杂性
• 认证复杂,每个服务都要进行认证
• http请求不同服务次数增加,性能不高

• 网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等

• 在目前的网关解决方案里,有Nginx+ Lua、Netflix Zuul 、Spring Cloud Gateway等等

SpringCloud(二、服务组件Eureka、ribbon、feign、Hystrix、Gateway)_客户端_04

总结: 网关也是一个应用,有了网关之后,我们所有的请求都访问网关应用,由网关帮我们去调用其他服务。

网关干什么用?主要功能有两个:

  1. 路由

  2. 过滤

十二、Gateway 网关-快速入门

疑问:如何来使用Gateway 网关?
需求:使用Gateway 网关来路由转发请求

操作步骤:

  1. 搭建网关模块,导入资料中的初始化代码

其实就是创建一个最基本的spring cloud模块。

  1. 引入依赖:starter-gateway
<dependencies>
<!--引入gateway 网关-->

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
  1. 编写启动类,无特殊操作
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {

public static void main(String[] args) {
SpringApplication.run(ApiGatewayApp.class,args);
}

}

  1. 编写配置文件
server:
port: 80

spring:
application:
name: api-gateway-server

cloud:
# 网关配置
gateway:
# 路由配置:转发规则
routes: #集合。
# id: 唯一标识。默认是一个UUID
# uri: 转发路径
# predicates: 条件,用于请求网关路径的匹配规则

- id: gateway-provider
uri: http://localhost:8001/
predicates:
- Path=/goods/**

- id: gateway-cum
uri: http://localhost:9000/
predicates:
- Path=/orders/**

  1. 启动测试

访问网关应用: http://localhost/goods/findOne/2

十三、Gateway 网关-静态路由

疑问: 什么是静态路由?

就是转发的地址是固定的。在开发中不便于维护,不使用。知道概念就可以。

分析:

配置:

server:
port: 80

spring:
application:
name: api-gateway-server

cloud:
# 网关配置
gateway:
# 路由配置:转发规则
routes: #集合。
# id: 唯一标识。默认是一个UUID
# uri: 转发路径
# predicates: 条件,用于请求网关路径的匹配规则
# filters:配置局部过滤器的

- id: gateway-provider
# 静态路由
uri: http://localhost:8001/
predicates:
- Path=/goods/**

- id: gateway-consumer
uri: http://localhost:9000
predicates:
- Path=/order/**
# 微服务名称配置

十四、Gateway 网关-动态路由

疑问:静态路由的缺点是什么?什么是动态路由?有什么用

分析:

静态路由的缺点是什么?

​ 静态路由,在网关中uri的配置是写死的,不便于维护。

什么是动态路由?有什么用?

​ 让网关应用能够从注册中心Eureka中,动态的通过应用的名称来获取应用的地址

配置方式:

  1. 添加依赖(之前已经完成)
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  1. 启动类添加注解(之前已经完成)
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {
  1. 配置动态路由
- id: gateway-consumer
# uri: http://localhost:9000
uri: lb://GATEWAY-CONSUMER
predicates:
- Path=/order/**


eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka

总结: 为网关添加Eureka客户端依赖,能够从注册中心发现服务。在配置路由的uri时,通过lb://服务名称 来获取转发服务器的地址信息。

十五、Gateway 网关 – 微服务名称配置

疑问: 网关路由转发的应用很多,名称容易冲突,如何进行方便的区分?

分析:

​ 将Eureka注册中心里应用的名称作为uri中的前缀来区分不同的应用。

配置:

spring:
application:
name: api-gateway-server

cloud:
# 网关配置
gateway:
discovery:
locator:
enabled: true # 设置为true 请求路径前可以添加微服务名称
lower-case-service-id: true # 允许为小写

测试:

​ 访问网关应用: http://localhost/goods/findOne/2

​ 也可以: http://localhost/gateway-provider/goods/findOne/2

十六、Gateway 网关 – 过滤器-概述

过滤器

• Gateway 支持过滤器功能,对请求或响应进行拦截,完成一些通用操作。

• Gateway 提供两种过滤器方式:“pre”和“post”
• pre 过滤器,在转发之前执行,可以做参数校验、权限校验、流量监控、日志输出、协议转换等。
• post 过滤器,在响应之前执行,可以做响应内容、响应头的修改,日志的输出,流量监控等。

• Gateway 还提供了两种类型过滤器
• GatewayFilter:局部过滤器,针对单个路由
• GlobalFilter :全局过滤器,针对所有路由

SpringCloud(二、服务组件Eureka、ribbon、feign、Hystrix、Gateway)_客户端_05

十七、Gateway 网关 – 局部过滤器

局部过滤器

• GatewayFilter 局部过滤器,是针对单个路由的过滤器。

• 在Spring Cloud Gateway 组件中提供了大量内置的局部过滤器,对请求和响应做过滤操作。

• 遵循约定大于配置的思想,只需要在配置文件配置局部过滤器名称,并为其指定对应的值,就可以让其生效。

参考资料: SpringCloud-资料\day02\资料\2. gateway内置过滤器工厂

配置:

# filters:配置局部过滤器的

- id: gateway-provider
# 静态路由
# uri: http://localhost:8001/
# 动态路由
uri: lb://GATEWAY-PROVIDER
predicates:
- Path=/goods/**
filters:
- AddRequestParameter=username,zhangsan

总结:

​ 根据文档中的过滤器的作用和名称进行配置,过滤的参数和值之间使用,逗号分隔。

十八、Gateway 网关 – 全局过滤器

全局过滤器

• GlobalFilter 全局过滤器,不需要在配置文件中配置,系统初始化时加载,并作用在每个路由上。

• Spring Cloud Gateway 核心的功能也是通过内置的全局过滤器来完成。

• 自定义全局过滤器步骤:

  1. 定义类实现 GlobalFilter 和 Ordered接口
  2. 复写方法
  3. 完成逻辑处理
@Component
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

System.out.println("自定义全局过滤器执行了~~~");
//获取web应用的对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();

return chain.filter(exchange);//放行
}

/**
* 过滤器排序
* @return 数值越小 越先执行
*/
@Override
public int getOrder() {
return 0;
}
}

总结:

自定义全局过滤器无需配置,只需要实现接口中的方法就可以。

自定义的过滤器需要添加@Component交给spring容器管理。