简单理解Feign的原理与使用

本文涉及的产品
应用型负载均衡 ALB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
日志服务 SLS,月写入数据量 50GB 1个月
简介: 简单理解Feign的原理与使用

SpringCloud 总架构图

Spring Cloud 常见的集成方式是使用Feign+Ribbon技术来完成服务间远程调用及负载均衡的,如下图

  1. 在微服务启动时,会向服务发现中心上报自身实例信息,这里ServiceB 包含多个实例。 每个实例包括:IP地址、端口号信息。
  2. 微服务会定期从Nacos Server(服务发现中心)获取服务实例列表。
  3. 当ServiceA调用ServiceB时,ribbon组件从本地服务实例列表中查找ServiceB的实例,如获取了多个实例如:Instance1、Instance2。这时ribbon会通过用户所配置的负载均衡策略从中选择一个实例。
  4. 最终,Feign组件会通过ribbon选取的实例发送http请求。

采用Feign+Ribbon的整合方式,是由Feign完成远程调用的整个流程。而Feign集成了Ribbon,Feign使用Ribbon

完成调用实例的负载均衡。

一、简介

1.1、负载均衡的概念

在SpringCloud服务协议流程中,ServiceA通过负载均衡调用ServiceB,下边来了解一下负载均衡

负载均衡就是将用户请求(流量)通过一定的策略,分摊在多个服务实例上执行,它是系统处理高并发、缓解网络

压力和进行服务端扩容的重要手段之一。它分为服务端负载均衡客户端负载均衡

服务器端负载均衡:

客户端负载均衡:

2.2、Feign概念

Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,是以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。

Feign被广泛应用在Spring Cloud 的解决方案中,是学习基于Spring Cloud 微服务架构不可或缺的重要组件。

**封装了Http调用流程,更符合面向接口化的编程习惯。**类似Dubbo服务调用。

项目主页:https://github.com/OpenFeign/feign

二、入门案例

使用Feign替代RestTemplate发送Rest请求。使之更符合面向接口化的编程习惯。

实现步骤:

  1. 导入feign依赖starter
  2. 编写Feign客户端接口
  3. 消费者启动引导类开启Feign功能注解
  4. 访问接口测试

实现过程:

2.1、导入依赖

  • 在consumer-service中添加spring-cloud-starter-openfeign依赖
<!--配置feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.2、Feign的客户端

  • 在consumer-service中编写Feign客户端接口类ConsumerService
@FeignClient(value = "provider-service")
public interface ConsumerService {
    //String url = String.format("http://provider-service/user/findUserById/%s",id);
    @RequestMapping("/user/findUserById/{id}")
    User findUserById(@PathVariable("id") Integer id);
}
  • Feign会通过动态代理,帮我们生成实现类。
  • 注解@FeignClient声明Feign的客户端,指明服务名称
  • 接口定义的方法,采用SpringMVC的注解。Feign会根据注解帮我们生成URL地址

2.3、调用Feign

  • 编写ConsumerFeignController,使用ConsumerService访问
  • @Autowired注入ConsumerService
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
    @Autowired
    private ConsumerService consumerService;
    @GetMapping("/findUserById/{id}")
    public User findUserById(@PathVariable Integer id){
        return consumerService.findUserById(id);
    }
}

2.4、开启Feign功能

  • 在ConsumerApplication启动类上,添加@EnableFeignClients注解,开启Feign功能
@SpringBootApplication
@EnableFeignClients  //开启feign
@EnableDiscoveryClient
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

2.5、启动测试

访问接口http://localhost:8081/consumer/findUserById/1,正常获取结果:

2.6、Feign实现原理简单分析

Feign帮我们做了哪些事儿:

  • 在 声明Feign客户端 之后,Feign会根据@FeignClient注解使用java的动态代理技术生成代理类,在这里我们指定@FeignClient value为serviceB,则说明这个类的远程目标为spring cloud的服务名称为serviceB的微服务。
  • serviceB的具体访问地址,Feign会交由ribbon获取,若该服务有多个实例地址,ribbon会采用指定的负载均衡策略选取实例。
  • Feign兼容spring的web注解(如:@GetMapping),它会分析声明Feign客户端方法中的Spring注解,得出Http请求method、参数信息以及返回信息结构。
  • 当业务调用Feign客户端方法时,会调用代理类,根据以上分析结果,由代理类完成实际的参数封装、远程http请求,返回结果封装等操作。

三、负载均衡(Ribbon)

Feign本身集成了Ribbon,因此不需要额外引入依赖。

Ribbon是一个客户端负载均衡器,它的责任是从一组实例列表中挑选合适的实例,如何挑选?取决于负载均衡策

Ribbon核心组件IRule是负载均衡策略接口,它有如下实现,大家仅做了解:

  • RoundRobinRule(默认):轮询,即按一定的顺序轮换获取实例的地址。
  • RandomRule:随机,即以随机的方式获取实例的地址。
  • AvailabilityFilteringRule: 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,以及并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问;
  • WeightedResponseTimeRule: 根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越大,被选中的机率越高; 刚启动时,如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够时,会切换到WeightedResponseTimeRule
  • RetryRule: 先按照RoundRobinRule的策略获取服务,如果获取服务失败,则在指定时间内会进行重试,获取可用的服务;
  • BestAvailableRule: 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;
  • ZoneAvoidanceRule: 默认规则,复合判断server所在区域的性能和server的可用性选择服务器;

可通过下面方式在spring boot 配置文件中修改默认的负载均衡策略:

account‐service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

account-service 是调用的服务的名称,后面的组成部分是固定的。

四、熔断器支持

Feign本身也集成Hystrix熔断器,starter内查看。

服务降级方法实现步骤:

  1. 在配置文件application.yml中开启feign熔断器支持
  2. 编写FallBack处理类,实现FeignClient客户端
  3. 在@FeignClient注解中,指定FallBack处理类。
  4. 测试服务降级效果

实现过程:

  1. 在配置文件application.yml中开启feign熔断器支持:默认关闭
feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能
  1. 定义一个类ConsumerServiceImpl,实现刚才编写的ConsumerService,作为FallBack的处理类
@Component
public class ConsumerServiceImpl implements ConsumerService {
    //熔断方法
    @Override
    public User findUserById(Integer id) {
        User user = new User();
        user.setId(id);
        user.setNote("网络异常,请稍后再试...");
        return user;
    }
}
  1. 在@FeignClient注解中,指定FallBack处理类。。
@FeignClient(value = "provider-service",fallback = ConsumerServiceImpl.class)
public interface ConsumerService {
    //String url = String.format("http://provider-service/user/findUserById/%s",id);
    @RequestMapping("/user/findUserById/{id}")
    User findUserById(@PathVariable("id") Integer id);
}
  1. 重启测试:关闭provider-service服务,然后在页面访问;http://localhost:8081/consumer/findUserById/1

五、请求压缩和响应压缩

SpringCloudFeign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。

通过配置开启请求与响应的压缩功能:

feign:
  compression:
        request:
            enabled: true # 开启请求压缩
        response:
            enabled: true # 开启响应压缩

也可以对请求的数据类型,以及触发压缩的大小下限进行设置

#  Feign配置
feign:
  compression:
    request:
      enabled: true # 开启请求压缩
      mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
      min-request-size: 2048 # 设置触发压缩的大小下限
      #以上数据类型,压缩大小下限均为默认值

六、配置日志级别

在发送和接收请求的时候,Feign定义了日志的输出定义了四个等级:这里我们配置测试一下。

级别 说明
NONE 不做任何记录
BASIC 只记录输出Http 方法名称、请求URL、返回状态码和执行时间
HEADERS 记录输出Http 方法名称、请求URL、返回状态码和执行时间 和 Header 信息
FULL 记录Request 和Response的Header,Body和一些请求元数据

实现步骤:

  1. 在application.yml配置文件中开启日志级别配置
  2. 编写配置类,定义日志级别bean。
  3. 在接口的@FeignClient中指定配置类
  4. 重启项目,测试访问

实现过程:

  1. 在consumer-service的配置文件中设置com.itheima包下的日志级别都为debug
# com.itheima 包下的日志级别都为Debug
logging:
  level:
    com.itheima: debug
  1. 在consumer-service编写配置类,定义日志级别
@Configuration
public class FeignLogLevleConfig {
    //采用full打印日志
    @Bean
    public Logger.Level configLog(){
        return Logger.Level.FULL;
    }
}
  1. 在consumer-service的ConsumerService中指定配置类
@FeignClient(value = "provider-service",
        fallback = ConsumerServiceImpl.class,
        configuration = FeignLogLevleConfig.class)
public interface ConsumerService {
    @RequestMapping("/user/findUserById/{id}")
    User findUserById(@PathVariable("id") Integer id);
}
  1. 重启项目,即可看到每次访问的日志
相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
SpringCloud极简入门-Feign开启Hystrix
1.支付服务集成Hystrix 官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/single/spring-cloud.html#spring-cloud-feign-hystrix 支付服务 springcloud-pay-server-1040 之前集成了Feign,修改该工程集成Hystrix。我们除了要给Feign开启Hystrix以外还需要为Feign接口编写托底类。
191 0
|
设计模式 负载均衡 Nacos
远程调用 OpenFeign 底层原理解析
Feign 是Springcloud 提供一个声明式的伪Http客户端 它使得调用远程服务就像调用本地服务一样简单 只需要创建一个接口 并且添加注解就可以 Nacos 很好的兼容Feign Feign 默认集成了Ribbon 所以在Nacos 下使用Fegin 默认就实现了负载均衡的效果
1772 0
远程调用 OpenFeign 底层原理解析
|
5月前
Feign使用原理
Feign使用原理
131 0
|
7月前
|
负载均衡 Java 应用服务中间件
Ribbon、Feign和OpenFeign的区别来了
Ribbon、Feign和OpenFeign的区别来了
313 2
|
7月前
|
JSON Java 关系型数据库
【Feign】 基于 Feign 远程调用、 自定义配置、性能优化、实现 Feign 最佳实践
【Feign】 基于 Feign 远程调用、 自定义配置、性能优化、实现 Feign 最佳实践
283 0
|
7月前
|
负载均衡 前端开发 Java
openfeign远程调用的底层原理?
openfeign远程调用的底层原理?
|
设计模式 缓存 Dubbo
|
消息中间件 JavaScript 小程序
Spring 6 正式“抛弃”feign
Spring 6 正式“抛弃”feign
|
JSON 负载均衡 算法
9、Eureka、Feign、Ribbon的工作原理及项目实战
在前后端分离架构中,服务层被拆分成了很多的微服务,Spring Cloud中提供服务注册中心来管理微服务信息
190 0
9、Eureka、Feign、Ribbon的工作原理及项目实战
|
负载均衡 前端开发 网络协议
feign的使用及原理
feign的使用及原理
1080 0
feign的使用及原理