002 SpringCloud 的 Feign 调用、Hystix 熔断和 Gateway 网关

SpringCloud02-Feign、Hystix 和 Gateway

文章目录

  • SpringCloud02-Feign、Hystix 和 Gateway
    • 3.Feign 声明式服务调用
      • 3.1 Feign 声明式服务调用
      • 3.2 feign 超时设置
      • 3.3 Feign 日志记录
    • 4.Hystrix 熔断器
      • 4.1 Hystix降级
        • 1.服务提供方降级
        • 2.服务消费方降级
      • 4.2 Hystrix熔断
      • 4.3 Hystrix熔断监控
    • 5.Gateway 网关
      • 5.1 Gateway 网关快速入门
      • 5.2 Gateway 路由配置
      • 5.3 Gateway 过滤器

3.Feign 声明式服务调用

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

作用在消费端

3.1 Feign 声明式服务调用

使用步骤:

  1. 在消费端引入open-feign依赖
  2. 编写Feign调用接口
  3. 在启动类添加 @EnableFeignClients注解,开启Feign功能。

依赖

  		 <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>       
		
       <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>

调用接口

/**
 * feign的声明式调用接口
 *   String url = "http://EUREKA-PROVIDER/goods/goods/"+id;
 * 1.声明接口
 * 2.添加 @FeignClient 注解,其中 value为服务提供方的应用名,即 ribbon调用时的url里的名称,而调用地址则由接口声明。
 * 3.声明调用接口方法,接口方法规则要与服务提供方的调用方法规则一致,方法名和返回值可以不一致。
 * 4.在控制层注入接口
 */

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

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

}
    @Resource
    private GoodsFeignClient goodsFeignClient;

    /**
     * feign调用
     * @param id
     * @return
     */
    @GetMapping("/goods3/{id}")
    public Goods findGoodsById3(@PathVariable("id") Integer id){
        Goods goods = goodsFeignClient.findGoodsById(id);
        return goods;
    }

3.2 feign 超时设置

Feign底层依赖于Ribbon实现负载均衡和远程调用,所以一般配置Ribbon的超时,但Feign实际也有自己的超时配置。

Ribbon默认超时一秒。超时报错。

调用方配置

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

3.3 Feign 日志记录

调用的数据包监控。

1.Feign只能记录debug级别的日志信息

# 设置当前的日志级别为debug
logging:
  level:
    com.li: debug

2.定义Feign日志级别Bean

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

    @Bean
    public Logger.Level level(){
        return Logger.Level.FULL;
    }
}

3.启用该Bean

@FeignClient(value = "EUREKA-PROVIDER",configuration = FeignLogConfig.class)

4.Hystrix 熔断器

Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库、防止出现级联失败(雪崩)。

雪崩:一个服务失败,导致整条链路的服务都失败的情形。

Hystrix主要功能 :

  • ​ 隔离:

    ​ 线程池隔离:如果服务a调用服务时,服务挂掉,则可能a会有更多线程去调用服务,但都无法释放导致线程池可用线程资源耗尽,其他服务则不能正常调用,所以需要线程池隔离。默认为线程池隔离。

    ​ 信号量隔离:添加访问次数,超过次数可以拒绝提供服务。

  • ​ 降级 :提供方和消费方都需要降级,异常,超时。给提示。

  • ​ 熔断 :

  • ​ 限流

4.1 Hystix降级

当服务发生异常或调用超时,返回默认数据。

1.服务提供方降级

  1. 引入hystrix依赖
    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
    dependency>
  1. 定义降级方法
    /**
     * 定义降级方法:
     * 1.方法的返回值需要和原方法一样
     * 2.方法的参数需要和原方法一样
     */
    public Goods findGoods_fallback(@PathVariable("id") Integer id){
        Goods goods = new Goods();
        goods.setName("降级了~~~");
        return goods;
    }
  1. 使用@HystrixCommand注解配置降级方法
 /**
     * feign调用
     *  @HystrixCommand 注解降级,当异常或超时后降级,默认超时一秒
     *  其中 fallbackMethod 属性为降级后执行的方法,commandProperties 来指定其他配置
     *  @HystrixProperty 指定其属性配置,如超时时间,
     *  HystrixCommandProperties类中定义了各个参数
     */
    @GetMapping("/goods/{id}")
    @HystrixCommand(fallbackMethod = "findGoods_fallback",commandProperties = {
            //超时三秒降级
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public Goods findGoodsById(@PathVariable("id") Integer id){
        int i = 1/0;
        Goods goods = goodsService.findOne(id);
        goods.setName(goods.getName()+":"+port);
        return goods;
    }
  1. 在启动类上开启Hystrix
@EnableCircuitBreaker

2.服务消费方降级

消费方也可以使用服务端的写法来编写降级

由于消费方使用feign组件进行远程调用,而feign组件已经集成了hystrix组件

定义feign 调用接口实现类,复写方法,即降级方法。

@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {
    @Override
    public Goods findGoodsById(Integer id) {
        Goods goods = new Goods();
        goods.setName("消费端降级~~");
        return goods;
    }
}

在@FeignClient注解中使用fallback属性设置降级处理类。

@FeignClient(value = "EUREKA-PROVIDER",fallback = GoodsFeignClientFallback.class)

配置开启 feign的hystrix支持,默认关闭

# 启用feign的hystrix降级
feign:
  hystrix:
    enabled: true

注意:当服务端和消费端都提供了降级时,由于提供方已经降级所以提供的数据就是正常数据而不是异常数据,一般为调用超时或调用异常降级,所以显示的是服务端降级。

4.2 Hystrix熔断

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

如果熔断时,5秒后,断路器会半开尝试,调用失败继续打开断路器,如果调用成功次数达到阈值,则关闭熔断器。

熔断器机制默认是开启的。

配置

   @GetMapping("/goods/{id}")
    @HystrixCommand(fallbackMethod = "findGoods_fallback",commandProperties = {
       //超时三秒降级
      @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
       //失败次数,默认20次
      @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "20"),
       //监控时间,默认5000毫秒
      @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
       //失败率,默认50%
      @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50")
    })

4.3 Hystrix熔断监控

Hystrix 提供了Hystrix-dashboard 功能,用于实时监控微服务运行状态。但只能监控一个微服务。

Netflix提供了Turbine,进行聚合监控。

在浏览器访问http://localhost:8769/hystrix/ 进入Hystrix Dashboard界面

界面中输入监控的Url地址 http://localhost:8769/turbine.stream,监控时间间隔2000毫秒和title,

5.Gateway 网关

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

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

​ 存在的问题:

​ 客户端多次请求不同的微服务,增加客户端的复杂性

​ 认证复杂,每个服务都要进行认证

​ http请求不同服务次数增加,性能不高

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

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

5.1 Gateway 网关快速入门

1.搭建网关模块

2.引入依赖

	 <dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>
    dependencies>

3.编写启动类

4.编写配置文件

server:
  port: 80

spring:
  application:
    name: api-gateway-server
  cloud:
    # 网关配置
    gateway:
      #路由配置:转发规则
      routes: #集合
      # id:唯一标识。默认是一个UUID
      # uri:转发路径
      # predicates:条件,用于请求网关路径的匹配规则
      - id: eureka-provider
        uri: http://localhost:8001/
        predicates:
        - Path=/goods/**

注意:此时服务端请求调用有效http://localhost/goods/goods/1。消费端不能用80端口

5.2 Gateway 路由配置

1.静态路由

server:
  port: 80

spring:
  application:
    name: api-gateway-server
  cloud:
    # 网关配置
    gateway:
      #路由配置:转发规则
      routes: #集合
        # id:唯一标识。默认是一个UUID
        # uri:转发路径
        # predicates:条件,用于请求网关路径的匹配规则
        - id: eureka-provider
          uri: http://localhost:8001/
          predicates:
            - Path=/goods/**

        - id: eureka-consumer
            uri: http://localhost:9000/
            predicates:
              - Path=/order/**

2.动态路由

通过eureka动态拉取数据

引入eureka-client配置

server:
  port: 80

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信

spring:
  application:
    name: api-gateway-server
  cloud:
    # 网关配置
    gateway:
      #路由配置:转发规则
      routes: #集合
        # id:唯一标识。默认是一个UUID
        # uri:转发路径
        # predicates:条件,用于请求网关路径的匹配规则
        - id: eureka-provider
          # 静态路由
          # uri: http://localhost:8001/
          # 动态路由
          uri: lb://EUREKA-PROVIDER
          predicates:
            - Path=/goods/**

        - id: eureka-consumer
            # uri: http://localhost:9000/
            uri: lb://EUREKA-CONSUMER
            predicates:
              - Path=/order/**
      # 微服务名称配置,并且配置后,不管路径添加不添加标识都能正常访问
      discovery:
        locator:
          enabled: true #设置为true
          lower-case-service-id: true #允许小写,因为Eureka默认应用名称为大写

3. 微服务名称配置

路径太多可能会冲突,可以使用名称来标识

spring:
  cloud:
    # 网关配置
    gateway:
      # 微服务名称配置,并且配置后,不管路径添加不添加标识都能正常访问
      discovery:
        locator:
          enabled: true #设置为true
          lower-case-service-id: true #允许小写,因为Eureka默认应用名称为大写

5.3 Gateway 过滤器

  • Gateway 支持过滤器功能,对请求或响应进行拦截,完成一些通用操作。
  • Gateway 提供两种过滤器方式:”pre“和”post“。
  • pre 过滤器,在转发之前执行,可以做参数校验、权限校验、流量监控、日志输出、协议转换等。
  • post 过滤器,在响应之前执行,可以做响应内容、响应头的修改、日志的输出、流量监控等。
  • Gateway 提供了两种类型的过滤器
    • GatewayFilter:局部过滤器,针对单个路由
    • GlobalFilter:全局过滤器,针对所有路由

1.局部过滤器

Spring Cloud Gateway 中提供了大量的内置过滤器组件(过滤器工厂)

只需要配置文件中配置局部过滤器名称,并指定对应的值,就可以让其生效。

这里简单将Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格。如下:

过滤器工厂 作用 参数
AddRequestHeader 为原始请求添加Header Header的名称及值
AddRequestParameter 为原始请求添加请求参数 参数名称及值
AddResponseHeader 为原始响应添加Header Header的名称及值
DedupeResponseHeader 剔除响应头中重复的值 需要去重的Header名称及去重策略
Hystrix 为路由引入Hystrix的断路器保护 HystrixCommand的名称
FallbackHeaders 为fallbackUri的请求头中添加具体的异常信息 Header的名称
PrefixPath 为原始请求路径添加前缀 前缀路径
PreserveHostHeader 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host
RequestRateLimiter 用于对请求限流,限流算法为令牌桶 keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo 将原始请求重定向到指定的URL http状态码及重定向的url
RemoveHopByHopHeadersFilter 为原始请求删除IETF组织规定的一系列Header 默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader 为原始请求删除某个Header Header名称
RemoveResponseHeader 为原始响应删除某个Header Header名称
RewritePath 重写原始的请求路径 原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader 重写原始响应中的某个Header Header名称,值的正则表达式,重写后的值
SaveSession 在转发请求之前,强制执行WebSession::save操作
secureHeaders 为原始响应添加一系列起安全作用的响应头 无,支持修改这些安全响应头的值
SetPath 修改原始的请求路径 修改后的路径
SetResponseHeader 修改原始响应中某个Header的值 Header名称,修改后的值
SetStatus 修改原始响应的状态码 HTTP 状态码,可以是数字,也可以是字符串
StripPrefix 用于截断原始请求的路径 使用数字表示要截断的路径的数量
Retry 针对不同的响应进行重试 retries、statuses、methods、series
RequestSize 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large 请求包大小,单位为字节,默认值为5M
ModifyRequestBody 在转发请求之前修改原始请求体内容 修改后的请求体内容
ModifyResponseBody 修改原始响应体的内容 修改后的响应体内容
Default 为所有路由添加过滤器 过滤器工厂名称及值

**Tips:**每个过滤器工厂都对应一个实现类,并且这些类的名称必须以GatewayFilterFactory结尾,这是Spring Cloud Gateway的一个约定,例如AddRequestHeader对应的实现类为AddRequestHeaderGatewayFilterFactory


配置

spring:
  application:
    name: api-gateway-server
  cloud:
    # 网关配置
    gateway:
      #路由配置:转发规则
      routes: #集合
        # id:唯一标识。默认是一个UUID
        # uri:转发路径
        # predicates:条件,用于请求网关路径的匹配规则
        # filters:配置局部过滤器
        - id: eureka-provider
          # 静态路由
          # uri: http://localhost:8001/
          # 动态路由
          uri: lb://EUREKA-PROVIDER
          predicates:
            - Path=/goods/**
          filters:
          	#添加请求参数,添加微服务名称配置时为null
            - addRequestParameter=username, zhangsan

2. 全局过滤器

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

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

自定义全局过滤器

  • 定义类实现GlobalFliter和Ordered接口
  • 复写方法
  • 完成逻辑处理
@Component
public class MyFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("自定义全局过滤器执行~~~~~~");
        //放行
        return chain.filter(exchange);
    }

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

你可能感兴趣的:(SpringCloud,spring,cloud,微服务,java)