詳解tomcat的連線數與執行緒池
1、connector的protocol
connector在處理http請求時,會使用不同的protocol。不同的tomcat版本支援的protocol不同,其中最典型的protocol包括bio、nio和apr(tomcat7中支援這3種,tomcat8增加了對nio2的支援,而到了tomcat8.5和tomcat9.0,則去掉了對bio的支援)。
bio是blocking io,顧名思義是阻塞的io;nio是non-blocking io,則是非阻塞的io。而apr是apache portable runtime,是apache可移植執行庫,利用本地庫可以實現高可擴充套件性、高效能;apr是在tomcat上執行高併發應用的首選模式,但是需要安裝apr、apr-utils、tomcat-native等包。
2、如何指定protocol
connector使用哪種protocol,可以通過元素中的protocol屬性進行指定,也可以使用預設值。
指定的protocol取值及對應的協議如下:
http/1.1:預設值,使用的協議與tomcat版本有關
如果沒有指定protocol,則使用預設值http/1.1,其含義如下:在tomcat7中,自動選取使用bio或apr(如果找到apr需要的本地庫,則使用apr,否則使用bio);在tomcat8中,自動選取使用nio或apr(如果找到apr需要的本地庫,則使用apr,否則使用nio)。
3、bio/nio有何不同
無論是bio,還是nio,connector處理請求的大致流程是一樣的:
在accept佇列中接收連線(當客戶端向伺服器傳送請求時,如果客戶端與os完成三次握手建立了連線,則os將該連線放入accept佇列);在連線中獲取請求的資料,生成request;呼叫servlet容器處理請求;返回response。為了便於後面的說明,首先明確一下連線與請求的關係:連線是tcp層面的(傳輸層),對應socket;請求是http層面的(應用層),必須依賴於tcp的連線實現;乙個tcp連線中可能傳輸多個http請求。
在bio實現的connector中,處理請求的主要實體是jioendpoint物件。jioendpoint維護了acceptor和worker:acceptor接收socket,然後從worker執行緒池中找出空閒的執行緒處理socket,如果worker執行緒池沒有空閒執行緒,則acceptor將阻塞。其中worker是tomcat自帶的執行緒池,如果通過配置了其他執行緒池,原理與worker類似。
acceptor接收socket後,不是直接使用worker中的執行緒處理請求,而是先將請求傳送給了poller,而poller是實現nio的關鍵。acceptor向poller傳送請求通過佇列實現,使用了典型的生產者-消費者模式。在poller中,維護了乙個selector物件;當poller從佇列中取出socket後,註冊到該selector中;然後通過遍歷selector,找出其中可讀的socket,並使用worker中的執行緒處理相應請求。與bio類似,worker也可以被自定義的執行緒池代替。
通過上述過程可以看出,在nioendpoint處理請求的過程中,無論是acceptor接收socket,還是執行緒處理請求,使用的仍然是阻塞方式;但在「讀取socket並交給worker中的執行緒」的這個過程中,使用非阻塞的nio實現,這是nio模式與bio模式的最主要區別(其他區別對效能影響較小,暫時略去不提)。而這個區別,在併發量較大的情形下可以帶來tomcat效率的顯著提公升:
目前大多數http請求使用的是長連線(http/1.1預設keep-alive為true),而長連線意味著,乙個tcp的socket在當前請求結束後,如果沒有新的請求到來,socket不會立馬釋放,而是等timeout後再釋放。如果使用bio,「讀取socket並交給worker中的執行緒」這個過程是阻塞的,也就意味著在socket等待下乙個請求或等待釋放的過程中,處理這個socket的工作執行緒會一直被占用,無法釋放;因此tomcat可以同時處理的socket數目不能超過最大執行緒數,效能受到了極大限制。而使用nio,「讀取socket並交給worker中的執行緒」這個過程是非阻塞的,當socket在等待下乙個請求或等待釋放時,並不會占用工作執行緒,因此tomcat可以同時處理的socket數目遠大於最大執行緒數,併發效能大大提高。
二、3個引數:acceptcount、maxconnections、maxthreads
再回顧一下tomcat處理請求的過程:在accept佇列中接收連線(當客戶端向伺服器傳送請求時,如果客戶端與os完成三次握手建立了連線,則os將該連線放入accept佇列);在連線中獲取請求的資料,生成request;呼叫servlet容器處理請求;返回response。
相對應的,connector中的幾個引數功能如下:
1、acceptcount
accept佇列的長度;當accept佇列中連線的個數達到acceptcount時,佇列滿,進來的請求一律被拒絕。預設值是100。
2、maxconnections
tomcat在任意時刻接收和處理的最大連線數。當tomcat接收的連線數達到maxconnections時,acceptor執行緒不會讀取accept佇列中的連線;這時accept佇列中的執行緒會一直阻塞著,直到tomcat接收的連線數小於maxconnections。如果設定為-1,則連線數不受限制。
預設值與聯結器使用的協議有關:nio的預設值是10000,apr/native的預設值是8192,而bio的預設值為maxthreads(如果配置了executor,則預設值是executor的maxthreads)。
在windows下,apr/native的maxconnections值會自動調整為設定值以下最大的1024的整數倍;如設定為2000,則最大值實際是1024。
3、maxthreads
請求處理執行緒的最大數量。預設值是200(tomcat7和8都是的)。如果該connector繫結了executor,這個值會被忽略,因為該connector將使用繫結的executor,而不是內建的執行緒池來執行任務。
maxthreads規定的是最大的執行緒數目,並不是實際running的cpu數量;實際上,maxthreads的大小比cpu核心數量要大得多。這是因為,處理請求的線**正用於計算的時間可能很少,大多數時間可能在阻塞,如等待資料庫返回資料、等待硬碟讀寫資料等。因此,在某一時刻,只有少數的線**正的在使用物理cpu,大多數執行緒都在等待;因此執行緒數遠大於物理核心數才是合理的。
換句話說,tomcat通過使用比cpu核心數量多得多的執行緒數,可以使cpu忙碌起來,大大提高cpu的利用率。
4、引數設定
(1)maxthreads的設定既與應用的特點有關,也與伺服器的cpu核心數量有關。通過前面介紹可以知道,maxthreads數量應該遠大於cpu核心數量;而且cpu核心數越大,maxthreads應該越大;應用中cpu越不密集(io越密集),maxthreads應該越大,以便能夠充分利用cpu。當然,maxthreads的值並不是越大越好,如果maxthreads過大,那麼cpu會花費大量的時間用於執行緒的切換,整體效率會降低。
(2)maxconnections的設定與tomcat的執行模式有關。如果tomcat使用的是bio,那麼maxconnections的值應該與maxthreads一致;如果tomcat使用的是nio,maxconnections值應該遠大於maxthreads。
(3)通過前面的介紹可以知道,雖然tomcat同時可以處理的連線數目是maxconnections,但伺服器中可以同時接收的連線數為maxconnections+acceptcount 。acceptcount的設定,與應用在連線過高情況下希望做出什麼反應有關係。如果設定過大,後面進入的請求等待時間會很長;如果設定過小,後面進入的請求立馬返回connection refused。
詳解tomcat的連線數與執行緒池
1 connector的protocol t11 2 如何選擇protocol t12 3 bio nio有何不同 t13 1 acceptcount t21 2 maxconnections t22 3 maxthreads t23 4 引數設定 t24 1 連線數 t41 2 執行緒 t42 一...
Tomcat 的連線數與執行緒池
connector在處理http請求時,會使用不同的protocol。不同的tomcat版本支援的protocol不同,其中最典型的protocol包括bio nio和apr tomcat7中支援這3種,tomcat8增加了對nio2的支援,而到了tomcat8.5和tomcat9.0,則去掉了對b...
Tomcat連線數設定
size medium maxthreads 150 表示最多同時處理150個連線 minsparethreads 25 表示即使沒有人使用也開這麼多空 maxsparethreads 75 表示如果最多可以空75個執行緒,例如某時刻有80人訪問,之後沒有人訪問了,則tomcat不會保留80個空執行...