一屡律、前言
“不好了腌逢,線上服務(wù)器超時嚴(yán)重,請求非常慢超埋,好像報連接數(shù)too many了搏讶,怎么辦?“小伙伴們在反饋霍殴。一般我們的技術(shù)老大的處理方式媒惕,把連接數(shù)和線程池調(diào)大點,重啟繁成,再觀察吓笙。
往往這個方式是應(yīng)急措施,治標(biāo)不治本巾腕,因為不知道問題的原因。
有個嚴(yán)重誤區(qū)絮蒿,以為線程池設(shè)置太小了尊搬,調(diào)大點請求就會快了。
今天就帶著小伙伴們溝通一下土涝,線程池的大小應(yīng)該如何合理的設(shè)置其大蟹鹗佟?
二但壮、問題
如果有兩個任務(wù)需要處理冀泻,一個任務(wù)A,一個任務(wù)B
方案一:一個線程執(zhí)行任務(wù)A和B蜡饵,A執(zhí)行完后弹渔,執(zhí)行B
方案二:兩個線程A和B去執(zhí)行任務(wù)A 和 B,同時進(jìn)行
哪個方案會快點溯祸?應(yīng)該很多人會回答肢专,肯定是方案二啊舞肆,多線程并行去處理任務(wù)A和B,肯定快啊博杖。是這樣嗎椿胯?回答這個問題之前,先帶著大家去回顧梳理一下剃根。
三哩盲、線程執(zhí)行
線程的執(zhí)行,是由CPU進(jìn)行調(diào)度的狈醉,一個CPU在同一時刻只會執(zhí)行一個線程廉油,我們看上去的線程A 和 線程B并發(fā)執(zhí)行。
為了讓用戶感覺這些任務(wù)正在同時進(jìn)行舔糖,操作系統(tǒng)利用了時間片輪轉(zhuǎn)的方式娱两,CPU給每個任務(wù)都服務(wù)一定的時間,然后把當(dāng)前任務(wù)的狀態(tài)保存下來金吗,在加載下一任務(wù)的狀態(tài)后十兢,繼續(xù)服務(wù)下一任務(wù)。任務(wù)的狀態(tài)保存及再加載摇庙,這段過程就叫做上下文切換旱物。
上下文切換過程是需要時間的;現(xiàn)在我們來看一下上面的問題卫袒,小伙伴們再看一下是哪個方案快呢宵呛?是不是有些小伙伴們會說方案一,因為不需要線程切換夕凝;方案二需要來回切換這兩個線程宝穗,耗時會多點。
小伙伴們心中此時是不是會有疑惑码秉,那為什么會有多線程逮矛?先不急,再往下看转砖。
四须鼎、為什么要多線程
小伙伴想想在我們真實業(yè)務(wù)中,我們是什么流程府蔗?
上圖的流程:
1晋控、先發(fā)起網(wǎng)絡(luò)請求
2、Web服務(wù)器解析請求
3姓赤、請求后端的數(shù)據(jù)庫獲取數(shù)據(jù)
4赡译、獲取數(shù)據(jù)后,進(jìn)行處理
5模捂、把處理結(jié)果放回給用戶
這個是我們處理業(yè)務(wù)的時候捶朵,常規(guī)的請求流程蜘矢;我們看一下整個過程涉及到什么計算機(jī)處理。
1综看、網(wǎng)絡(luò)請求----->網(wǎng)絡(luò)IO
2品腹、解析請求----->CPU
3、請求數(shù)據(jù)庫----->網(wǎng)絡(luò)IO
4红碑、MySQL查詢數(shù)據(jù)----->磁盤IO
5舞吭、MySQL返回數(shù)據(jù)----->網(wǎng)絡(luò)IO
6、數(shù)據(jù)處理----->CPU
7析珊、返回數(shù)據(jù)給用戶----->網(wǎng)絡(luò)IO
講到這里羡鸥,小伙伴們是不是感覺又不亂了,在真實業(yè)務(wù)中我們不單單會涉及CPU計算忠寻,還有網(wǎng)絡(luò)IO和磁盤IO處理惧浴,這些處理是非常耗時的。如果一個線程整個流程是上圖的流程奕剃,真正涉及到CPU的只有2個節(jié)點衷旅,其他的節(jié)點都是IO處理,那么線程在做IO處理的時候纵朋,CPU就空閑出來了柿顶,CPU的利用率就不高。
小伙伴們現(xiàn)在知道多線程的用處了吧操软,對嘁锯,就是為了提升CPU利用率。
五聂薪、提升QPS/TPS
衡量系統(tǒng)性能如何家乘,主要指標(biāo)系統(tǒng)的(QPS/TPS)
QPS/TPS:每秒能夠處理請求/事務(wù)的數(shù)量
并發(fā)數(shù):系統(tǒng)同時處理的請求/事務(wù)的數(shù)量
響應(yīng)時間:就是平均處理一個請求/事務(wù)需要時長
QPS/TPS = 并發(fā)數(shù)/響應(yīng)時間
上面公式代表并發(fā)數(shù)越大,QPS就越大藏澳;所以很多人就會以為調(diào)大線程池烤低,并發(fā)數(shù)就會大,也會提升QPS笆载,所以才會出現(xiàn)一開始前言所說的,大多數(shù)人的誤區(qū)涯呻。
其實QPS還跟響應(yīng)時間成反比凉驻,響應(yīng)時間越大,QPS就會越小复罐。
雖然并發(fā)數(shù)調(diào)大了涝登,就會提升QPS,但線程數(shù)也會影響響應(yīng)時間效诅,因為上面我們也提到了上下文切換的問題胀滚,那怎么設(shè)置線程數(shù)的呢趟济?
六、如何設(shè)置線程數(shù)
那我們?nèi)绾畏峙渚€程咽笼?我們提供一個公式:
最佳線程數(shù)目 = ((線程等待時間+線程CPU時間)/線程CPU時間 )* CPU數(shù)目
備注這個公式也是前輩們分享的顷编,當(dāng)然之前看了淘寶前臺系統(tǒng)優(yōu)化實踐的文章,和上面的公式很類似剑刑,不過在CPU數(shù)目那邊媳纬,他們更細(xì)化了,上面的公式只是參考施掏。不過不管什么公式钮惠,最終還是在生產(chǎn)環(huán)境中運(yùn)行后,再優(yōu)化調(diào)整七芭。
我們繼續(xù)上面的任務(wù)素挽,我們的服務(wù)器CPU核數(shù)為4核,一個任務(wù)線程cpu耗時為20ms狸驳,線程等待(網(wǎng)絡(luò)IO预明、磁盤IO)耗時80ms,那最佳線程數(shù)目:( 80 + 20 )/20 * 4 = 20锌历。也就是設(shè)置20個線程數(shù)最佳贮庞。
從這個公式上面我們就得出,線程的等待時間越大究西,線程數(shù)就要設(shè)置越大窗慎,這個正好符合我們上面的分析,可提升CPU利用率卤材。那從另一個角度上面說遮斥,線程數(shù)設(shè)置多大,是根據(jù)我們自身的業(yè)務(wù)的扇丛,需要自己去壓力測試术吗,設(shè)置一個合理的數(shù)值。
七帆精、基礎(chǔ)常規(guī)標(biāo)準(zhǔn)
那我們小伙伴們會問较屿,因為很多業(yè)務(wù)集中到一個線程池中,不像上面的案例比較簡單卓练,事實上業(yè)務(wù)太多隘蝎,怎么設(shè)置呢?這個就是要去壓力測試去調(diào)整襟企。不過我們的前輩已經(jīng)幫我們總結(jié)了一個基礎(chǔ)的值(最終還是要看運(yùn)行情況自行調(diào)整)
1嘱么、CPU密集型:操作內(nèi)存處理的業(yè)務(wù),一般線程數(shù)設(shè)置為:CPU核數(shù) + 1 或者 CPU核數(shù)*2顽悼。核數(shù)為4的話曼振,一般設(shè)置 5 或 8
2几迄、IO密集型:文件操作,網(wǎng)絡(luò)操作冰评,數(shù)據(jù)庫操作映胁,一般線程設(shè)置為:cpu核數(shù) / (1-0.9),核數(shù)為4的話集索,一般設(shè)置 40
八屿愚、總結(jié)
今天介紹了線程數(shù)大小的設(shè)置,一些小伙伴們的誤區(qū)务荆。講到這里我們小伙伴們是不是對線程有了更新的理解妆距,不像之前那么粗暴,應(yīng)該要去分析為什么這么慢函匕,系統(tǒng)的瓶頸出現(xiàn)在什么地方娱据,減少瓶頸的耗時。
另外盅惜,推薦小伙伴們再去看一下Redis中剩、Nginx;為什么他們會那么快呢抒寂?其實和這篇文章的知識點有共同的地方结啼。