总有一个人要赢,为什么不是我呢? 代码下载地址:https://github.com/f641385712/netflix-learning
目录- 前言
- 正文
- getFallbackOrThrowException() 源码解读
- fallback函数执行成功or执行失败的处理
- getFallbackOrThrowException回退步骤文字总结
- 总结
- 声明
- getFallbackOrThrowException() 源码解读
- fallback函数执行成功or执行失败的处理
- getFallbackOrThrowException回退步骤文字总结
- 声明
前言
我们知道Hystrix是一个限流、降级容错框架,它能很好的保护我们的接口、应用。这很大程度上得益于它提供了fallback机制:回退(也叫降级)。
本文所讲述的fallabck机制是xxxCommand
系列的fallback实现,它是我们主要的使用方式。由于很多小伙伴并不清楚什么时候会触发fallabck,以及常问的fallabck后到底发生了什么呢?本文就带你一起深入了解Hystrix的fallback回退逻辑源码解读部分,从根本上掌握Hystrix回退处理逻辑。
正文
xxxCommand
系列正常的执行逻辑、以及出现异常的回退逻辑均在HystrixCommand
和HystrixObservableCommand
二者的抽象父类AbstractCommand
里实现的。而对fallback的所有执行逻辑便在方法getFallbackOrThrowException()
里,下面我们来一探究竟。
getFallbackOrThrowException() 源码解读
该方法是AbstractCommand
的一个私有方法,语义是:执行fallabck回滚或者抛出异常(一般为HystrixRuntimeException
异常类型,当然不是绝对的)。
值得注意的是:若执行到了这一步,Hystrix
它能100%保证无论如何都能尽快把你的请求掐断,避免系统被拖死。虽然Hystrix它建议你不要在getFallback()
里面写耗时的阻塞的(比如请求网络)逻辑,但是建议归建议,但还是可能有人不这么做怎么办呢?所以fallbackSemaphoreOverride
信号量的作用:专门用于fallabck的信号量控制,决不让其堆积请求。
代码语言:javascript复制需要注意的是:调用此方法必传一个Exception,因为Hystrix认为执行进入到这里肯定是发生了一个异常才行的。
AbstractCommand:
// _cmd:命令对象
// eventType:事件类型
// failureType:失败类型枚举(BAD_REQUEST_EXCEPTION...) 见下面枚举定义
// message:失败的消息。如timed-out、failed、short-circuited等
// Exception:导致失败的异常(一定只有异常才能导致失败),如java.util.concurrent.TimeoutException
private Observable<R> getFallbackOrThrowException(
AbstractCommand<R> _cmd, HystrixEventType eventType,
FailureType failureType, String message,
Exception originalException) {
// 因为fallabck也是在线程池里面执行,所以也是需要传递数据的
HystrixRequestContext requestContext = HystrixRequestContext.getContextForCurrentThread();
// 统计相关事件的次数:详见事件计数器
executionResult = executionResult.addEvent((int) latency, eventType);
...
// 如果异常类型是ExceptionNotWrappedByHystrix类型
if (shouldNotBeWrapped(originalException)){
... // 触发executionHook.onError()动作
return Observable.error(e);
// 是否是不可恢复的异常类型:比如StackOverflowError/VirtualMachineError...
// 因为并不是所有的Error都不会恢复,所以这里例举出来。如果是不可恢复的错误,就包装一下抛出
} else if (isUnrecoverable(originalException)) {
...
// 若是不可恢复错误,转未HystrixRuntimeException异常抛出
return Observable.error(new HystrixRuntimeException(failureType, ... );
} else {
// 若是可自己恢复的Error,如IOError,那就输入一句日志即可
if (isRecoverableError(originalException)) { ... }
// =======普通异常类型(比如NPE之类的),那就开始执行fallabck函数========
if (properties.fallbackEnabled().get()) { // 显然默认是开启的,不建议关闭它
// 若你没指定,默认使用的是TryableSemaphoreActual 10个信号量
// 你可以通过fallbackIsolationSemaphoreMaxConcurrentRequests指定这个值
// 该信号量用于杜绝你的fallabck还非常耗时的case,以防万一
TryableSemaphore fallbackSemaphore = getFallbackSemaphore();
...
// 最终return的可观察对象
// getFallbackObservable是个抽象方法,由子类提供
// 比如command它就是使用Observable.just(getFallback())把任意对象转换为Observable
// 当然它是个defer的Observable
Observable<R> fallbackExecutionChain;
// 若还有信号量资源就继续执行(否则会会做异常处理,见下面)
if (fallbackSemaphore.tryAcquire()) {
// 用户是否自定义了fallabck函数
// 也就是是否重写了getFallabck()方法嘛
if (isFallbackUserDefined()) {
... // executionHook.onFallbackStart(this);
fallbackExecutionChain = getFallbackObservable();
} else { // 区别是:若没有复写这个方法,就不会触发onFallbackStart()动作
fallbackExecutionChain = getFallbackObservable();
}
// 绑定固定的处理函数
return fallbackExecutionChain
// 作用于每个iter身上:setRequestContextIfNeeded(requestContext);
// 确保上下文是同一个,数据是通的
.doOnEach(setRequestContext)
// 主要是为了触发executionHook相关回调
.lift(new FallbackHookApplication(_cmd))
.lift(new DeprecatedOnFallbackHookApplication(_cmd))
// 发布事件:HystrixEventType.FALLBACK_EMIT
// executionResult.addEvent(HystrixEventType.FALLBACK_EMIT)
.doOnNext(markFallbackEmit)
// 完成了。发布事件:HystrixEventType.FALLBACK_SUCCESS
// 证明fallabck成功
.doOnCompleted(markFallbackCompleted)
// fallabck失败(出现异常了),发布事件
// HystrixEventType.FALLBACK_MISSING、FALLBACK_FAILURE
.onErrorResumeNext(handleFallbackError)
// 释放信号量:fallbackSemaphore.release();
.doOnTerminate(singleSemaphoreRelease)
// fallbackSemaphore.release();
.doOnUnsubscribe(singleSemaphoreRelease);
} else { // 此else对应逻辑:信号量不够的情况
return handleFallbackRejectionByEmittingError();
}
} else { // 此else对应逻辑:properties禁用了fallabck的情况
return handleFallbackDisabledByEmittingError(originalException, failureType, message);
}
}
}
// 定义失败枚举:一个7种类型
HystrixRuntimeException:
public static enum FailureType {
BAD_REQUEST_EXCEPTION, COMMAND_EXCEPTION, TIMEOUT, SHORTCIRCUIT, REJECTED_THREAD_EXECUTION, REJECTED_SEMAPHORE_EXECUTION, REJECTED_SEMAPHORE_FALLBACK
}
fallback函数执行成功or执行失败的处理
针对以上fallbackExecutionChain
被观察对象的执行,还需注意关心它的执行成功or失败,需要做对应的处理:
.doOnNext(markFallbackEmit)
:没发射一个数据(执行fallabck方法之前),给事件计数executionResult.addEvent(HystrixEventType.FALLBACK_EMIT)
doOnCompleted(markFallbackCompleted)
:正常执行完成(fallabck未抛出异常)时,记录结果事件executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_SUCCESS)
.onErrorResumeNext(handleFallbackError)
:若执行fallabck时候发生错误(重点),就执行如下逻辑:
// 若异常类型是该类型(比如你使用HystrixCommand,但没重写getFallabck()方法,执行就抛出此异常)
// 就包装为HystrixRuntimeException给你抛出
// 并且有你熟悉的抛错消息: message " and no fallback available."
if (fe instanceof UnsupportedOperationException) {
...
// 记录结果:事件类型是FALLBACK_MISSING
executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_MISSING);
return Observable.error(new HystrixRuntimeException(failureType, ...);
} else { // 你的fallabck方法里抛出了其它异常
...
// 记录事件,此时事件类型是Fallabck执行失败FALLBACK_FAILURE
executionResult.addEvent((int) latency, HystrixEventType.FALLBACK_FAILURE);
return Observable.error(new HystrixRuntimeException(failureType ... message " and fallback failed." ...);
}
对于fallabck执行失败的case,请注意错误消息and no fallback available.
和and fallback failed.
的区别。前者是木有提供fallback函数,后者是提供了但是执行时抛错了(fallback函数里都出错了也是人才)。
另外,源码处有两个else逻辑
此处也给个简要描述:
- 如果
properties.fallbackEnabled() = false
显示禁用了fallabck功能,最终会触发handleFallbackDisabledByEmittingError()
方法(此为唯一调用处):
AbstractCommand:
private Observable<R> handleFallbackDisabledByEmittingError(Exception underlying, FailureType failureType, String message) {
... // 触发executionHook.onError动作
// 转换为一个HystrixRuntimeException抛出
return Observable.error(new HystrixRuntimeException(failureType, ... " and fallback disabled." ... );
}
- 如果执行fallabck时请求信号量资源不够用了,那么执行
handleFallbackRejectionByEmittingError()
方法(此处为唯一调用处):
AbstractCommand:
private Observable<R> handleFallbackRejectionByEmittingError() {
...
// 这里记录了结果哦。统计对应事件的次数(毕竟出现此case的数据还是蛮有意义的)
executionResult = executionResult.addEvent((int) latencyWithFallback, HystrixEventType.FALLBACK_REJECTION);
return Observable.error(new HystrixRuntimeException(FailureType.REJECTED_SEMAPHORE_FALLBACK,... " fallback execution rejected." ...);
}
总的来说,出现以上两种else情况,最终的效果均是抛出一个HystrixRuntimeException
异常。这是Hystrix
对fallback
处理的全部逻辑,那么,针对其正常的回退步骤,下面用一个文字版步骤总结。
getFallbackOrThrowException回退步骤文字总结
首先需要明确:执行此fallabck步骤肯定是发生了Exception异常的(当然有可能是Error错误),所以异常类型很关键,此处用e
来表示源生异常类型(如目标方法自己产生的NPE)。
- 若
e
不需要被包装,那就不用使用HystrixRuntimeException
去包它了,直接返回:Observable.error(e);
ExceptionNotWrappedByHystrix
是个标记接口:若你的异常类型实现了此接口,那么抛出此类型的异常将不会再被HystrixRuntimeException
包起来了
- 若
e
是不可恢复的异常类型如:StackOverflowError/VirtualMachineError/ThreadDeath/LinkageError
,那就直接包装为HystrixRuntimeException
类型抛出。 - 到这一步,
e
的类型“过关”了,着手执行fallabck逻辑。若禁用了fallabck,就执行handleFallbackDisabledByEmittingError()
方法 -> 抛出HystrixRuntimeException
异常,否则继续。 - 准备执行fallabck函数,先请求fallabck专用的信号量。若无资源了,那就执行
handleFallbackRejectionByEmittingError()
犯法 -> 抛出HystrixRuntimeException
异常,否则继续。否则继续 - 通过抽象方法
getFallbackObservable()
拿到被观察对象Observable<R>
,然后便可开始执行目标fallabck函数了。其中执行目标fallback函数时分为成功or失败。- 成功: 执行
doOnCompleted
放,整成记录FALLBACK_SUCCESS
事件到结果即可 - 失败:分为未提供fallabck函数和fallback函数内部抛出了异常两种case -> 均抛出
HystrixRuntimeException
异常,对应异常消息是著名的:and no fallback available.
和and fallback failed.
。
- 成功: 执行
总结
关于Hystrix的fallback回退逻辑源码解读就介绍到这了,本文主要介绍了AbstractCommand#getFallbackOrThrowException
的执行逻辑以及源码分析,相信你已经对Hystrix是如何调用目标fallback函数以及执行目标fallback函数时若发生异常时的处理有了一定的认识,但是你或许还会关注一个重点:什么时候会触发fallabck回退呢?