執行緒數,512是否合理?

ITPUB社群發表於2022-12-27

Web-Server有個配置,工作執行緒數。
Service一般也有個配置,工作執行緒數。

經驗豐富的架構師,懂得如何配置這些引數,使得系統的效能達到最優:有些業務設定為CPU核數的2倍,有些業務設定為CPU核數的8倍,有些業務設定為CPU核數的32倍。

“執行緒數”的設定依據,是本文要討論的問題。

工作執行緒數是不是設定的越大越好?
答案顯然是否定的
(1)伺服器CPU核數有限,能夠同時併發的執行緒數有限,單核CPU設定1000個工作執行緒沒有意義;
(2)執行緒切換有開銷,如果執行緒切換過於頻繁,反而會使效能降低;
 
呼叫sleep()函式的時候,執行緒是否一直佔用CPU?
不佔用,休眠時會把CPU讓出來,給其他需要CPU資源的執行緒使用。

不止sleep,一些阻塞呼叫,例如網路程式設計中的:
(1)阻塞accept(),等待客戶端連線;
(2)阻塞recv(),等待下游回包;
都會讓出CPU資源

單核CPU,設定多執行緒有意義麼?
單核CPU,設定多執行緒能否提高併發效能?
即使是單核,使用多執行緒也是有意義的,大多數情況也能提高併發
(1)多執行緒編碼可以讓程式碼更加清晰,例如:IO執行緒收發包,Worker執行緒進行任務處理,Timeout執行緒進行超時檢測;
(2)如果有一個任務一直佔用CPU資源在進行計算,此時增加執行緒並不能增加併發,例如以下程式碼會一直佔用CPU,並使得CPU佔用率達到100%:
 while(1){ i++; }
(3)通常來說,Worker執行緒一般不會一直佔用CPU進行計算,此時即使CPU是單核,增加Worker執行緒也能夠提高併發,因為這個執行緒在休息的時候,其他的執行緒可以繼續工作;
 

常見服務執行緒模型有幾種?

瞭解常見的服務執行緒模型,有助於理解服務併發的原理,一般來說網際網路常見的服務執行緒模型有兩種
(1)IO執行緒工作執行緒透過任務佇列解耦;
(2)純非同步;

第一種,IO執行緒與工作執行緒透過佇列解耦類模型。
執行緒數,512是否合理?
如上圖,大部分Web-Server與服務框架都是使用這樣的一種“IO執行緒與Worker執行緒透過佇列解耦”類執行緒模型:
(1)有少數幾個IO執行緒監聽上游發過來的請求,並進行收發包(生產者);
(2)有一個或者多個任務佇列,作為IO執行緒與Worker執行緒非同步解耦的資料傳輸通道(臨界資源);
(3)有多個工作執行緒執行真正的任務(消費者);

這個執行緒模型應用很廣,符合大部分場景,這個執行緒模型的特點是,工作執行緒內部是同步阻塞執行任務的,因此可以透過增加Worker執行緒數來增加併發能力,今天要討論的重點是“該模型Worker執行緒數設定為多少能達到最大的併發”。
 
第二種,純非同步執行緒模型。
沒有阻塞,這種執行緒模型只需要設定很少的執行緒數就能夠做到很高的吞吐量,該模型的缺點是:
(1)如果使用單執行緒模式,難以利用多CPU多核的優勢;
(2)程式設計師更習慣寫同步程式碼,callback的方式對程式碼的可讀性有衝擊,對程式設計師的要求也更高;
(3)框架更復雜,往往需要server端收發元件,server端佇列,client端收發元件,client端佇列,上下文管理元件,有限狀態機元件,超時管理元件的支援;

however,這個模型不是今天討論的重點。
 

第一類“IO執行緒與工作執行緒透過佇列解耦”類執行緒模型,工作執行緒的工作模式是怎麼樣的?

瞭解工作執行緒的工作模式,對量化分析執行緒數的設定非常有幫助:
執行緒數,512是否合理?
上圖是一個典型的工作執行緒的處理過程,從開始處理start到結束處理end,該任務的處理共有7個步驟:
(1)從工作佇列裡拿出任務,進行一些本地初始化計算,例如http協議分析、引數解析、引數校驗等;
(2)訪問cache拿一些資料;
(3)拿到cache裡的資料後,再進行一些本地計算,這些計算和業務邏輯相關;
(4)透過RPC呼叫下游service再拿一些資料,或者讓下游service去處理一些相關的任務;
(5)RPC呼叫結束後,再進行一些本地計算,怎麼計算和業務邏輯相關;
(6)訪問DB進行一些資料操作;
(7)操作完資料庫之後做一些收尾工作,同樣這些收尾工作也是本地計算,和業務邏輯相關;
 
分析整個處理的時間軸,會發現:
(1)其中1,3,5,7步驟中(上圖中粉色時間軸),執行緒進行本地業務邏輯計算需要佔用CPU;
(2)而2,4,6步驟中(上圖中橙色時間軸),訪問cache、service、DB過程中執行緒處於一個等待結果的狀態不需要佔用CPU,進一步的分解,這個“等待結果”的時間共分為三部分:
2.1)請求在網路上傳輸到下游的cache、service、DB;
2.2)下游cache、service、DB進行任務處理;
2.3)cache、service、DB將報文在網路上傳回工作執行緒;
 

如何量化分析,併合理設定工作執行緒數呢?

透過上面的分析,Worker執行緒在執行的過程中:
(1)有一部計算時間需要佔用CPU;
(2)另一部分等待時間不需要佔用CPU;

透過量化分析,例如打日誌進行統計,可以統計出整個Worker執行緒執行過程中這兩部分時間的比例,例如:
(1)執行計算,佔用CPU的時間(粉色時間軸)是100ms;
(2)等待時間,不佔用CPU的時間(橙色時間軸)也是100ms;

得到的結果是,這個執行緒計算和等待的時間是1:1,即有50%的時間在計算(佔用CPU),50%的時間在等待(不佔用CPU):
(1)假設此時是單核,則設定為2個工作執行緒就可以把CPU充分利用起來,讓CPU跑到100%;
(2)假設此時是N核,則設定為2N個工作現場就可以把CPU充分利用起來,讓CPU跑到N*100%;
 
噹噹噹當!!!

結論來了
N核伺服器,透過執行業務的單執行緒分析出本地計算時間x等待時間y,則工作執行緒數(執行緒池執行緒數)設定為 N*(x+y)/x,能讓CPU的利用率最大化。

一般來說,非CPU密集型的業務(加解密、壓縮解壓縮、搜尋排序等業務是CPU密集型的業務),瓶頸都在後端資料庫訪問或者RPC呼叫,本地CPU計算的時間很少,所以設定幾十或者幾百個工作執行緒是能夠提升吞吐量的。
《頂尖的人都是怎麼想的!(很殘酷)》

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2929656/,如需轉載,請註明出處,否則將追究法律責任。

相關文章