一、回顾
上一期我博客主要写了RestTemplate结合Hystrix实现降级、超时、限流、熔断的操作。
《SpringCloud深入学习(五)——Hystrix的简介以及降级、限流、超时、熔断机制》
其中针对Feign和Hystrix的结合使用,只简单说明了下失败请求fallback函数的使用问题,针对其他如降级、超时、限流、熔断等暂未作详细的说明。
(本来是准备写在一篇博客中的,只是那一篇博客内容过多,想了下还是分出来比较好)。
所以这一节专门做详细说明吧。
二、feign的大致讲解
我们上一篇博客中,说明了下如何去配置Hystrix,做请求出问题时,fallback函数的触发,如下列代码所示:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value="app-bunana-product",fallback=FallbackHystrix.class)
public interface ConsumerFeignClient {
@RequestMapping("/product/getProduct")
public String getTest1ByFeign(@RequestParam("name") String name);
}
以及使用到的fallback函数类:
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import cn.linkpower.feignService.ConsumerFeignClient;
@Component
public class FallbackHystrix implements ConsumerFeignClient {
@Override
public String getTest1ByFeign(String name) {
return "服务错误,请联系开发者";
}
}
[问1:]为什么直接再Feign,也就是在@FeignClient中定义fallback引入FallbackHystrix.class 就能实现呢?
我们可以看下Feign的引入依赖文件信息:
在Feign中,本身就默认引入了Hystrix。
SpringCloud默认已为Feign整合了Hystrix,只要Hystrix在项目的classpath中, Feign默认就会用断路器包裹所有方法
[问2:]为什么Feign整合Hystrix时,我们需要在配置文件中开启Hystrix?但为什么有些时候我没看见有配置也能用,有时候又不行?
从Spring Cloud Dalston开始,Feign默认是不开启Hystrix的。因此,如使用 Dalston及以上版本请务必额外设置属性:feign.hystrix.enabled=true,否则断路器不会 生效。
三、Feign实现部分接口不降级
我们上面已经阐述了,在D版本及以上默认不开启Hystrix实现降级操作,当我们需要采取Hystrix实现降级操作时,我们则需要增加一个全局的配置。
feign.hystrix.enabled=true
但是并非每一个接口都需要降级。
[问1:]为什么说不是每一个接口都需要降级?
当我们配置了降级操作时,
Hystrix会默认配置超时时间为1秒;
默认分配5000ms内达到错误次数20次触发熔断;
默认创建10个线程的线程池大小,实现限流。
如果此时我们的项目中,Feign接口很多,默认10个线程(未使用时,会默认存活一个线程),这样我们服务器的资源占用依旧还是很大的。
所以并不是所有的接口我们都需要采取Hystrix实现保护操作,但Feign开启全局后,使用Feign就会自带Hystrix。
[问2:]既然使用Feign会自带Hystrix,我们要使用Hystrix就必须开启Feign支持Hystrix。但我们如何设置某些接口不适用Hystrix呢?
此时我们只需要新增一个配置类,在指定的不使用Hystrix的接口上,增加其配置调用即可。
[问3:]那怎么做呢?
- 配置全局使用Hystrix。
##feign中使用断路器,默认是没有开启的,需要在配置文件中开启
feign:
hystrix:
enabled: true
- 增加配置类(与启动类不在一个层级下)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import feign.Feign;
/**
* 在不需要使用Feign中Hystrix的接口上增加其注解
* @author 7651
*
*/
@Configuration
public class NoFeignHystrixConfig {
@Bean
@Scope("prototype")
public Feign.Builder getFeignBuiler(){
//feignBuilder方法默认返回HystrixFeign.Builder也就是说Feign默认支持Hystrix
//现在改成Feign.Builder就禁用了Hystrix的支持
return Feign.builder();
}
}
- 将上述配置的类,增加至指定的Feign的接口方法上
我们如何测试呢?
我们可以制定两个Feign接口,一个进行Hystrix降级操作,一个屏蔽降级操作,分别请求测试即可。
正常测试:
http://localhost:10001/test2?name=1
异常测试:
http://localhost:10001/test1?name=1
[注意:]
- 如果出现org.springframework.beans.factory.support.BeanDefinitionOverrideException 报错,一定要记得 查看@FeignClient注解中value 属性是否重名!
参见文章:《Feign报错’xx.FeignClientSpecification’, defined in null, could not be registered》中的
- NoFeignHystrixConfig.class 的配置文件必须放在启动类路径之外,不然就是全局配置!
四、Feign实现Hystrx的降级配置
由于在Feign中默认引入了Hystrix,所以我们的依赖文件中,并不需要对Hystrix做额外的引入。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<!-- 管理依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.M7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot整合eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 加入feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
然后针对具体的接口请求中,我们需要采取Feign接口的方式调用,调用的规则:
Feign接口的传递参数类型,参数个数与使用的接口保持一致!
所以我们编写Feign接口的方式:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value="app-bunana-product",fallback=ConsumerFallbackHystrix.class)
public interface ConsumerFeignClient {
// @RequestParam("name")的作用在于使用该接口,可以将前接口传递的数据映射至新接口上
@RequestMapping("/product/getProduct")
public String getTest1ByFeign(@RequestParam("name") String name);
}
@Component
class ConsumerFallbackHystrix implements ConsumerFeignClient {
@Override
public String getTest1ByFeign(String name) {
return "服务错误,请联系开发者";
}
}
启动Eureka注册中心和Consumer-eureka-feign-hystrix-10001服务。进行接口的请求测试:(详细demo会在文章末尾处展示github下载连接)
五、Feign整合Hystrix实现超时降级配置
上一篇博客中,我们说到Hystrix默认的超时时间为1秒,如果超过默认的请求回应时间,就会触发降级操作。
我们这次设置Consumer的超时时间规则为 2000ms;
hystrix:
command:
default:
execution: ## 超时配置
isolation:
thread:
timeoutInMilliseconds: 2000 #设置请求超时时间,默认1秒,超过指定的时间后,触发降级
同时,我们也给定Product的超时代码
@RestController
@RequestMapping("/product")
public class TestController {
private static Logger log = LoggerFactory.getLogger(TestController.class);
@Value("${server.port}")
private String port;
@RequestMapping("/getProduct")
public String getTest1(String name) throws InterruptedException{
int timeout = new Random().nextInt(3000);
log.info("此时的超时时间--->{}",String.valueOf(timeout));
Thread.sleep(timeout);
return "this is product project getProduct name = "+String.valueOf(name)+",port="+port;
}
}
启动两者服务并注册至eureka注册中心上,请求接口进行访问测试:
http://localhost:10001/test2?name=1
当请求响应时间低于 2000ms时,不会出现降级操作。
当请求响应时间超过 2000ms时,触发降级操作。
[注意:]这里有个坑!
feign底层是 ribbon的封装,所以 直接配置ribbon,ribbon默认超时也是1秒。如果要测试Hystrix,必须要求ribbon的超时时间要大于hystrix的超时时间!
《springcloud(七) feign + Hystrix 整合 》
我的没有配置,能正常测试,若以后出现这种问题,再看此处!
六、Feign整合Hystrix实现熔断配置
相比上一篇博客,我们只需要当请求为 name="1"时,触发熔断操作即可!
先配置Consumer中,熔断的相关参数信息:
#hystrix相关配置
hystrix:
command:
default:
execution: ## 超时配置
isolation:
thread:
timeoutInMilliseconds: 20000 #设置请求超时时间,默认1秒,超过指定的时间后,触发降级
circuitBreaker: ##熔断配置
requestVolumeThreshold: 3 #达到指定的次数后熔断服务 (默认20次)
sleepWindowInMilliseconds: 10000 #熔断后,多长时间进行恢复(默认 5000)
我们再定义Product服务中,出现问题的逻辑:
if("1".equalsIgnoreCase(name)){
throw new NullPointerException();
}
分别启动项目,注册至注册中心中,请求测试:
需要达到的效果:10s内,连续3次错误,触发熔断,隔离后面的请求;
隔离10s后半开释放。
github代码下载
《feign动态配置某些接口带Hystrix,某些接口不带Hystrix》
《Feign整合Hystrix实现熔断配置》