天天看點

如何決定 Web 應用的線程池大小

在部署 web 應用到生産環境,或者在對 web 應用進行性能測試的時候,經常會有人問:如何決定 web 應用線程池大小?決定一個 IO 阻塞型 web 應用的線程池大小是一項很艱巨的任務。通常是通過進行大量的性能測試來完成。在一個 web 應用中同時擁有多個線程池會讓決定最優線程池大小的過程變得更加複雜。本文将就這個常見的問題進行一些讨論和建議。

線程池

web 應用中的線程池大小決定了在指定時間内能夠處理的并發請求數。如果一個 web 應用接收到的請求數高于線程池大小,多出來的請求将進入隊列等待,或被拒絕。

請注意并發和并行不是一個概念。并發請求指的是正在進行中的請求數量,在某個時間點,隻有其中的一小部分能夠得到 CPU 執行。而并行請求指的是正在處理的請求數量,在某個時間點,所有請求都在被 CPU 執行。

在非阻塞型 IO 應用中,比如 NodeJS,單個線程(程序)能夠同時處理多個請求。多核 CPU 處理器下,通過增加線程或程序數能夠處理并行請求。

在阻塞型 IO 應用中,比如 SpringMVC,單個線程隻能同時處理一個請求。要同時處理多個并發請求的話,我們必須增加線程數量。

計算密集型應用

在計算密集型應用中,線程池的大小應該等同于主機中 CPU 的數量。再添加更多線程将會打斷請求的處理,因為線程的上下文切換也會延遲響應時間。

非阻塞型 IO 應用将會是 CPU 密集型的,因為在請求得到處理的時候沒有線程等待時間。

IO 等待應用

決定 IO 等待應用的線程池大小會由于依賴于下遊系統的響應時間而變得更加複雜,因為一個線程在其他系統響應之前始終是阻塞的。我們不得不像《​​應答者模式:I/O 阻塞型應用​​》中讨論的那樣去增加線程的數量以提高 CPU 使用率。

利特爾法則

利特爾法則應用于非技術領域,比如銀行,以估算處理進入銀行客戶所需要的銀行出納櫃台的數量。

利特爾法則:

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

适用于 web 應用的利特爾法則:

一個系統中線程的平均數量(Threads),等于 web 請求的到達速率(WebRequests per sec),與平均每個處理的響應時間(ResponseTime)的乘積。

Threads = 線程的數量

WebRequests per sec = 一秒内能夠處理的 web 請求數

ResponseTime = 處理一次 web 請求所需要的時間

Threads = (WebRequests/sec) X ResponseTime

盡管上邊這個公式提供了處理進入請求的線程個數,它并沒有提供線程數和 CPU 核心數之間的比率資訊,比如一個 x 個 CPU 的主機需要配置設定多少個線程。

測試決定線程池大小

要找出合适的線程池大小,需要在吞吐量和響應時間之間進行權衡。先以一個最小值開始測試:一個 CPU 一個線程(也就是線程池大小 = CPU 個數),應用線程池大小與下遊系統平均響應時間成正比增長,直到 CPU 使用率飽和或者響應時間開始退化為止。

下圖指出了請求數、CPU 以及響應時間等名額之間的關聯關系。

CPU Vs 請求數示範了在增加 web 應用負載時的 CPU 使用率。

響應時間 Vs 請求數圖示範了增加 web 應用負載對響應時間的影響。

綠點指出了最佳吞吐量和響應時間。

線程池大小 = CPU 個數

如何決定 Web 應用的線程池大小

上圖描述的是 IO 等待型應用線上程數等于 CPU 數時的情況。應用的線程在等待下遊系統響應時發生了阻塞。由于線程都阻塞住了,系統響應時間因請求進入等待隊列而被拉長。由于所有線程都處于阻塞狀态,應用開始拒絕請求,盡管 CPU 使用率還很低。

線程池很大

如何決定 Web 應用的線程池大小

上圖描述的是 IO 等待型應用在 web 應用中建立了很多線程的情況。由于有很多數量的線程,線程的上下文切換将會很頻繁。由于不必要的線程上下文切換,盡管吞吐量還沒升上去的時候應用的 CPU 使用率就已經很高了。響應時間由于被請求的處理被線程的上下文切換所打斷而被拉長。

最佳線程池大小

如何決定 Web 應用的線程池大小

上圖描述的是 IO 等待型應用在 web 應用中建立了合理數量的線程的情況。CPU 得到了有效利用,具備良好的吞吐量和較少的線程上下文切換。我們可以看到由于更少的打斷(上下文切換),請求處理更加有效,應用有一個良好的響應時間。

線程池隔離

對于大多數 web 應用而言,隻有少數幾種類型的 web 請求會花費比較長的處理時間。這些慢的請求處理可能會拖累所有線程,并降低整個應用的性能。

處理這種問題的兩個方案是:

  • 為慢處理的 web 請求設定在一台獨立的主機;
  • 在同一個應用中為慢處理的 web 請求配置設定一個獨立的線程池;

決定一個 IO 阻塞型 web 應用的線程池大小是一項很艱巨的任務。通常是通過進行大量的性能測試來完成。在一個 web 應用中同時擁有多個線程池會讓決定最優線程池大小的過程變得更加複雜。

原文連結:

​​http://venkateshcm.com/2014/05/How-To-Determine-Web-Applications-Thread-Poll-Size/​​。

繼續閱讀