0 Github
資源隔離兩種策略
- 線程池隔離
- 信號(hào)量隔離
對(duì)于資源隔離,做更加深入一些的講解扛稽,除了可以選擇隔離策略,對(duì)選擇的隔離策略,可以做一定的細(xì)粒度的控制
1 execution.isolation.strategy
指定HystrixCommand.run()的資源隔離策略
- THREAD
基于線程池
// to use thread isolation
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)
- SEMAPHORE
基于信號(hào)量// to use semaphore isolation
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)線程池機(jī)制谜疤,每個(gè)command運(yùn)行在一個(gè)線程中,限流是通過(guò)線程池的大小來(lái)控制的
信號(hào)量機(jī)制,command是運(yùn)行在調(diào)用線程中夷磕,但是通過(guò)信號(hào)量的容量來(lái)進(jìn)行限流
如何在線程池和信號(hào)量之間做選擇呢履肃?
默認(rèn)的策略為線程池
線程池其實(shí)最大的好處就是對(duì)于網(wǎng)絡(luò)訪問(wèn)請(qǐng)求,若超時(shí)坐桩,可以避免調(diào)用線程阻塞住
而使用信號(hào)量的場(chǎng)景尺棋,通常是針對(duì)超大并發(fā)量的場(chǎng)景下,每個(gè)服務(wù)實(shí)例每秒都幾百的QPS
此時(shí)用線程池绵跷,線程一般不會(huì)太多膘螟,可能撐不住那么高的并發(fā)
要撐住,可能要耗費(fèi)大量的線程資源碾局,那么就是用信號(hào)量荆残,來(lái)限流保護(hù)
一般用信號(hào)量常見(jiàn)于那種基于純內(nèi)存的一些業(yè)務(wù)邏輯服務(wù),而不涉及到任何網(wǎng)絡(luò)訪問(wèn)請(qǐng)求
netflix有100+的command運(yùn)行在40+的線程池中净当,只有少數(shù)command是不運(yùn)行在線程池中的内斯,就是從純內(nèi)存中獲取一些元數(shù)據(jù),或者是對(duì)多個(gè)command包裝起來(lái)的facacde command像啼,是用信號(hào)量限流的
2 command名稱 & command組
線程池隔離嘿期,依賴服務(wù)->接口->線程池魁莉,如何來(lái)劃分
每個(gè)command随闺,都可以設(shè)置一個(gè)自己的名稱,同時(shí)可以設(shè)置一個(gè)自己的組
private static final Setter cachedSetter =
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"));
public CommandHelloWorld(String name) {
super(cachedSetter);
this.name = name;
}
- command group
一個(gè)非常重要的概念爆班,默認(rèn)情況下甚颂,因?yàn)榫褪峭ㄟ^(guò)command group來(lái)定義一個(gè)線程池的蜜猾,而且還會(huì)通過(guò)command group來(lái)聚合一些監(jiān)控和報(bào)警信息
同一個(gè)command group中的請(qǐng)求,都會(huì)進(jìn)入同一個(gè)線程池中
3 command線程池
ThreadPoolKey代表了一個(gè)HystrixThreadPool振诬,用來(lái)進(jìn)行統(tǒng)一監(jiān)控蹭睡,統(tǒng)計(jì),緩存
默認(rèn)的threadpool key就是command group名稱
每個(gè)command都會(huì)跟它的ThreadPoolKey對(duì)應(yīng)的ThreadPool綁定
如果不想直接用command group赶么,也可以手動(dòng)設(shè)置thread pool name
public CommandHelloWorld(String name) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
this.name = name;
}
command threadpool => command group => command key
-
command key
代表了一類command肩豁,代表底層的依賴服務(wù)的一個(gè)接口
-
command group
代表了某一個(gè)底層的依賴服務(wù),合理辫呻,一個(gè)依賴服務(wù)可能會(huì)暴露出來(lái)多個(gè)接口清钥,每個(gè)接口就是一個(gè)command key
command group
在邏輯上去組織起來(lái)一堆command key的調(diào)用,統(tǒng)計(jì)信息放闺,成功次數(shù)祟昭,timeout超時(shí)次數(shù),失敗次數(shù)怖侦,可以看到某一個(gè)服務(wù)整體的一些訪問(wèn)情況
推薦是根據(jù)一個(gè)服務(wù)去劃分出一個(gè)線程池篡悟,command key默認(rèn)都是屬于同一個(gè)線程池的
比如說(shuō)你以一個(gè)服務(wù)為粒度谜叹,估算出來(lái)這個(gè)服務(wù)每秒的所有接口加起來(lái)的整體QPS在100左右
你調(diào)用那個(gè)服務(wù)的當(dāng)前服務(wù),部署了10個(gè)服務(wù)實(shí)例搬葬,每個(gè)服務(wù)實(shí)例上荷腊,其實(shí)用這個(gè)command group對(duì)應(yīng)這個(gè)服務(wù),給一個(gè)線程池急凰,量大概在10個(gè)左右停局,就可以了,你對(duì)整個(gè)服務(wù)的整體的訪問(wèn)QPS大概在每秒100左右
一般來(lái)說(shuō)香府,command group是用來(lái)在邏輯上組合一堆command的
舉個(gè)例子董栽,對(duì)于一個(gè)服務(wù)中的某個(gè)功能模塊來(lái)說(shuō),希望將這個(gè)功能模塊內(nèi)的所有command放在一個(gè)group中企孩,那么在監(jiān)控和報(bào)警的時(shí)候可以放一起看
command group锭碳,對(duì)應(yīng)了一個(gè)服務(wù),但是這個(gè)服務(wù)暴露出來(lái)的幾個(gè)接口勿璃,訪問(wèn)量很不一樣擒抛,差異非常之大
你可能就希望在這個(gè)服務(wù)command group內(nèi)部,包含的對(duì)應(yīng)多個(gè)接口的command key补疑,做一些細(xì)粒度的資源隔離
對(duì)同一個(gè)服務(wù)的不同接口歧沪,都使用不同的線程池
command key -> command group
command key -> 自己的threadpool key
邏輯上來(lái)說(shuō),多個(gè)command key屬于一個(gè)command group莲组,在做統(tǒng)計(jì)的時(shí)候诊胞,會(huì)放在一起統(tǒng)計(jì)
每個(gè)command key有自己的線程池,每個(gè)接口有自己的線程池锹杈,去做資源隔離和限流
但對(duì)于thread pool資源隔離來(lái)說(shuō)撵孤,可能是希望能夠拆分的更加一致一些,比如在一個(gè)功能模塊內(nèi)竭望,對(duì)不同的請(qǐng)求可以使用不同的thread pool
command group一般來(lái)說(shuō)邪码,可以是對(duì)應(yīng)一個(gè)服務(wù),多個(gè)command key對(duì)應(yīng)這個(gè)服務(wù)的多個(gè)接口咬清,多個(gè)接口的調(diào)用共享同一個(gè)線程池
如果說(shuō)你的command key闭专,要用自己的線程池,可以定義自己的threadpool key旧烧,就ok了
4 coreSize
設(shè)置線程池的大小影钉,默認(rèn)是10
HystrixThreadPoolProperties.Setter()
.withCoreSize(int value)
一般來(lái)說(shuō),用這個(gè)默認(rèn)的10個(gè)線程大小就夠了
5 queueSizeRejectionThreshold
控制queue滿后reject的threshold粪滤,因?yàn)閙axQueueSize不允許熱修改斧拍,因此提供這個(gè)參數(shù)可以熱修改,控制隊(duì)列的最大值
HystrixCommand在提交到線程池之前杖小,其實(shí)會(huì)先進(jìn)入一個(gè)隊(duì)列中肆汹,這個(gè)隊(duì)列滿了之后,才會(huì)reject
默認(rèn)值是5
HystrixThreadPoolProperties.Setter()
.withQueueSizeRejectionThreshold(int value)
-
線程池+queue的工作原理
6 isolation.semaphore.maxConcurrentRequests
設(shè)置使用SEMAPHORE隔離策略的時(shí)候予权,允許訪問(wèn)的最大并發(fā)量昂勉,超過(guò)這個(gè)最大并發(fā)量,請(qǐng)求直接被reject
這個(gè)并發(fā)量的設(shè)置扫腺,跟線程池大小的設(shè)置岗照,應(yīng)該是類似的
但是基于信號(hào)量的話,性能會(huì)好很多笆环,而且hystrix框架本身的開(kāi)銷會(huì)小很多
默認(rèn)值是10攒至,設(shè)置的小一些,否則因?yàn)樾盘?hào)量是基于調(diào)用線程去執(zhí)行command的躁劣,而且不能從timeout中抽離迫吐,因此一旦設(shè)置的太大,而且有延時(shí)發(fā)生账忘,可能瞬間導(dǎo)致tomcat本身的線程資源本占滿
參考
- 《Java工程師面試突擊第1季-中華石杉老師》