微服务实战(三) OpenFegin 声明式服务调用

概述

  • Fegin是一个声明式的Http客户端,它使得写Http客户端变得更简单,使用Fegin只需要创建一个接口并注解,它具有可插拔的注解特性。
  • Nacos很好的兼容了Fegin,Fegin中也是默认集成了Ribbons实现负载均衡的效果,底层使用了HttpClient作为服务框架。

Feign+Nacos实现服务间调用

引入依赖
<!-- SpringCloud Ailibaba Nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- SpringCloud Ailibaba Nacos Config -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

<!-- feign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类添加注解

@EnableFeignClients启用feign客户端

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }
}
定义接口

@FeignClient 定义feign客户端

参数:

  • name 与value相同,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现。
  • url: url一般用于调试,可以手动指定@FeignClient调用的地址
  • fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
  • url: url一般用于调试,可以手动指定@FeignClient调用的地址
  • configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
  • fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
@FeignClient(value = "sunnyws-service-example1")
public interface Example1Client {
    
    @GetMapping("/test")
    void test();
}
调用
@Resource
private Example1Client example1Client;

@GetMapping("/test")
public void test(){
    log.info("开始调用example1服务的test方法!");
    long time1=System.currentTimeMillis();
    example1Client.test();
    long time2=System.currentTimeMillis();
    log.info("耗时:"+(time2-time1)+"ms");
    log.info("调用完成!");
}

Feign + Hystrix 服务的熔断 降级

  • 请求熔断:Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。
  • 服务降级 Fallback:当处理出现异常,或不具备处理能力时(负载过高、线程池用完),则会快速返回一个预先指定的值。
  • Fallback主要是用来解决依赖的服务不可用或者调用服务失败或超时,使用默认的返回值。
  • OpenFeign 中Fallback是通过Hystrix实现的, 所以需要开启Hystrix
  • 有服务熔断,必然要有服务降级。
  • 在网络请求时,可能会出现异常请求,如果还想再异常情况下使系统可用,那么就需要熔断,降级处理。

修改配置

  • feign.hystrix.enabled: true #开启Hystrix默认关闭
  • hystrix默认超时时间为1s
spring:
  application:
    name: sunnyws-service-example2
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: 172.16.220.10:8848
        namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
      config:
        server-addr: 172.16.220.10:8848
        file-extension: yml
        namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
feign:
  hystrix:
    enabled: true

hystrix:
  command:
    default: #配置服务降级全局超时时间
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 12000  #默认(1s)
        timeout:
          enabled: true #(默认true)开启超时熔断,为false将超时控制交给ribbon
      circuitBreaker:
        #10秒内,5次请求,失败率在50%,熔断8秒。
        requestVolumeThreshold: 5  #默认20 ,一个rolling window内最小的请求数。如果设为20, 10秒(Hystrix的滑动窗口算法)内发起了至少20次请求,失败率超过50%(errorThresholdPercentage),从熔断开启后,不在调用该远程服务
        sleepWindowInMilliseconds: 8000  #默认5S   休眠时长
        errorThresholdPercentage: 50 #触发熔断的失败请求最小占比,默认50%

定义Fallback实现类

实现Feign接口

@Slf4j
@Component
public class Example1ClientFallBack implements Example1Client {

    @Override
    public void test() {
        log.info("熔断方法被调用了!");
    }
}

Feign接口指定一个实现Feign接口的实现类

@FeignClient(value = "sunnyws-service-example1",fallback = Example1ClientFallBack.class)
public interface Example1Client {
    @GetMapping("/test")
    void test();
}

Feign + Ribbon 服务的负载均衡和重试

  • openfeign默认集成了ribbon,做下简单配置即可实现负载均衡
  • openfeign中ribbon默认负载算法为轮询
  • openfeign中ribbon默认重试机制为当前请求实例 重试1次

比较常用的负载均衡策略有:

随机 (Random)
轮询 (RoundRobin)
一致性哈希 (ConsistentHash)
哈希 (Hash)
加权(Weighted)

  • Ribbon 提供了 IRule 接口,通过其可以设置并更换负载均衡规则。
  • IRule 实质就是 根据某种负载均衡规则,从服务列表中选取一个需要访问的服务。
  • 一般默认使用 ZoneAvoidanceRule + RoundRobinRule。
#【IRule 子类如下:】
RoundRobinRule   
#轮询,按照服务列表顺序 循环选择服务。
    
RandomRule      
#随机,随机的从服务列表中选取服务。
    
RetryRule        
#重试,先按照轮询策略获取服务,若获取失败,则在指定时间进行重试,重新获取可用服务。
    
WeightedResponseTimeRule   
#加权响应时间,响应时间越低(即响应时间快),权重越高,越容易被选择。刚开始启动时,使用轮询策略。
    
BestAvailableRule          
#高可用,先过滤掉不可用服务(多次访问故障而处于断路器跳闸的服务),选择一个并发量最小的服务。

AvailabilityFilteringRule
#可用筛选,先过滤掉不可用服务 以及 并发量超过阈值的服务,对剩余服务按轮询策略访问。

ZoneAvoidanceRule
#区域回避,默认规则,综合判断服务所在区域的性能 以及 服务的可用性,过滤结果后采用轮询的方式选择结果。

基本使用

OpenFeign默认集成Ribbon,如果只是简单的使用,直接在配置文件中添加相应配置即可。

spring:
  application:
    name: sunnyws-service-example2
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: 172.16.220.10:8848
        namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
      config:
        server-addr: 172.16.220.10:8848
        file-extension: yml
        namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
feign:
  hystrix:
    enabled: true

ribbon:
  MaxAutoRetries: 0 #(默认1次 不包括第一次)最大重试次数,当注册中心中可以找到服务,但是服务连不上时将会重试,如果注册中心中找不到服务则直接走断路器
  MaxAutoRetriesNextServer: 2 #(默认0次 不包括第一次)切换实例的重试次数
  OkToRetryOnAllOperations: false  #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
  ConnectTimeout: 3000  #(默认1s)请求连接的超时时间
  ReadTimeout: 3000 #(默认1s)请求处理的超时时间

hystrix:
  command:
    default: #配置服务降级全局超时时间
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 12000  #默认(1s)
        timeout:
          enabled: true #(默认true)开启超时熔断,为false将超时控制交给ribbon
      circuitBreaker:
        #10秒内,5次请求,失败率在50%,熔断8秒。
        requestVolumeThreshold: 5  #默认20 ,一个rolling window内最小的请求数。如果设为20, 10秒(Hystrix的滑动窗口算法)内发起了至少20次请求,失败率超过50%(errorThresholdPercentage),从熔断开启后,不在调用该远程服务
        sleepWindowInMilliseconds: 8000  #默认5S   休眠时长
        errorThresholdPercentage: 50 #触发熔断的失败请求最小占比,默认50%

设置超时时间

hystrix

hystrix:
  command:
    default: #配置服务降级全局超时时间
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 12000  #默认(1s)
        timeout:
          enabled: true #(默认true)开启超时熔断,为false将超时控制交给ribbon

ribbon

ribbon:
  MaxAutoRetries: 0 #(默认1次 不包括第一次)最大重试次数,当注册中心中可以找到服务,但是服务连不上时将会重试,如果注册中心中找不到服务则直接走断路器
  MaxAutoRetriesNextServer: 1 #(默认0次 不包括第一次)切换实例的重试次数
  OkToRetryOnAllOperations: false  #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
  ConnectTimeout: 3000  #(默认1s)请求连接的超时时间
  ReadTimeout: 3000 #(默认1s)请求处理的超时时间
  • Hystrix与Ribbon的默认请求超时时间都是1秒
  • 在接口调用的时候,两个计时器会同时读秒。所以建议配置Hystrix的超时时间要大于ribbon的超时时间,ribbon重试超时后,再进行熔断处理。
  • OpenFeign默认开启Ribbon,开启Hystrix需要添加配置。当开启Hystrix,单独设置Hystrix的超时时间,可能会小于Ribbon的默认时间,会出现不确定的结果。
  • 当Hystrix超时时间 < Ribbon超时时间,程序会先回调进入到Hystrix的fallback方法,并继续执行下去。Ribbon会继续发送请求,直到请求完成,或达到重试次数,Ribbon的重试也就没有了意义。
  • Ribbon的重试次数不包括第一次请求,如果MaxAutoRetries=1MaxAutoRetriesNextServer=2,则最大请求次数为6((1+1)*(2+1))次,最大超时时间为(ConnectTimeout+ReadTimeout)*6

作者: SunnyWs