引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
并在主函数加上@EnableHystrix注解 测试不添加以上注释,好像也没毛病 我们首先使用继承HystrixCommand的形式,来实现可以更直观的看出使用细节
第一种使用方式:使用继承HystrixCommand的形式
public class MyCommand extends HystrixCommand<Integer> {
//注入自己的相关服务
@Autowired
private Dome dome;
//构造函数
protected MyCommand(Dome dome) {
//dome是相应的类,queryByOrderId是其中具体的方法
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("dome"))
.andCommandKey(HystrixCommandKey.Factory.asKey("queryByOrderId"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withCircuitBreakerRequestVolumeThreshold(10)//至少有10个请求,熔断器才进行错误率的计算
.withCircuitBreakerSleepWindowInMilliseconds(5000)//熔断器中断请求5秒后会进入半打开状态,放部分流量过去重试
.withCircuitBreakerErrorThresholdPercentage(50)//错误率达到50开启熔断保护
.withExecutionTimeoutEnabled(true))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties
.Setter().withCoreSize(10)));
this.dome = dome;
}
@Override
protected Integer run() throws Exception {
return null;
}
@Override
protected Integer getFallback() {
return -1;
}
开始运行
public void testQueryByOrderIdCommand() {
Integer r = new MyCommand(dome).execute();
}
这里有几种运行方式,下面说明一哈
execute()
以同步堵塞方式执行run(),只支持接收一个值对象。hystrix会从线程池中取一个线程来执行run(),并等待返回值。
queue()
以异步非阻塞方式执行run(),只支持接收一个值对象。调用queue()就直接返回一个Future对象。可通过 Future.get()拿到run()的返回结果,但Future.get()是阻塞执行的。若执行成功,Future.get()返回单个返回值。当执行失败时,如果没有重写fallback,Future.get()抛出异常。
observe()
事件注册前执行run()/construct(),支持接收多个值对象,取决于发射源。调用observe()会返回一个hot Observable,也就是说,调用observe()自动触发执行run()/construct(),无论是否存在订阅者。 如果继承的是HystrixCommand,hystrix会从线程池中取一个线程以非阻塞方式执行run();如果继承的是HystrixObservableCommand,将以调用线程阻塞执行construct()。
observe()使用方法:
1、调用observe()会返回一个Observable对象
2、调用这个Observable对象的subscribe()方法完成事件注册,从而获取结
toObservable()
事件注册后执行run()/construct(),支持接收多个值对象,取决于发射源。调用toObservable()会返回一个cold Observable,也就是说,调用toObservable()不会立即触发执行run()/construct(),必须有订阅者订阅Observable时才会执行。 如果继承的是HystrixCommand,hystrix会从线程池中取一个线程以非阻塞方式执行run(),调用线程不必等待run();如果继承的是HystrixObservableCommand,将以调用线程堵塞执行construct(),调用线程需等待construct()执行完才能继续往下走。
toObservable()使用方法:
1、调用observe()会返回一个Observable对象
2、调用这个Observable对象的subscribe()方法完成事件注册,从而获取结果
需注意的是,HystrixCommand也支持toObservable()和observe(),但是即使将HystrixCommand转换成Observable,它也只能发射一个值对象。只有HystrixObservableCommand才支持发射多个值对象。 下面一图展示了几种方式的联系
execute()实际是调用了queue().get() queue()实际调用了toObservable().toBlocking().toFuture() observe()实际调用toObservable()获得一个cold Observable,再创建一个ReplaySubject对象订阅Observable,将源Observable转化为hot Observable。 因此调用observe()会自动触发执行run()/construct()。
- 以上继承的方式可以很明确的看出具体细节,但是相对来说代码敲得比较繁琐,一般可以使用官方提供的注解来使用,以下看方式二
方式二:使用@HystrixCommand配置相关内容
@SneakyThrows
@GetMapping("/getOther")
@HystrixCommand(fallbackMethod = "fallback",
// 线程池标识
threadPoolKey = "getTodayStatisticB",
threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "1"), // 这个就是咱们那个线程池core线程核心数
@HystrixProperty(name="maxQueueSize",value="100") //这个是队列大小
},
// 使用commandProperties 可以配置熔断的一些细节信息
commandProperties = {
// 类似kv形式
//这里这个参数意思是熔断超时时间2s,表示过了多长时间还没结束就进行熔断
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000"),
// 当遇到失败后,开启一个11s的窗口
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "11000"),
// 最小请求数
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "3"),
// 失败次数占请求的50%
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
// 跳闸后 活动窗口配置 这里配置了10s
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000")
})
public String getOther(@RequestParam(required = false) String userId){
//暂停2秒
Thread.sleep(2000);
System.out.println("当前线程为:"+Thread.currentThread().getName());
String res = restTemplate.getForObject("http://CLIENT2-SERVICE/client2/get",String.class);
return res;
}
使用配置说明
commandProperties配置熔断细节
execution.isolation.thread.timeoutInMilliseconds为超时时间
metrics.rollingStats.timeInMilliseconds当遇到失败后,开启一个一定时间的窗口(详情见滑动窗口限流)
circuitBreaker.requestVolumeThreshold最小请求数
circuitBreaker.errorThresholdPercentage失败比例
circuitBreaker.sleepWindowInMilliseconds跳闸后滑动窗口时间
测试
按照上面代码所示配置,我们开始测试 使用Thread.sleep(2000);休眠两秒调用方法getOther,发现成功进入熔断 如上代码所示,我们设置的失败占比为50%,我们代码中写的线程暂停2秒,使用postman调用可以 发现前两次次进入熔断, 时间均为2秒左右
第三次进入熔断 时间为
可以发现我们已经进入失败窗口 此时等待11秒后再次请求,又开始重新判断,可以看见我们前面配置的失败滑动窗口时间 为11s