SpringCloud Feign整合Hystrix实现服务熔断服务降级彻底解耦
个人博客网:www.lfuping.cn (你想要这里多有)
Feign Hystrix整合&服务熔断服务降级彻底解耦
用@HystrixCommand fallbackMethod的方式不是很好,因为和业务代码耦合度太高,不利于维护,所以需要解耦,就Feign Hystrix整合。
一、springcloud-common项目:
添加FallbackClientFactory类
package com.li.springcloud.common.feign;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import com.li.springcloud.common.model.Student;
import feign.hystrix.FallbackFactory;
/**
* 解耦服务熔断服务降级
*
* @author Administrator
*
*/
@Component
public class FallbackClientFactory implements
FallbackFactory<FeignClientService> {
public FeignClientService create(Throwable cause) {
// TODO Auto-generated method stub
return new FeignClientService() {
public List<Student> listHystrix() {
List<Student> list = new ArrayList<Student>();
Student stu = new Student();
stu.setName("系统繁忙,请稍后重试....服务提供者------1");
stu.setId(500);
list.add(stu);
return list;
}
public List<Student> list() {
// TODO Auto-generated method stub
return null;
}
};
}
}
FeignClientService类:
package com.li.springcloud.common.feign;
import java.util.List;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import com.li.springcloud.common.model.Student;
/**
* Feign接口客户端
*
* @author Administrator
*
*/
@FeignClient(value = "PROVIDER",fallbackFactory=FallbackClientFactory.class)
public interface FeignClientService {
/**
* 查询用户信息
*
* @return
*/
@GetMapping(value = "/provider/list")
public List<Student> list();
/**
* Hystrix的方式
* @return
*/
@GetMapping(value="/provider/listHystrix")
public List<Student> listHystrix();
}
二、在服务生产者springcloud-provider-1,springcloud-provider-2添加如下方法:
StudentService:
/**
* 获取信息
* @return
*/
public List<Student> getInfo();
StudentServiceImpl:
@Override
public List<Student> getInfo() {
List<Student> list = new ArrayList<Student>();
Student stu = new Student();
//如果是第二个服务就写成 2, 测试时方便观察
stu.setName("业务数据xxxxxxxxxxxxxxxxx....服务提供者------1");
stu.setId(200);
list.add(stu);
return list;
}
ProviderController类:
package com.li.spingcloud.provider.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.li.spingcloud.provider.service.StudentService;
import com.li.springcloud.common.model.Student;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@RestController
public class ProviderController {
@Autowired
private StudentService studentService;
/**
* 查询
*
* @return
*/
@RequestMapping(value = "/provider/list", produces = "application/json; charset=utf-8", method = {
RequestMethod.POST, RequestMethod.GET })
public List<Student> list() {
System.out.println("ProviderController----我是生产者1");
return studentService.list();
}
/**
* 查询 Hystrix的方式
*
* @return
* @throws InterruptedException
*/
// 加上@HystrixCommand注解 以及 fallbackMethod
// 表明这个方法再没有异常以及没有超时(hystrix默认1秒算超时)的情况,才返回正常的业务数据;
//@HystrixCommand(fallbackMethod = "getInfoFallback")
@RequestMapping(value = "/provider/listHystrix", produces = "application/json; charset=utf-8", method = {
RequestMethod.POST, RequestMethod.GET })
public List<Student> listHystrix() throws InterruptedException {
//模拟调用延迟
Thread.sleep(1000);
System.out.println("ProviderController----我是生产者1");
// 模拟调用服务超时
// 然后采取 Hystrix进行服务降级,进而熔断该节点的服务调用,快速返回自定义的错误影响页面信息。
return studentService.getInfo();
}
}
三、springcloud-consumer-feign-1消费者项目:
修改配置如下:
server:
port: 8080
context-path: /
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:7001/eureka/
#集群模式 defaultZone: http://lifuping.eureka3.com:6001/eureka/,http://lifuping.eureka2.com:5001/eureka/,http://lifuping.eureka1.com:7001/eureka/
feign:
hystrix:
enabled: true
#hystrix超时时间配置 (如果不配置的话默认是1000毫秒超时)
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
修改ConsumerFeignApplication启动类:
package com.li.spingcloud.consumerfeign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class })
@EnableEurekaClient
@ComponentScan(basePackages = { "com.li.spingcloud.consumerfeign",
"com.li.springcloud.common.feign" })
@EnableFeignClients({ "com.li.springcloud.common.feign" })
public class ConsumerFeignApplication {
/**
* 程序启动
*
* @param args
*/
public static void main(String[] args) {
SpringApplication.run(ConsumerFeignApplication.class, args);
}
}
四、测试启动顺序:
- 先启动eureka单机或者集群;
- 在启动服务生产者集群;
- 启动消费者;
如果在启动消费者项目springcloud-consumer-feign-1报如下错误:
无法加载到 No fallbackFactory instance of type class com.li.springcloud.common.feign.FallbackClientFactory found for feign client PROVIDER;
要在FallbackClientFactory类加上@Component注解,并且在消费者项目加上
@ComponentScan(basePackages = { "com.li.spingcloud.consumerfeign",
"com.li.springcloud.common.feign" })
-
打开浏览器输入地址:http://localhost:8080/consumer/listHystrix
测试:返回正常信息;超过1秒的话,就返回错误提示;
之前在生产者项目配置Hystrix的超时时间配置就无效了;所以Hystrix默认还是1秒钟,要把这段配置写到springcloud-consumer-feign-1消费者项目;并且因为还有一个 feign 也有一个超时时间的设置,当然feign底层是ribbon的封装,所以直接配置ribbon,ribbon默认超时也是1秒。所以这里都是强制要求,ribbon的超时时间要大于hystrix的超时时间,否则 hystrix自定义的超时时间毫无意义。
完整配置:
server:
port: 8080
context-path: /
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:7001/eureka/
#集群模式 defaultZone: http://lifuping.eureka3.com:6001/eureka/,http://lifuping.eureka2.com:5001/eureka/,http://lifuping.eureka1.com:7001/eureka/
feign:
hystrix:
enabled: true
#hystrix超时时间配置 (如果不配置的话默认是1000毫秒超时)
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
ribbon:
ReadTimeout: 10000
ConnectTimeout: 9000
五、关于Ribbon核心组件之IRule
在springcloud-consumer-feign-1消费者项目的config包下SpringCloudConfig类:
/**
* 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,
然后选择一个并发量最小的服务
*
* @return
*/
@Bean
public IRule myRule() {
return new BestAvailableRule();
}
我测试用的BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。
它默认出厂自带了7种算法。
第一种是:RoundRobinRule 轮询
第二种是:RandomRule 随机
第三种是:AvailabilityFilteringRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,
还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问。
第四种是:WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换到WeightedResponseTimeRule。
第五种是:RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务。
第六种是:BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。
第七种是:ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器。
源码下载链接: https://pan.baidu.com/s/1KVaGrvv9p9rYacmS_KnXsA
提取码: tcv3
欢迎关注我的微信公众号:平川大叔