Hystrix配置
@Configuration
public class HystrixConfig {
@Bean
public HystrixCommandAspect hystrixCommandAspect() {
return new HystrixCommandAspect();
}
/**
* 向監(jiān)控中心Dashboard發(fā)送stream消息
*/
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet() {
ServletRegistrationBean registrationBean =
new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/hystrix.stream");
return registrationBean;
}
}
Hystrix配置參數(shù)講解:
// 熔斷器在整個統(tǒng)計時間內(nèi)是否開啟的閥值
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
// 至少有3個請求才進(jìn)行熔斷錯誤比率計算
/**
* 設(shè)置在一個滾動窗口中,打開斷路器的最少請求數(shù)脊僚。
比如:如果值是20,在一個窗口內(nèi)(比如10秒),收到19個請求鸠姨,即使這19個請求都失敗了择膝,斷路器也不會打開。
*/
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "3"),
//當(dāng)出錯率超過50%后熔斷器啟動
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
// 熔斷器工作時間油湖,超過這個時間巍扛,先放一個請求進(jìn)去,成功的話就關(guān)閉熔斷乏德,失敗就再等一段時間
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000")
@HystrixProperty(name = "coreSize", value = "30"),
/**
* BlockingQueue的最大隊列數(shù)撤奸,當(dāng)設(shè)為-1,會使用SynchronousQueue喊括,值為正時使用LinkedBlcokingQueue胧瓜。
*/
@HystrixProperty(name = "maxQueueSize", value = "101"),
/**
* 設(shè)置存活時間,單位分鐘瘾晃。如果coreSize小于maximumSize贷痪,那么該屬性控制一個線程從實用完成到被釋放的時間.
*/
/**
我們知道,線程池內(nèi)核心線程數(shù)目都在忙碌蹦误,再有新的請求到達(dá)時,線程池容量可以被擴(kuò)充為到最大數(shù)量肉津。
等到線程池空閑后强胰,多于核心數(shù)量的線程還會被回收,此值指定了線程被回收前的存活時間妹沙,默認(rèn)為 2偶洋,即兩分鐘。
*/
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
/**
* 設(shè)置隊列拒絕的閾值,即使maxQueueSize還沒有達(dá)到
*/
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
// 滑動統(tǒng)計的桶數(shù)量
/**
* 設(shè)置一個rolling window被劃分的數(shù)量距糖,若numBuckets=10玄窝,rolling window=10000,
*那么一個bucket的時間即1秒悍引。必須符合rolling window % numberBuckets == 0恩脂。默認(rèn)1
*/
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
// 設(shè)置滑動窗口的統(tǒng)計時間。熔斷器使用這個時間
/** 設(shè)置統(tǒng)計的時間窗口值的趣斤,毫秒值俩块。
circuit break 的打開會根據(jù)1個rolling window的統(tǒng)計來計算。
若rolling window被設(shè)為10000毫秒浓领,則rolling window會被分成n個buckets玉凯,
每個bucket包含success,failure联贩,timeout漫仆,rejection的次數(shù)的統(tǒng)計信息。默認(rèn)10000
**/
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000")
fallbackMethod:方法執(zhí)行時熔斷泪幌、錯誤盲厌、超時時會執(zhí)行的回退方法署照,需要保持此方法與 Hystrix 方法的簽名和返回值一致。
defaultFallback:默認(rèn)回退方法狸眼,當(dāng)配置 fallbackMethod 項時此項沒有意義藤树,另外,默認(rèn)回退方法不能有參數(shù)拓萌,返回值要與 Hystrix方法的返回值相同岁钓。
對Hystrix服務(wù)降級和熔斷進(jìn)行測試,3個例子微王。
@RestController
@RequestMapping("/hystrix1")
@DefaultProperties(defaultFallback = "defaultFail")
public class HystrixController1 {
@HystrixCommand(fallbackMethod = "fail1")
@GetMapping("/test1")
public String test1() {
throw new RuntimeException();
}
private String fail1() {
System.out.println("fail1");
return "fail1";
}
@HystrixCommand(fallbackMethod = "fail2")
@GetMapping("/test2")
public String test2() {
throw new RuntimeException();
}
@HystrixCommand(fallbackMethod = "fail3")
private String fail2() {
System.out.println("fail2");
throw new RuntimeException();
}
@HystrixCommand
private String fail3() {
System.out.println("fail3");
throw new RuntimeException();
}
private String defaultFail() {
System.out.println("default fail");
return "default fail";
}
}
當(dāng)訪問http://localhost:8082/hystrix1/test1
拋出異常屡限,服務(wù)降級返回fail1。
當(dāng)訪問http://localhost:8082/hystrix1/test2
拋出異常炕倘,服務(wù)不斷降級返回default fail钧大。
@RestController
@RequestMapping("/hystrix2")
@DefaultProperties(defaultFallback = "defaultFail")
public class HystrixController2 {
@HystrixCommand(commandProperties =
{
// 熔斷器在整個統(tǒng)計時間內(nèi)是否開啟的閥值
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
// 至少有3個請求才進(jìn)行熔斷錯誤比率計算
/**
* 設(shè)置在一個滾動窗口中,打開斷路器的最少請求數(shù)罩旋。
比如:如果值是20啊央,在一個窗口內(nèi)(比如10秒),收到19個請求涨醋,即使這19個請求都失敗了瓜饥,斷路器也不會打開。
*/
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "3"),
//當(dāng)出錯率超過50%后熔斷器啟動
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
// 熔斷器工作時間浴骂,超過這個時間乓土,先放一個請求進(jìn)去,成功的話就關(guān)閉熔斷溯警,失敗就再等一段時間
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
// 統(tǒng)計滾動的時間窗口
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000")
})
@GetMapping("/test1")
public String test1(@RequestParam("id") Integer id) {
System.out.println("id:" + id);
if (id % 2 == 0) {
throw new RuntimeException();
}
return "test_" + id;
}
private String defaultFail() {
System.out.println("default fail");
return "default fail";
}
}
當(dāng)訪問1次http://localhost:8082/hystrix2/test1?id=1
和2次http://localhost:8082/hystrix2/test1?id=2
趣苏,錯誤率達(dá)66%超過了設(shè)置的50%。服務(wù)進(jìn)入熔斷梯轻。
下次請求http://localhost:8082/hystrix2/test1?id=2
會進(jìn)入熔斷策略食磕,返回default fail
如果在5s之后,下一次請求成功檩淋,會關(guān)閉熔斷芬为,服務(wù)恢復(fù)。
@RestController
@RequestMapping("/hystrix3")
@DefaultProperties(defaultFallback = "defaultFail")
public class HystrixController3 {
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500")
})
@GetMapping("/test1")
public String test1() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(1000);
return "test1";
}
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500"),
// 滑動統(tǒng)計的桶數(shù)量
/**
* 設(shè)置一個rolling window被劃分的數(shù)量蟀悦,若numBuckets=10媚朦,rolling window=10000,
*那么一個bucket的時間即1秒日戈。必須符合rolling window % numberBuckets == 0询张。默認(rèn)1
*/
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
// 設(shè)置滑動窗口的統(tǒng)計時間。熔斷器使用這個時間
/** 設(shè)置統(tǒng)計的時間窗口值的浙炼,毫秒值份氧。
circuit break 的打開會根據(jù)1個rolling window的統(tǒng)計來計算唯袄。
若rolling window被設(shè)為10000毫秒,則rolling window會被分成n個buckets蜗帜,
每個bucket包含success恋拷,failure,timeout厅缺,rejection的次數(shù)的統(tǒng)計信息蔬顾。默認(rèn)10000
**/
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000")},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "15"),
/**
* BlockingQueue的最大隊列數(shù),當(dāng)設(shè)為-1湘捎,會使用SynchronousQueue诀豁,值為正時使用LinkedBlcokingQueue。
*/
@HystrixProperty(name = "maxQueueSize", value = "15"),
/**
* 設(shè)置存活時間窥妇,單位分鐘舷胜。如果coreSize小于maximumSize,那么該屬性控制一個線程從實用完成到被釋放的時間.
*/
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
/**
* 設(shè)置隊列拒絕的閾值,即使maxQueueSize還沒有達(dá)到
*/
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000")
})
@GetMapping("/test2")
public String test2() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(1000);
return "test2";
}
private String defaultFail() {
System.out.println("default fail");
return "default fail";
}
}
當(dāng).\ab -c 30 -n 30 http://localhost:8082/hystrix3/test1
并發(fā)30個請求活翩。
由于沒有顯式配置maxQueueSize烹骨。Hystrix不會向阻塞隊列里面放任務(wù)。當(dāng)任務(wù)的數(shù)量超過了線程池負(fù)載的閾值材泄,會采用拒絕任務(wù)策略展氓。核心線程數(shù)量+初始數(shù)量=11個線程。11個線程由于線程阻塞進(jìn)入了Timeout狀態(tài)脸爱,后續(xù)無法正常繼續(xù)執(zhí)行其他任務(wù),采取拒絕任務(wù)策略(拒絕了30-11=19個任務(wù))未妹。
此時服務(wù)進(jìn)入到熔斷狀態(tài)簿废,在5s之后,我們再發(fā)送http://localhost:8082/hystrix3/test1
請求络它,發(fā)現(xiàn)還是處于timeout狀態(tài)族檬,依舊是失敗,繼續(xù)保持熔斷狀態(tài)化戳。
后續(xù)再發(fā)送http://localhost:8082/hystrix3/test1
請求单料,該請求已經(jīng)進(jìn)入到熔斷處理。
maxQueueSize:作業(yè)隊列的最大值点楼,默認(rèn)值為 -1扫尖,設(shè)置為此值時,隊列會使用 SynchronousQueue掠廓,此時其 size 為0换怖。
Hystrix 不會向隊列內(nèi)存放作業(yè)。如果此值設(shè)置為一個正的 int 型蟀瞧,隊列會使用一個固定 size 的 LinkedBlockingQueue沉颂。
此時在核心線程池內(nèi)的線程都在忙碌時条摸,會將作業(yè)暫時存放在此隊列內(nèi),但超出此隊列的請求依然會被拒絕铸屉。
queueSizeRejectionThreshold:由于 maxQueueSize 值在線程池被創(chuàng)建后就固定了大小钉蒲,
如果需要動態(tài)修改隊列長度的話可以設(shè)置此值,
即使隊列未滿彻坛,隊列內(nèi)作業(yè)達(dá)到此值時同樣會拒絕請求顷啼。
此值默認(rèn)是 5,所以有時候只設(shè)置了 maxQueueSize 也不會起作用小压。
當(dāng).\ab -c 100 -n 100 http://localhost:8082/hystrix3/test2
并發(fā)100個請求线梗。核心線程數(shù)是15個,加上初始的1個怠益。核心線程數(shù)應(yīng)該是16個仪搔,阻塞隊列里面有15個。所以executions為31個蜻牢。當(dāng)線程數(shù)超過了阻塞隊列的閾值烤咧,就拒絕任務(wù),所以Rejected的數(shù)量是100-31=69個抢呆。默認(rèn)情況下煮嫌,在滑動窗口內(nèi),請求數(shù)量超過了20個抱虐,才計算熔斷錯誤比率昌阿。當(dāng)熔斷錯誤比率超過了50%,采用熔斷策略恳邀。