Web應用擴充套件系列(2):如何確定Web應用執行緒池的大小

熊崽Kevin發表於2014-06-25

繼續上篇博文《Web應用擴充套件系列(1):架構篇》,本文中將會介紹一個Web應用擴充套件過程中的常見問題,即如何設定web應用執行緒池的大小,這經常在部署生產環境以及測試web應用效能的時候遇到。

執行緒池

對於Web應用而言,執行緒池的大小決定了同一時刻能夠被處理的併發(Concurrent)請求的個數。如果一個Web應用在執行時收到了多於執行緒池大小的請求,那麼多出來的請求要麼被丟棄,要麼會被排隊。

請注意併發(concurrent)與並行(parallel)的區別。併發請求指的是通過分享CPU時間片而不是獨佔CPU而執行的請求;而並行指的是通過在多個處理器上同時執行的請求。

在一些非阻塞IO的應用例如NodeJS之中,一個單執行緒(或程式)能夠併發處理多個請求。而在多核CPU的系統中,並行請求能夠通過增加執行緒或程式來進行處理。

在阻塞IO應用例如Java SpringMVC框架中,一個單執行緒僅僅能夠併發處理一個請求,而為了併發處理多個請求,我們必須增加處理執行緒的數量。

CPU密集型應用

對於CPU密集型應用而言,執行緒池的大小應該等於系統中cpu的數量。更多的執行緒會因為執行緒的上下文切換而中斷當前請求的執行並且增加響應時間。

非阻塞IO應用因為當請求被處理時沒有執行緒的等待時間,所以此時將會變成CPU密集型應用。

IO密集型應用

對於IO密集型應用而言,確定執行緒池的大小相對比較複雜,因為這涉及到下游系統的響應時間,因為一個執行緒常常因為等待其他系統的響應而被阻塞。所以我們必須增加執行緒的數量以更好地利用CPU,正如這篇文章Reactor Pattern Part 1 : Applications with Blocking I/O所提到的。

利特爾法則(Little’s law)

利特爾法則(Little’s law)被廣泛運用於許多非技術領域,例如銀行利用此法則確定服務客戶的銀行櫃檯櫃員的數量。

利特爾法則:在一個穩定的系統中,長時間觀察到的平均顧客數量L,等於,長時間觀察到的有效到達速率λ與平均每個顧客在系統中花費的時間之乘積,即L = λW。

利特爾法則在web app中的應用:一個系統的平均服務執行緒數量(Threads),等於平均請求到達率(WebRequests per sec)乘以平均服務時間(ResponseTime)。

  • Threads = 服務執行緒數量
  • WebRequests per sec = 能夠在一秒鐘內被處理的web請求數量
  • ResponseTime = 處理一個web請求所需的時間

雖然上面的等式指出了處理訪問請求所需執行緒的數量,然而它並未說明執行緒與CPU個數的關係,即在一個擁有x個CPU的系統上為執行緒池分配多少CPU資源更為合理。

確定執行緒池大小的測試

確定執行緒池大小的過程就是在吞吐率以及響應時間之間尋找平衡點。首先從一個CPU一個執行緒開始(執行緒池大小=CPU個數),此時應用的執行緒池大小將會與下游系統的平均響應時間成反比,直到CPU利用率最大化或響應時間不再減少。

下面的幾個圖表展示了請求數量、CPU和響應時間之間的相互關係。

關於CPU和請求個數之間關係的圖展示了當Web應用負載增加時CPU利用率的變化情況。

響應時間和請求數量關係圖展示了增加應用負載所引起的響應時間變化。

綠點展示了理想狀況下的吞吐量和響應時間。

執行緒池大小 = CPU個數

上圖描述了當執行緒數量等於CPU數量IO密集型應用的相關情況。執行緒在等待下游系統響應的時候陷入了阻塞的狀態。響應時間隨著請求開始排隊而不斷增加,這是因為執行緒正在被阻塞。當所有的執行緒都被阻塞及時cpu利用率此時還很低,但應用已經開始拒絕服務。

增大執行緒池

 

上圖展示的是當增大執行緒池的時候IO密集型應用會發生什麼。因為有了更多的執行緒,所以相關的上下文切換將會變得十分頻繁。而cpu利用率即使在吞吐量沒有明顯增加的情況下也會飆升,這是因為多了許多不必要的執行緒切換開銷。響應時間也會增加因為請求因為上下文切換而被打斷了。

理想的執行緒池大小

 

上圖展示了對於IO密集型應用而言最佳的執行緒池大小。CPU能夠得到很有效的利用,吞吐量很客觀並且上下文切換很少。我們可以看到最佳響應時間在有效的請求處理伴隨著很少的上下文切換的情況下出現。

執行緒池隔離

對於大部分Web應用而言,很少有請求會花費比別的請求長得多的時間來處理。最慢的請求也許會佔用所有的執行緒資源並且可能會搞掛整個應用。

對於這個問題有以下一些解決方法:

  • 對於相對而言慢的請求用隔離的系統(應用)來處理
  • 在同一個應用中,分配一個隔離的執行緒池來處理慢請求

如何確定一個IO密集型Web應用的最佳執行緒池大小是一個十分困難的工作,通常需要很多次的實驗才能得出結論。當然了,在應用中增加更多的執行緒池無疑會增加這個過程的難度。

相關文章