先談?wù)剄ps蚯姆,rt和線程數(shù)的關(guān)系
單機(jī)單線程能夠處理的最大qps為1000ms/rt(拋開cpu利用率等等其他的因素)
比如任務(wù)的rt為100ms爹袁,那么單機(jī)單線程理論上能夠處理的最大值為10qps
對于多線程場景碌廓,最大qps =(1000/rt)* coreSize * cpu利用率忿磅。(假定統(tǒng)一設(shè)置coreSize=maxSize)
比如我的dubbo服務(wù),默認(rèn)最大線程池為200条霜,那么最大qps =(1000/rt)* 200 * cpu利用率
注意:rt在不同并發(fā)度下的表現(xiàn)可能不一樣间雀。
可以參考看看這篇文章悔详,講得比較清楚: https://blog.csdn.net/sinat_34976604/article/details/88125707
再談?wù)劸€程數(shù)和系統(tǒng)最大并發(fā)數(shù)的關(guān)系
假設(shè)服務(wù)端只有10個線程,同一時刻有16個請求并發(fā)打過來惹挟,這時系統(tǒng)會將10個請求立刻執(zhí)行茄螃,另外6個請求則需要在queue中等待。
只有當(dāng)有一個線程執(zhí)行完连锯,可以理解為線程空了一個槽位归苍,才會執(zhí)行在queue中排隊的一個任務(wù)。所以線程數(shù)決定了系統(tǒng)中在同一時刻最大并行的任務(wù)數(shù)运怖,也就是最大并發(fā)數(shù)拼弃。 如果我們想要讓一個線程在一秒內(nèi)處理多個請求,后面的請求勢必要在隊列中等待摇展。
進(jìn)入正題
1. 為什么要使用線程隔離吻氧?
為了避免由個別下游依賴出現(xiàn)問題,影響其他依賴的使用資源,占用大量線程資源医男,導(dǎo)致鏈路rt升高砸狞,進(jìn)而造成雪崩效應(yīng)
2. 怎么配置核心線程數(shù)捻勉?
coreSize = qps / (timout/rt)
qps:打到下游最大的qps镀梭, timeout:對下游能夠忍受的最大rt, rt:下游rt
-
公式解析
這個公式直接拿出來可能不太好理解踱启,沒關(guān)系报账,我們先看前人總結(jié)的公式,我對這個公式進(jìn)行了優(yōu)化
原始版本:
coreSize=qps * rt + buffer 我們先拋開buffer這一項來看埠偿,這個等式等價于coreSize= qps / (1000/rt)
很容易想到透罢,這個計算思路就是: qps除以單線程能夠處理的最大qps,得出的就是所需要的線程數(shù)
-
網(wǎng)上已有公式冠蒋,為什么還要提出這個變種的公式呢羽圃?
- 按1000ms打滿算,但是我的業(yè)務(wù)并不允許一個20ms的請求抖剿,排隊執(zhí)行等到1000ms才返回
- 公式里面簡單粗暴的+buffer朽寞,每個下游處理情況不一樣要怎么加buffer呢?心里是不是沒譜
-
優(yōu)化分析
很容易發(fā)現(xiàn)斩郎,優(yōu)化后的公式與原公式的差別是將1000變量化了脑融,可以根據(jù)各個業(yè)務(wù)場景適配。timeout/rt還是一個線程需要分擔(dān)的qps缩宜,但是這樣可以量化到最排隊在最后的任務(wù)也不會超過timeout這個時間肘迎。而不是簡單粗暴的對coreSize加buffer
線程池coresize.png
3. 如何配置隊列大小锻煌?
queueSize = 最大并發(fā)數(shù) - coreSize
-
為什么是最大并發(fā)數(shù)而不是qps?
舉個例子妓布,我們dubbo服務(wù)最大線程數(shù)200,此時260個請求同時打過來宋梧,只有200個請求能夠立即執(zhí)行匣沼。
假設(shè)對下游的調(diào)用是1:1的,那么打到下游最大的并發(fā)數(shù)也是200乃秀,只有下游執(zhí)行成功一個肛著,下游隔離的線程池空了一個位置,并且這個請求做完剩下所有的事情成功返回跺讯,才會將隊列中的等待的60個請求漏一個下來枢贿。
所以我們只要保證我的隔離線程池每時每刻都能夠承接下最大的并發(fā)數(shù)即可。
服務(wù)并發(fā)處理情況.png
4. 對每個下游獨(dú)立線程池開銷很大刀脏,有沒有辦法優(yōu)化局荚?
-
滿足 同一來源 && 不會同時執(zhí)行 這兩個特征的下游依賴,可以考慮合并線程池管理
比如系統(tǒng)對A和B兩個下游接口依賴,如果A B都只在同一個中調(diào)用耀态,并且這個接口對A和B的執(zhí)行一定是串行的轮傍,那么可以將這兩個接口的線程池合并。
線程池合并.png可以看到執(zhí)行完A空閑的時候首装,線程池可以處理另一個request的B创夜,這樣可以提高線程池的利用率
需要注意的是代入公式計算的時候粥航,可以把A和B看成一個整體漓柑,將AB的rt之和代入計算。
性能壓測驗證
-
壓測場景
購物車加購履腋,目標(biāo)qps260系奉,配置下游線程池coreSize:87檬贰,queue:120
爬坡1分鐘,持續(xù)10分鐘
-
壓測表現(xiàn)
-
未開啟hystrix缺亮,平均rt 70ms
未開啟 加購壓測數(shù)據(jù).png
-
-
開啟hystrix之后翁涤,平均rt 69ms
開啟后加購壓測數(shù)據(jù).png
-
是不是納悶加入了排隊機(jī)制rt不升反降了?
我們來看看壓測期間下游rt情況
-
未開啟hystrix萌踱,下游rt 29.24ms
未開啟下游rt情況.png -
開啟hystrix后葵礼,下游rt 28.92ms
開啟下游rt情況.png
-
-
結(jié)論
對下游的并發(fā)度,會影響下游的處理能力虫蝶,如果配置的線程數(shù)是 下游并發(fā)處理能力的拐點(diǎn)時章咧,這時候的效果應(yīng)該會比較好。所以想要滿足要求的線程池配置通過上面的公式很容易配置能真,但是對下游并發(fā)度的控制赁严,也就是timeout的取值,就需要壓測慢慢調(diào)粉铐,才能拿到最優(yōu)的參數(shù)了疼约。
引申思考
線程池隔離的思想也能夠用來做限流, 對某個接口分配一個線程池蝙泼,以線程池大小來控制這個接口的最大并發(fā)量程剥。理論上對應(yīng)限制的qps可以認(rèn)為是(1000/rt) * coreSize