Spring Cloud完整组件搭建之路 第三篇 -OpenFeign、Hystrix整合
书接上回【Spring Cloud完整组件搭建之路 第二篇 -OpenFeign、Ribbon整合】,OpenFeignn和Ribbon的整合我们已经配置完了,这次来整合OpenFeignn和Hystrix。
SpringCloud配置系列目录:
【Spring Cloud完整组件搭建之路 第一篇-Eureka】
【Spring Cloud完整组件搭建之路 第二篇 -OpenFeign、Ribbon整合】
【Spring Cloud完整组件搭建之路 第三篇 -OpenFeign、Hystrix整合】
【Spring Cloud完整组件搭建之路 第四篇 -Zuul】
【Spring Cloud完整组件搭建之路 第五篇 -Spring Cloud Config】
【Spring Cloud完整组件搭建之路 总结篇】
前置知识
Hystrix作为SpringCloud的一个容错组件,用于隔离远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。主要有以下功能:
- 为系统提供保护机制。在依赖的服务出现高延迟或失败时,为系统提供保护和控制。
- 防止雪崩。
- 包裹请求:使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中运行。
- 跳闸机制:当某服务失败率达到一定的阈值时,Hystrix可以自动跳闸,停止请求该服务一段时间。
- 资源隔离:Hystrix为每个请求都的依赖都维护了一个线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。防止级联失败。线程池隔离的方式能防止因一个请求出现问题而影响其他请求。
- 快速失败:同时能快速恢复。不会真正的请求服务,发生异常再返回,而是不请求服务,直接失败。
- 监控:Hystrix可以实时监控运行指标和配置的变化,提供近实时的监控、报警、运维控制。
- 回退机制:fallback,当请求失败、超时、被拒绝,或当断路器被打开时,执行回退逻辑。回退逻辑我们自定义,提供服务降级。
- 自我修复:断路器打开一段时间后,会自动进入“半开”状态,可以进行打开,关闭,半开状态的转换。
引入依赖
在上一篇博客【Spring Cloud完整组件搭建之路 第二篇 -OpenFeign、Ribbon整合】中,我们在Eureka的消费者客户端使用了OpenFeign,所以这次添加Hystrx依赖也要在Eureka的消费者客户端添加。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
配置文件修改
在Eureka的消费者客户端配置文件中添加如下配置:
feign:
circuitbreaker:
enabled: true
启动类添加注解
在Eureka的消费者客户端启动类添加注解
@EnableHystrix
OpenFeign和Hystrix整合有两种方式:
- 使用@FeignClient的fallback属性,使用统一的降级逻辑。
- 使用@FeignClient的fallbackFactory属性,根据不同的错误信息使用不同的降级逻辑。
使用fallback进行降级
修改测试方法
消费者客户端
修改测试接口类
在上一篇博客【Spring Cloud完整组件搭建之路 第二篇 -OpenFeign、Ribbon整合】中,我们创建了ConsumerInterface测试接口类,我们将其进行修改,修改后代码如下:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 第一行的@FeignClient注解是写死url进行远程服务调用
* 第二行的@FeignClient注解是通过eureka的app名称进行远程服务调用
* 根据第一行注解,得知Feign可以脱离Eureka独立实现远程访问
*/
//@FeignClient(name="user-service", url = "http://localhost:7300")
@FeignClient(name="USER-PROVIDER" , fallback = UserProviderBack.class)
public interface ConsumerInterface{
// 访问远端的/aliveGet地址
@RequestMapping(value = "/aliveGet",method = RequestMethod.GET)
public String aliveGet(@RequestParam("id") Integer id);
@RequestMapping(value = "/noParamGet",method = RequestMethod.GET)
public String noParamGet();
// 访问远端的/alivePost地址
@PostMapping("/alivePost")
public String alivePost(@RequestBody Map<String, Object> map);
// 访问远端的/alivePost地址
@PostMapping("/alivePostParam")
public String alivePostParam(@RequestParam Map<String, Object> map);
}
代码修改点:第二行的@FeignClient注解修改为:
@FeignClient(name="USER-PROVIDER" , fallback = UserProviderBack.class)
加了一个回退信息接收属性,所以我们新增一个回退信息接收类UserProviderBack
添加UserProviderBack回退信息接收类
此类需要添加@Component加载到IOC容器中。
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class UserProviderBack implements ConsumerInterface {
@Override
public String aliveGet(Integer id) {
return "访问失败,访问降级!!!";
}
@Override
public String noParamGet() {
return null;
}
@Override
public String alivePost(Map<String, Object> map) {
return null;
}
@Override
public String alivePostParam(Map<String, Object> map) {
return null;
}
}
从代码中看出,如果OpenFeign调用aliveGet方法出现异常,那就进入UserProviderBack类的aliveGet方法,执行相应逻辑。
生产者客户端
修改测试类方法逻辑
在上一篇博客【Spring Cloud完整组件搭建之路 第二篇 -OpenFeign、Ribbon整合】创建的UserProviderController测试类中,加入异常代码,测试Hystrix,修改后代码如下:
import org.apache.commons.lang.builder.ToStringBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
public class UserProviderController {
@Value("${server.port}")
private String port;
/**
* 用于为consumer提供feign带参的get访问
* @param id
* @return
*/
@RequestMapping(value = "/aliveGet",method = RequestMethod.GET)
public String aliveGet(@RequestParam("id") Integer id){
int i = 1/0;
return id + "---"+ port + "aliveGet";
}
/**
* 用于为consumer提供feign带参的get访问
* @return
*/
@RequestMapping(value = "/noParamGet",method = RequestMethod.GET)
public String noParamGet(){
return port + "aliveGet";
}
/**
* 用于为consumer提供feign带参的post访问
* @param map
* @return
*/
@RequestMapping(value = "/alivePost",method = RequestMethod.POST)
public String alivePost(@RequestBody Map<String,Object> map){
return ToStringBuilder.reflectionToString(map) + "---"+ port + "alivePost";
}
/**
* 用于为consumer提供feign带参的post访问
* @param map
* @return
*/
@RequestMapping(value = "/alivePostParam",method = RequestMethod.POST)
public String alivePostParam(@RequestParam Map<String,Object> map){
return ToStringBuilder.reflectionToString(map) + "---"+ port + "alivePostParam";
}
}
在aliveGet方法中加入算法异常代码。
OpenFeign/Hystrix整合测试
我只在其中一个生产者客户端添加了异常,他还是会有Ribbon负载均衡逻辑,访问其他有效生产者客户端。
使用fallbackFactory进行降级
修改测试方法
消费者客户端
修改测试接口类
对刚才fallback降级的ConsumerInterface测试接口类进行修改,修改后代码如下:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 第一行的@FeignClient注解是写死url进行远程服务调用
* 第二行的@FeignClient注解是通过eureka的app名称进行远程服务调用
* 根据第一行注解,得知Feign可以脱离Eureka独立实现远程访问
*/
//@FeignClient(name="user-service", url = "http://localhost:7300")
@FeignClient(name="USER-PROVIDER" ,
fallbackFactory = UserProviderFallBackFactory.class)
public interface ConsumerInterface{
// 访问远端的/aliveGet地址
@RequestMapping(value = "/aliveGet",method = RequestMethod.GET)
public String aliveGet(@RequestParam("id") Integer id);
@RequestMapping(value = "/noParamGet",method = RequestMethod.GET)
public String noParamGet();
// 访问远端的/alivePost地址
@PostMapping("/alivePost")
public String alivePost(@RequestBody Map<String, Object> map);
// 访问远端的/alivePost地址
@PostMapping("/alivePostParam")
public String alivePostParam(@RequestParam Map<String, Object> map);
}
代码修改点:第二行的@FeignClient注解修改为:
@FeignClient(name="USER-PROVIDER" , fallbackFactory = UserProviderFallBackFactory.class)
加了一个回退信息接收工厂属性,所以我们新增一个回退信息接收工厂类UserProviderFallBackFactory
添加UserProviderFallBackFactory回退信息接收工厂类
此类需要添加@Component加载到IOC容器中。
import feign.FeignException;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class UserProviderFallBackFactory
implements FallbackFactory<ConsumerInterface> {
@Override
public ConsumerInterface create(Throwable cause) {
return new ConsumerInterface() {
@Override
public String aliveGet(Integer id) {
if(cause instanceof FeignException.InternalServerError){
return "invoke error promote 500!!!"
+ cause.getLocalizedMessage() + " "
+ cause.getStackTrace() + " "
+ ToStringBuilder.reflectionToString(cause);
}
return "invoke localhost error!!!" + cause.getLocalizedMessage();
}
@Override
public String noParamGet() {
return null;
}
@Override
public String alivePost(Map<String, Object> map) {
return null;
}
@Override
public String alivePostParam(Map<String, Object> map) {
return null;
}
};
}
}
从代码中看出,如果OpenFeign调用aliveGet方法出现异常,那就进入UserProviderFallBackFactory类的create方法,传入异常对象,执行相应逻辑。