1.概念
Feign是Spring Cloud Netflix组件中的一个轻量级RESTful的HTTP服务客户端,实现了负载均衡和Rest调用的开源框架
封装了Ribbon和RestTemplate,实现了WebService的面向接口编程,进一步降低了项目的耦合度。
Feign内置了Ribbon,用来做客户端负载均衡调用服务注册中心的服务。
Felgn本身并不支持Spring MVC的注解,它有一会自己的注解,为了更方便的使用,Spring Cloud孵化了openFelgn。
Feign是一种声明式、模板化的HTTP客户端(仅在Consumer中使用)。
Feign支持的注解和用法请参考官方文档: htps://github.com/OpenFeign/feign 或spring.io言网文档
Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。
Feign旨在使编写JAVA HTTP客户端变得更加容易,Feign 简化了RestTemplate代码,实现了Ribbon负载均衡
使代码变得更加简洁,也少了客户端调用的代码,使用Feign实现负载均衡是首选方案。
只需要你创建一个接口,然后在上面添加注解即可。
Feign是声明式服务调用组件,其核心就是:像调用本地方法一样调用远程方法,无感知远程HTTP请求。
- 它解决了让开发者调用远程接口就跟调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。无需关注与远程的交互细节,更无需关注分布式环境开发。
- 它像Dubbo-样, Consumer直接调用Provider接口方法,而不需要通过常规的Http Client构造请求再解析返回数据。
OpenFeign是Spring Cloud在Feign的基础上支持了Spring MVC的注解,如@RequesMapping 、Pathvariable 等等。
OpenFeign的@FeignClient 可以解析SpringMVC的@RequestMapping 注解下的接口,并通过动态代理的方式产“生实现
类,实现类中做负载均衡并调用服务。 - 读作 fei en
2.实现
- 服务中心和提供者一致
- pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
- 生产者中的ProductService
@FeignClient("provider")
public interface ProductService {
@GetMapping("/product/list")
List<Product> listProducts();
}
3.Feign负载均衡
Feign封装了Ribbon自然也就集成了负载均衡的功能,默认采用轮询策略。如何修改负载均衡策略呢?与之前学习Ribbon时讲解的配置是一致的。
4.参数请求
- 消费者的ProductSercice
@FeignClient("provider")
public interface ProductService {
@GetMapping("/product/{id}")
Product selectProductById(@PathVariable("id") Integer id);
@PostMapping("/product/save")
Map<Object, Object> createProduct(Product product);
}
- 生产者的ProductController
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/{id}")
public Product selectProduct(@PathVariable("id") Integer id){
return productService.selectProductById(id);
}
@PostMapping("/save")
public Map<Object, Object> createProduct(@RequestBody Product product){
return productService.createProduct(product);
}
}
5.Feign性能优化
5.1 Gzip压缩
gzip介绍: gzip 是-种数据格式,采用deflate 算法压缩数据; gzip 是-种流行的文件压缩算法,应用十分广泛,尤其是在Linux平台。
gzip能力:当Gzip压缩一个纯文本文件时,效果是非常明显的,大约可以减少70%以上的文件大小。
gzip作用:网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。
网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是Gzip与搜索引擎的抓取工具有着更好的关系。
例如Google就可以通过直接读取gzip文件来比普通手工抓取更快地检索网页。
5.1.1 HTTP协议关于压缩传输的规定
1.客户端向服务器请求中带有: Accept-Encoding:gzip ,deflate 字段,向服务器春示賽户端支持的压缩格式(gzip 或
者deflate),如果不发送该消息头,服务端默认是不会压缩的。
2.服务端在收到请求之后,如果发现请求头中含有Accept-Encoding 字段,并且支持该类型压缩,就会对响应报文压缩之
后返回给客户端,并且携芾Content- Encoding:gzip消息头,表示响应报文是根据该格式进行压缩的。
3.客户端接收到请求之后,先判断是否有Content-Encoding 消息头,如果有,按该格式解压报文。否则按正常报文处理。
5.1.2 实现
- 局部
只配置Consumer通过Feign到Provider的请求与相应的Gzip压缩。服务消费者application.yml
server:
port: 9090
compression:
#开启压缩
enabled: true
#压缩支持的 MINME TYPE
mime-types: application/json,application/xml,text/html,text/xml,text/plain
- 全局
对客户端浏览器的请求以及Consumer对Provider的请求与响应都实现Gzip压缩。
服务消费者applicationyml
feign:
compression:
request:
mime-types: text/xml. application/xn1. application/json #配置压缩支持的MIME TYPE
min-request-size: 512 #配置压缩数据大小的最小阈值,默认2048
enabled: true #请求是否开启gzip压缩
response:
enabled: true #响应是否开启gzip压缩
5.2 HTTP连接池
5.2.1HTTP的背景原理
- 两台服务器建立HTTP连接的过程是很复杂的一个过程,涉及到多个数据包的交换,很耗时间。
- HTTP连接需要的3次握手4次挥手开销很大,这一 开销对于大量的比较小的HTTP消息来说更大。
5.2.2 解决方案
采用HTTP连接池,可以节约大量的3次握手4次挥手,这样能大大提升吞吐量。
Feign的HTTP客户端支持3种框架: HttpURLConnection,HttpClient,OkHttp;默认是HttpURLConnection 。
- 传统的HttpURLConnection是JDK自带的,并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。
对于网络请求这种底层相对复杂的操作,如果有可用的其他方案,没有必要自己去管理连接对象。 - HttpClient 相比传统JDK自带的HttpURLConnection,它封装了访问HTTP的请求头,参数,内容体,响应等等
它不仅使客户端发送HTTP请求变得容易,而且也方便了开发人员测试接口(基于HTTP协议的) , 既提高了开发的效率,又提高了代码的健壮性;
另外高并发大量的请求网络的时候,也是用连接池提升吞吐量。
5.2.3 实现
#httpclient开启
feign:
httpclient:
enabled: true
5.3 状态查看
浏览器发起的请求我们可以借助F12 Devtools 中的Network来查看请求和响应信息。
对于微服务中每个接口我们又该如何查看URL,状态码和耗时信息?我们可以使用配置日志的方式进行查看。
5.3.1 实现
- logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="/home" />
<!--控制台日志, 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--文件日志, 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- show parameters for hibernate sql 专为 Hibernate 定制 -->
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
<logger name="org.hibernate.SQL" level="DEBUG" />
<logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
<logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />
<!--myibatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别 -->
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE"/>
</root>
</configuration>
- 启动类加入
/**
* NONE: 不记录任何信息
* BASIC 记录请求方法,URL,状态码,用时
* HEADERS BASIC基础上记录一些常用信息
* FULL 记录请求相关所有信息
* @return
*/
@Bean
public Logger.Level getLog(){
return Logger.Level.FULL;
}
- application.yml
#httpclient开启
feign:
httpclient:
enabled: true
client:
#服务名称
provider:
loggerLevel: FULL
5.4 请求超时
Feign的负载均衡底层用的就是Ribbon,所以这里的请求超时配置其实就是配置Ribbon.
分布式项目中,服务压力比较大的情况下,可能处理服务的过程需要花费一定的时间, 而默认情况下请求超时的配置是1s所以我们需要调整该配置延长请求超时时间。
5.4.1 实现
- 局部
provider:
ribbon:
NFLoadBalanceRuleClassName: com.netflix.loadbalancer.RandomRule
#所有请求都进行重试
OkToRetryOnAllOperations: true
#对当前实例重试次数
MaxAutoRetries: 2
#切换实例的重试次数
MaxAutoRetriesNextServer: 0
#请求连接的超时时间
ConnectTimeout: 3000
#请求处理的超时时间
ReadTimeout: 3000
- 全局
ribbon:
#请求连接超时时间
ConnectTimeout: 5000
#请求处理的超时时间
ReadTimeout: 5000
标签:Feign,HTTP,请求,压缩,gzip,客户端
From: https://www.cnblogs.com/lwx11111/p/17494451.html