Hystrix使用fallback機制很簡單,繼承HystrixCommand只需重寫getFallback(),繼承HystrixObservableCommand只需重寫resumeWithFallback(),比如上篇文章的HelloWorldHystrixCommand加上下面代碼片段:
@Override
protected String getFallback() {
return "fallback: " + name;
}
fallback實際流程是當run()/construct()被觸發執行時或執行中發生錯誤時,將轉向執行getFallback()/resumeWithFallback()。
結合下圖,4種情況(出現異常,超時,熔斷,線程池已滿)將觸發fallback:

①run()方法中出現異常(非HystrixBadRequestException異常)或者出現超時()觸發fallback()
public class HystrixFallbackNomal extends HystrixCommand<String>{
private final String name;
public HystrixFallbackNomal(String name) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
}
@Override
public String run() throws Exception {
/*---------------會觸發fallback的case-------------------*/
// 無限循環,實際上屬於超時
/* int j = 0;
while (true) {
j++;
}*/
Thread.sleep(1000);
// 除零異常
// int i = 1/0;
// 主動拋出異常
// throw new HystrixTimeoutException();
// throw new RuntimeException("this command will trigger fallback");
// throw new Exception("this command will trigger fallback");
// throw new HystrixRuntimeException(FailureType.BAD_REQUEST_EXCEPTION, commandClass, message, cause, fallbackException);
/*---------------不會觸發fallback的case-------------------*/
// 被捕獲的異常不會觸發fallback
// try {
// throw new RuntimeException("this command never trigger fallback");
// } catch(Exception e) {
// e.printStackTrace();
// }
// HystrixBadRequestException異常由非法參數或非系統錯誤引起,不會觸發fallback,也不會被計入熔斷器
//throw new HystrixBadRequestException("HystrixBadRequestException is never trigger fallback");
//return name;
}
@Override
protected String getFallback() {
return "fallback: " + name;
}
}
}
②熔斷觸發fallback()
/**
* 熔斷機制相當於電路的跳閘功能,例如:我們可以配置熔斷策略為當請求錯誤比例在10s內>50%時,該服務將進入熔斷狀態,后續請求都會進入fallback
* CircuitBreakerRequestVolumeThreshold設置為3,意味着10s內請求超過3次就觸發熔斷器(10s這個時間暫時不可配置)
* run()中無限循環使命令超時進入fallback,10s內請求超過3次,將被熔斷,進入降級,即不進入run()而直接進入fallback
* 如果未熔斷,但是threadpool被打滿,仍然會降級,即不進入run()而直接進入fallback
*/
public class HystrixFallbackCircuitBreaker extends HystrixCommand<String>{
private final String name;
public HystrixFallbackCircuitBreaker(String name) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("CircuitBreakerTestGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("CircuitBreakerTestKey"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("CircuitBreakerTest"))
.andThreadPoolPropertiesDefaults( // 配置線程池
HystrixThreadPoolProperties.Setter()
.withCoreSize(200) // 配置線程池里的線程數,設置足夠多線程,以防未熔斷卻打滿threadpool
)
.andCommandPropertiesDefaults( // 配置熔斷器
HystrixCommandProperties.Setter()
.withCircuitBreakerEnabled(true)
.withCircuitBreakerRequestVolumeThreshold(3)
.withCircuitBreakerErrorThresholdPercentage(80)
// .withCircuitBreakerForceOpen(true) // 置為true時,所有請求都將被拒絕,直接到fallback
// .withCircuitBreakerForceClosed(true) // 置為true時,將忽略錯誤
// .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE) // 信號量隔離
// .withExecutionTimeoutInMilliseconds(5000)
)
);
this.name = name;
}
@Override
protected String run() throws Exception {
System.out.println("running run():" + name);
int num = Integer.valueOf(name);
if(num < 10) { // 直接返回
return name;
} else { // 無限循環模擬超時
int j = 0;
while (true) {
j++;
}
}
// return name;
}
@Override
protected String getFallback() {
return "CircuitBreaker fallback: " + name;
}
}
@Test
public void testFallbackCricuitBreaker() throws IOException {
for(int i = 0; i < 50; i++) {
try {
System.out.println("===========" + new HystrixFallbackCircuitBreaker(String.valueOf(i)).execute());
} catch(Exception e) {
System.out.println("run()拋出HystrixBadRequestException時,被捕獲到這里" + e.getCause());
}
}
System.out.println("------開始打印現有線程---------");
Map<Thread, StackTraceElement[]> map=Thread.getAllStackTraces();
for (Thread thread : map.keySet()) {
System.out.println(thread.getName());
}
System.out.println("thread num: " + map.size());
System.in.read();
}
③線程池已滿,觸發fallback()
public class HystrixThreadPoolFallback extends HystrixCommand<String>{
private final String name;
public HystrixThreadPoolFallback(String name) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ThreadPoolTestGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("testCommandKey"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("ThreadPoolTest"))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(5000)
)
.andThreadPoolPropertiesDefaults(
HystrixThreadPoolProperties.Setter()
.withCoreSize(3) // 配置線程池里的線程數
)
);
this.name = name;
}
@Override
protected String run() throws Exception {
System.out.println(name);
TimeUnit.MILLISECONDS.sleep(2000);
return name;
}
@Override
protected String getFallback() {
return "fallback: " + name;
}
}
@Test
public void testThreadPool() throws IOException {
for(int i = 0; i < 10; i++) {
try {
Future<String> future = new HystrixThreadPoolFallback("Hlx"+i).queue();
} catch(Exception e) {
System.out.println("run()拋出HystrixBadRequestException時,被捕獲到這里" + e.getCause());
}
}
for(int i = 0; i < 20; i++) {
try {
System.out.println("===========" + new HystrixThreadPoolFallback("Hlx"+i).execute());
} catch(Exception e) {
System.out.println("run()拋出HystrixBadRequestException時,被捕獲到這里" + e.getCause());
}
}
try {
TimeUnit.MILLISECONDS.sleep(2000);
}catch(Exception e) {}
System.out.println("------開始打印現有線程---------");
Map<Thread, StackTraceElement[]> map=Thread.getAllStackTraces();
for (Thread thread : map.keySet()) {
System.out.println(thread.getName());
}
System.out.println(map);
System.out.println("thread num: " + map.size());
System.in.read();
}
參考文獻:http://www.jianshu.com/p/b9af028efebb
