一、新建SpringBoot测试项目,pom依赖如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhq</groupId>
<artifactId>hystrix</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hystrix</name>
<description>Hystrix实现服务隔离、熔断、降级案例</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-metrics-event-stream</artifactId>
<version>1.5.12</version>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>1.5.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二、案例核心代码
1)、新建TestController类编写两个没有配置Hystrix的接口,一个配置了Hystrix的接口
@RestController
public class TestController {
@Autowired
private TestService testService;
/**
* 没有配置Hystrix的API01
* @return
*/
@RequestMapping("/noHystrixApi01")
public Object noHystrixApi01(){
JSONObject baidu =testService.getBaidu();
System.out.println("当前线程名称:" + Thread.currentThread().getName() + ",订单服务调用会员服务:member:" + baidu);
return baidu;
}
/**
* 没有配置Hystrix的API02
* @return
*/
@RequestMapping("/noHystrixApi02")
public Object noHystrixApi02(){
JSONObject baidu =testService.getBaidu();
System.out.println("当前线程名称:" + Thread.currentThread().getName() + ",订单服务调用会员服务:member:" + baidu);
return baidu;
}
/**
* 有配置Hystrix的API
* @return
*/
@RequestMapping("/hystrixApi")
public Object hystrixApi(){
return new HaveHystrixTestApiService(testService).execute();
}
}
2)、其中TestService代码
@Service
public class TestService {
public JSONObject getBaidu() {
return HttpClientUtils.httpGet("http://www.baidu.com");
}
}
3)、配置 Hystrix的核心代码HaveHystrixTestApiService
原理:
1、 使用线程池隔离可以完全隔离第三方应用,请求线程可以快速放回。 2、 请求线程可以继续接受新的请求,如果出现问题线程池隔离是独立的不会影响其他应用。
3、 当失败的应用再次变得可用时,线程池将清理并可立即恢复,而不需要一个长时间的恢复。
4、 独立的线程池提高了并发性
缺点:
线程池隔离的主要缺点是它们增加计算开销(CPU)。每个命令的执行涉及到排队、调度和上 下文切换都是在一个单独的线程上运行的。
public class HaveHystrixTestApiService extends HystrixCommand<JSONObject> {
@Autowired
private TestService testService;
public HaveHystrixTestApiService(TestService testService) {
super(setter());
this.testService = testService;
}
private static Setter setter() {
// 服务分组
HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("testGroup");
// 服务标识
HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("test");
// 线程池名称
HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("test-pool");
// #####################################################
// 线程池配置 线程池大小为10,线程存活时间15秒 队列等待的阈值为100,超过100执行拒绝策略
HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(10)
.withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);
// ########################################################
// 命令属性配置Hystrix 开启超时
HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
// 采用线程池方式实现服务隔离
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
// 禁止
.withExecutionTimeoutEnabled(false);
return HystrixCommand.Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey)
.andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);
}
@Override
protected JSONObject run() throws Exception {
JSONObject baidu = testService.getBaidu();
System.out.println("当前线程名称:" + Thread.currentThread().getName() + ",订单服务调用会员服务:member:" + baidu);
return baidu;
}
@Override
protected JSONObject getFallback() {
// 如果Hystrix发生熔断,当前服务不可用,直接执行Fallback方法
System.out.println("系统错误!");
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 500);
jsonObject.put("msg", "系统错误!");
return jsonObject;
}
}
三、通过JMeter测试案例
1)、没做接口保护的时候场景:
当并发请求noHystrixApi01接口线程池资源满,导致noHystrixApi02无法访问
启动以后:
没做接口保护时:虽然我们是并发请求api01但是导致api02也无法访问
其中api01:
api02:
即他们共用一个线程池
2)压测1)时如果访问有配置接口保护的hystrixApi接口
因为走的独立线程池不受影响