【Hystrix】四種fallback條件 例子
Hystrix會在以下四種情況下觸發fallback函式:
1.任務超過了"withExecutionTimeoutInMilliseconds"定義的超時時間;
2.任務丟擲了非HystrixBadRequestException的異常;
3.超過了執行緒池執行緒數目;
4.熔斷器開啟;
下面一一舉例。
1.超時
public class HelloCommand extends HystrixCommand<String> { protected HelloCommand() { super( Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("example")) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(1000)) ); } @Override protected String run() throws Exception { Thread.sleep(2000); return "hello"; } @Override protected String getFallback() { return "failed"; } }
main:
public class App
{
public static void main( String[] args )
{
try {
System.out.println(new HelloCommand().execute());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.拋異常:
public class HelloCommand extends HystrixCommand<String> { protected HelloCommand() { super( Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("example")) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(1000)) ); } @Override protected String run() throws Exception { throw new NullPointerException(); } @Override protected String getFallback() { return "failed"; } }
main:
public class App
{
public static void main( String[] args )
{
try {
System.out.println(new HelloCommand().execute());
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.超過執行緒池執行緒數目
public class HelloCommand extends HystrixCommand<String> { protected HelloCommand() { super( Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("example")) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(2000)) .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(3)) ); } @Override protected String run() throws Exception { Thread.sleep(1000); return "hello"; } @Override protected String getFallback() { return "failed"; } }
main:
public class App
{
public static void main( String[] args )
{
try {
for (int i = 0 ; i < 4; i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(new HelloCommand().execute());
}
}).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
結果會列印:
failed
hello
hello
hello
可以看到第四個任務先列印,說明在前三個執行時,第四個被直接判定為fail,第一個打印出來。原因就是執行緒池只配置了三個執行緒,所以第四個任務沒有被執行,直接fail。
當然執行緒池的maxQueueSize引數預設是-1,表示執行緒池的等待佇列為0,只要核心執行緒池沒有空閒,就fail。
4.熔斷器開啟。
那麼就得知道什麼時候熔斷器會開啟。
如果在10s有多於circuitBreakerSleepWindowInMilliseconds個請求到達,而且有多於circuitBreakerErrorThresholdPercentage百分比的請求失敗,則會導致熔斷器開啟,後續的circuitBreakerSleepWindowInMilliseconds時間段內的請求會直接fail。
public class HelloCommand extends HystrixCommand<String> {
protected HelloCommand() {
super(
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("example"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(500)
.withCircuitBreakerRequestVolumeThreshold(3)
.withCircuitBreakerErrorThresholdPercentage(75))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(100))
);
}
@Override
protected String run() throws Exception {
Thread.sleep(1000);
return "hello";
}
@Override
protected String getFallback() {
return "failed";
}
}
main:
public class App
{
public static void main( String[] args )
{
try {
for (int i = 0 ; i < 4; i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(new HelloCommand().execute());
}
}).start();
Thread.sleep(1000);
}
for (int i = 0 ; i < 4; i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(new HelloCommand().execute());
}
}).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
結果:
failed
failed
failed
failed
failed
failed
failed
failed
總共會有8個failed列印,因為總共8個任務。
但是前四個是間隔一定時間列印一個,後面四個是同時秒打出來。
因為配置了circuitBreakerSleepWindowInMilliseconds為3。第一個for迴圈裡的四個任務正好保證了每10秒內有大於3個任務達到,那麼會觸發熔斷器監控邏輯,這個四個任務執行時間是1s,而超時閾值是0.5s,那麼每一個任務最重都會超時。所以第四個任務fail之後,熔斷器已經打開了。這四個任務會執行到run方法,所以是執行了0.5s才打印的。
第二個for迴圈裡的任務根本不會執行,因為執行時熔斷器打開了,沒有sleep直到超時,而是直接秒fail,所以同時列印。