Feign简介
什么是Feign
Feign是spring cloud netflix
组件中的一个轻量级RESTful
的HTTP服务客户端,实现了负载均衡和Rest调用的开源框架,封装了Ribbon和RestTemplate
,实现了面向接口编程。
Feign内置了Ribbon,用来做客户端的负载均衡调用服务注册中心的服务。Feign本身并不支持Spring MVC
注解,为了方便使用,spring cloud孵化了OpenFeign
,OpenFeign
支持spring mvc
注解
Feign的使用方式,使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。
Feign是声明式服务调用组件,其核心就是,像调用本地方法一样调用远程方法,无感知远程HTTP请求。
Feign入门案例
Feign的使用主要分为以下几个步骤
- 服务消费者添加Feign依赖
- 创建业务层接口,添加
@FeignClient
注解声明需要调用的服务 - 业务层抽象方法使用
SpringMVC
注解配置服务地址和参数 - 启动类添加
@EnableFeignClients
注解激活Feign组件
添加依赖
<!-- 添加Feign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
创建业务层接口
@FeignClient("user")
public interface UserFeign {
@GetMapping("/api/user/{userId}")
String getUser(@PathVariable("userId") String userId);
}
@Service
public class ManagerService {
@Autowired
UserFeign userFeign;
/**Get请求*/
@GetMapping("/api/user/{userId}")
String getUser(@PathVariable("userId") String userId);
/**
* Post请求 需要@RequestBody注解声明参数
*/
@PostMapping("/api/user/save")
User saveUser(@RequestBody User user);
}
@RestController
@RequestMapping("/api/manager")
public class OrderController {
@Autowired
ManagerService managerService;
@GetMapping("/{userId}")
public String getUser(@PathVariable("userId") String userId){
return managerService.getManager(userId);
}
@GetMapping("/saveUser")
public String saveUser(){
return managerService.saveUser();
}
}
启动类添加@EnableFeignClients
注解
@SpringBootApplication
@EnableFeignClients
public class ManagerWebApplication {
public static void main(String[] args) {
SpringApplication.run(ManagerWebApplication.class);
}
}
注:服务端返回值不要用接口 IPage
,https://my.oschina.net/u/3873927/blog/3094200
Feign负载均衡
Feign封装了Ribbon自然也就集成了负载均衡功能,默认采用轮询策略,下面看下如何修改负载均衡策略。
全局配置
在配置类中声明负载均衡策略对象,所有服务请求都使用该策略
@Bean
public RandomRule randommRule(){
return new RandomRule();
}
Feign性能优化
Gzip
压缩
gzip
是一种数据结构,采用deflate算法压缩数据;应用十分广泛,尤其是在linux
平台,当使用Gzip
压缩一个纯文本文件时,效果是非常明显的,大约可以减少70%以上的文件大小。
网络数据经过Gzip
压缩后降低了网络传输的字节数,加快网页加载的速度。
Gzip
压缩配置
局部:只配置Consumer通过Feign到Provider的请求使用Gzip压缩
服务消费者application.yml
feign:
compression:
request:
mime-type: text/xml,application/xml;application/json # 配置压缩支持的Mime type
min-request-size: 512 # 配置压缩数据大小的最小阈值。默认2048
enable: true # 请求是否开启Gzip压缩
response:
enable: true # 响应是否开启Gzip压缩
全局:对客户端浏览器的请求以及Consumer到Provider的请求都使用Gzip
压缩
server:
port: 8082
compression:
enabled: true # 是否开启Gzip压缩
mime-type: application/json,application/xml,text/html,text/xml,text/plain # 配置压缩支持的Mime type
min-response-size: 1 #默认就是2048 byte
HTTP连接池
采用HTTP连接池,可以节约大量的3次握手四次挥手,这样能大大提升吞吐量。
Feign的HTTP客户端支持3中框架:HttpURLConnection
、HttpClient
、OkHttp
;默认是HttpURLConnection
.
传统的HttpURLConnection
是JDK
自带的,并不支持连接池,如果要实现连接池机制,可以使用HttpClient
,它封装了访问HTTP的请求头、参数、内容体、响应等;它不仅使客户端发送HTTP请求变得容易,而且也方便了开发人员测试接口;当高并发的请求网络时候,也可以用连接池提升吞吐量。
添加依赖
<!-- 连接池-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
配置文件
feign:
httpclient:
enabled: true # 开启httpClient
如果使用HttpClient
作为Feign的客户端工具,我们可以通过GET请求传递对象参数。
Feign请求超时处理
Feign的负载均衡底层使用的就是Ribbon,所以这里请求超时配置的就是Ribbon
分布式项目中,服务压力比较大的情况下,可能处理服务的过程需要花费一定的时间,而默认情况下请求超时的配置是1s
,所以我们需要调整该配置延长请求超时时间。
例如下面报的错就是请求超时,
2021-06-23 20:20:54.276 INFO 16032 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty : Flipping property: user.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2021-06-23 20:20:54.412 ERROR 16032 --- [io-8082-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.RetryableException: Read timed out executing POST http://user/api/user/save] with root cause
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method) ~[na:1.8.0_60]
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) ~[na:1.8.0_60]
at java.net.SocketInputStream.read(SocketInputStream.java:170) ~[na:1.8.0_60]
全局配置
consumer项目中配置请求超时的处理
ribbon:
ConnectTimeout: 5000 #请求连接的超时时间,默认为1s
ReadTimeout: 5000 #请求处理的超时时间
单微服务局部配置
一般我们会根据服务的压力大小配置不同的服务超时处理,使用局部配置
# 需要调用的服务名称
user:
ribbon:
ConnectTimeout: 5000 # 请求连接的超时时间,默认为1s
ReadTimeout: 5000 # 请求处理的超时时间
OkToRetryOnAllOperations: true # 对所有的请求都进行重试
MaxAutoRetries: 2 # 对当前实例重试次数
MaxAutoRetriesNextServer: 0 # 切换实例的重试次数