目的
优雅地处理服务失效,防止雪崩
功能
- 熔断器,统计服务执行情况,达到熔断条件时直接进行降级处理。
- 快速恢复,在熔断后一定时间会尝试半开,尝试重新请求。
- 服务隔离,服务可以使用单独的线程池,失效时无法影响其余服务。
- 快速失败。可以设置时延,以达到快速失效,不会一直耗着资源。
- 监控面板
使用方式
原生方式:
(1)继承HystrixCommand/HystrixObservableCommand
(2)重写run()/construct()
(3)实例化
(4)执行execute()/queue()/observe()/toObservable()。
public class LblCommand extends HystrixCommand<String>{
protected LblCommand() {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
}
@Override
protected String run() throws Exception {
throw new Exception();
}
@Override
protected String getFallback() {
return "fallback";
}
}
Spring cloud方式:
1. 创建项目,包含hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.主类中开启熔断器
@SpringBootApplication
@EnableCircuitBreaker
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
}
3.使用注解声明HystrixCommand,注意不可以在同一个类中调用HystrixCommand注解的方法,否则不会生效。
@Component
public class LblCommand2 {
@HystrixCommand(fallbackMethod = "myfallback",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")})
String testHystrix(int i) throws Exception{
System.out.println(new Date().getSeconds() + ":tried");
if(i == 0){
return "success";
}
throw new Exception();
}
@HystrixCommand
String myfallback(int i){
return "fallback!";
}
}
4. 更多的commandProperties可以查看HystrixCommandProperties这个类,有详细的说明和默认值。
原理
RXJava
在看Hystrix的时候会发现里面用到了大量的RXJava,这里分享一篇不错的博客https://www.jianshu.com/p/88aacbed8aa5
科普下RXJava。首先,它实现了基本的观察者模式。
观察者模式中有两种角色,Observable和Subscriber,就是被观察者和观察者。
在RXJava中:
(1)Observable的call方法就是被观察者主要逻辑。
(2)观察者需要实现一些回调方法,如onSuccess,onError
(3)在调用subscribe方法建立绑定关系时,将会触发被观察者的call方法,运行主要逻辑,并在运行过程中通过回调通知Subscriber。
其次就是RXJava的是链式调用,如:
//以下为伪代码
new Observable().doOnSuccess().doOnFail().subsribeOn(scheduler)
每一次调用都会根据上一个Observable封装一下生成新的Observable,新的Observable会在原来的基础上增加一些逻辑。
当声明完这一切后,所有方法都不会执行,只有调用subscribe,触发最后一个Observable的call方法,然后它又触发倒数第二个的call方法,一直触发到第一个的call方法。
当理解完这个,再去看hystrix的源码会清晰很多。
hystrix主要流程
观察HystrixCommand的queue方法,跟踪Observable的封装过程,可以得出hystrix的主要流程。
(1)检查circuitBreaker
(2)检查信号量
(3)检查线程池
(4)执行逻辑
(5)是否有异常
(6)是否超时
(7)一旦1/2/3/5/6失败则执行fallback方法
信号量/线程池
我们可以根据参数executionIsolationStrategy设置使用THREAD或SEMAPHORE模式。
信号量模式
无论如何,程序都会去获取信号量,如果设为信号量模式,此时会根据最大并发数创建信号量,当并达到并发数时,tryAcquire就会失败,则执行fallback。
线程模式
设为线程模式,获取信号量时会返回TryableSemaphoreNoOp,该对象的tryAcquire方法永远为true,相当于忽略信号量检查。
完成信号量检查后,会为Observerable再封装一层,增加线程异步执行的逻辑。
//位于AbstractCommand的executeCommandWithSpecifiedIsolation方法
subscribeOn(threadPool.getScheduler(new Func0<Boolean>() {
@Override
public Boolean call() {
return properties.executionIsolationThreadInterruptOnTimeout().get() && _cmd.isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT;
}
}));
在这里,每个CommandKey会使用单独的线程池,使得服务调用可以隔离开来,不会互相影响,但是线程上下文切换会影响效率。
关于线程池的参数可以查看对应的Setter类,会有详细的参数。
超时/异常
超时检查
//位于AbstractCommand的executeCommandAndObserve方法
Observable<R> execution;
if (properties.executionTimeoutEnabled().get()) {
execution = executeCommandWithSpecifiedIsolation(_cmd)
.lift(new HystrixObservableTimeoutOperator<R>(_cmd));
} else {
execution = executeCommandWithSpecifiedIsolation(_cmd);
}
如果配置了检查timeout,会为Observable再一层封装,增加timeout计时器的逻辑。
HystrixTimer.getInstance().addTimerListener(listener);
异常处理
final Func1<Throwable, Observable<R>> handleFallback = new Func1<Throwable, Observable<R>>() {
@Override
public Observable<R> call(Throwable t) {
Exception e = getExceptionFromThrowable(t);
executionResult = executionResult.setExecutionException(e);
if (e instanceof RejectedExecutionException) {
return handleThreadPoolRejectionViaFallback(e);
} else if (t instanceof HystrixTimeoutException) {
return handleTimeoutViaFallback();
} else if (t instanceof HystrixBadRequestException) {
return handleBadRequestByEmittingError(e);
} else {
/*
* Treat HystrixBadRequestException from ExecutionHook like a plain HystrixBadRequestException.
*/
if (e instanceof HystrixBadRequestException) {
eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);
return Observable.error(e);
}
return handleFailureViaFallback(e);
}
}
};
一旦发生异常,会触发此回调方法,并生成新的FallbackObservable,执行fallback逻辑。
总的来说,就是使用了大量的Observable.defer方法进行延迟绑定,根据逻辑判断生成对应的Observable,并使用这个链式编程的特性增加了成功、失败、超时等回调逻辑。