1.Feign介绍
1.1.什么是Feign
Feign是一个声明式的http客户端,使用Feign可以实现声明式REST调用,让WEB调用更加简单;
Feign整合了Ribbon和SpringMvc注解,这让Feign的客户端看起来像一个Controller;
Feign提供了HTTP请求模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息;
Feign会完全代理HTTP请求,我们只需要调用方法就可以完成服务请求及相关处理;
Feign整合了Hystrix,可以很容易的实现服务熔断和降级。
1.2.为什么要使用Feign
上篇文章我们说到使用Ribbon作为客户端使用负载均衡完成服务之间的通信;
我们使用RestTemplate调用其他服务时,需要的参数要在URL中进行拼接,如果参数过多,就会很麻烦;
Feign对Ribbon进行了封装,把一些url和参数处理细节屏蔽了起来,使用更方便。
2.使用
搭建Pay服务,注册到eureka
2.1.导入依赖
导入Feign的依赖jar包
<!--2.导入Feign的包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.2.编写配置类
主要是使用@EnableFeignClients注解
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class PayApp {
public static void main(String[] args) {
SpringApplication.run(PayApp.class,args);
}
}
2.3.yaml配置
#注册到EurekaServer
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1010/eureka/
instance:
instance-id: pay-server
spring:
application:
name: pay-server
server:
port: 1040
2.4.编写Feign客户端接口
创建一个客户端接口,加上@Feign注解,value值是服务名:
Feign可以根据服务名在注册中心找到目标服务的通信地址;
请求方式、路径、参数和返回值类型需要和被调用的接口一致。
@FeignClient(value = "user-server")
public interface UserClientFeign {
@GetMapping("/user/{id}")
User getUser(@PathVariable Long id);
}
2.5.编写Controller使用Feign接口
直接通过Feign接口调用方法
@RestController
@RequestMapping("/pay")
public class PayController {
@Autowired
private UserClientFeign userClientFeign;
@GetMapping("/{id}")
public User getPay(@PathVariable("id") Long id) {
User user = userClientFeign.getUser(id);
return user;
}
}
启动类上使用了@EnableFeignClient注解,会去扫描指定路径下的所有子包下使用了@FeignClient注解的类;
使用动态代理,生成代理类并将对象注入到IOC容器;
在代理方法中使用Http工具(RequestTemplate)生成request请求,交给Http客户端;
Http客户端会交给LoadBalanceClient,使用Ribbon的负载均衡发起调用。
3.Feign的参数配置
3.1.负载均衡配置
Feign已经集成了Ribbon,所以配置Ribbon的负载均衡即可;
通过@Bean方式或者xml方式:
@Bean
public RandomRule getRandomRule() {
return new RandomRule();
}
user-server:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
3.2.Feign的超时配置
在服务调用时出现"feign.RetryableException : Read timed out...”错误日志;
说明Ribbon处理超时,我们可以配置Ribbon的超时时间。
ribbon:
ConnectTimeout: 3000
ReadTimeout: 6000
4.Feign开启日志调试
NONE,不记录(DEFAULT)。
BASIC,仅记录请求方法和URL以及响应状态代码和执行时间。
HEADERS,记录基本信息以及请求和响应标头。
FULL,记录请求和响应的标题,正文和元数据。
向IOC容器注入Level对象
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL; //打印Feign的所有日志
}
上面配置的打印Feign的内容,下面是配置日志框架打印日志的级别。
logging:
level:
cn.liupeng: trace
5.Feign开启HZIP
开启Feign的数据压缩传输,这样可以节省网络开销;
但是压缩数据会增加CPU开销,所以太小的数据没必要压缩;
通过压缩大小阈值来控制,如下:
feign:
compression:
request:
enabled: true
min-request-size: 1024 #最小阈值,小于这个不压缩
mime-types: text/xml,application/xml,application/json #压缩哪些类型的数据
response:
enabled: true
开启之后在控制台就能看到以下结果:
6.了解Hystrix熔断器
6.1.雪崩效应
微服务中服务的调用非常复杂,一个请求往往需要很多的微服务共同完成,可能形成很长的调用链;
在整个调用链中,如果某一个服务发生故障会导致调用它的服务一起发生异常;
然后整个调用链异常,导致整个微服务架构瘫痪。
6.2.Hystrix作用
防止单个服务异常导致整个微服务异常;
快速失败,如果服务器出现故障,服务的请求快速失败,线程不会等待;
服务降级,请求故障可以返回设定好的备用方案(兜底数据);
熔断机制,防止故障的扩散,导致整个服务瘫痪;
服务监控,提供了Hystrix Bashboard仪表盘,实时监控熔断器状态。
资源隔离
线程池隔离:
使用一个线程池来存储当前请求,线程池对请求做处理,设置任务返回处理超时时间,堆积的请求先入线程池队列。
新线程、异步、线程调度和切换开销、支持并发。
信号量隔离:
使用一个原子计数器(或信号量)记录当前有多少个线程在运行,请求来先判断计数器的数值;
若超过设置的最大线程个数则丢弃该类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。
原线程、同步、无线程切换开销、支持并发。
6.3.OpenFeign使用Hystrix
6.3.1.导入依赖
OpenFeign上面已经导入过了
6.3.2.yaml配置
开启熔断支持
feign:
hystrix:
enabled: true #开启熔断支持
6.3.3.Feign接口熔断
指定托底数据有两种方式:
fallback和fallbackFactory
6.3.3.1.fallback方式
创建一个类实现Feign接口,重写接口方法,返回托底数据;(交给Spring管理)
6.3.3.2.fallbackFactory方式
Feign接口
@FeignClient(value = "user-server",fallbackFactory = UserClientFallBackFactory.class)
public interface UserClientFeign {
@GetMapping("/user/{id}")
User getUser(@PathVariable Long id);
}
Feign实现类
@Component
public class UserClientFallBackFactory implements FallbackFactory<UserClientFeign> {
@Override
public UserClientFeign create(Throwable throwable) {
return new UserClientFeign() {
@Override
public User getUser(Long id) {
throwable.printStackTrace();
return new User(-1l,"出毛病啦!!",65536L);
}
};
}
}