tomcat 最大併發數

只針對BIO模式,目標請求會sleep兩秒再返回結果,經過jmeter測試工具進行併發測試html

操做系統:windows && linuxlinux

tomcat7測試:windows

<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" maxThreads="1" acceptCount="2" 
redirectPort="8443" />tomcat

文檔:http://localhost:8080/docs/config/http.html併發

官方解釋:acceptCount對暫時沒法執行的請求進行隊列保存,超出設置則拒絕鏈接。socket

測試發現沒法限制住最大併發數,全部請求均可以依次執行,每次有1個線程執行(maxThreads=1)tcp

最大併發數若是過大,大於acceptCount值好幾倍,會隨機出現鏈接被拒絕。工具

進一步調查-----------------------------------------------------------------------------------------------------------------------------------源碼分析

首先關於tcp queue簡單介紹:測試

tcp三次握手:

第一次,客戶端發送syn,等待服務端確認,此時客戶端進入SYN_SEND狀態

第二次,服務端接收syn包並確認,發送syn+ack給客戶端,此時服務端進入SYN_RECV狀態

第三次,客戶端收到syn+ack,再次向服務端發送ack,此時客戶端進入ESTAB狀態(注意,此時服務端未必進入ESTAB狀態

 

半鏈接隊列:服務端維護的與客戶端保持SYN_RECV狀態的鏈接隊列,等待客戶端回覆,當收到客戶端ack後,若是條件容許(全鏈接隊列未達到最大值),服務端進入ESTAB狀態,從半鏈接隊列移到全鏈接隊列的隊尾。

全鏈接隊列:完成三次握手等待accept。完成三次握手即進入了全鏈接隊列的隊尾,當進程調用accept時,全鏈接隊列中的隊頭項將返回給進程,並從隊列中移出鏈接。若是該隊列爲空,那麼進程將被投入睡眠,直到TCP在該隊列中放入一項才喚醒它。

在listen(int sockfd, int backlog)中,backlog在Linux 2.2以後表示的是已完成三次握手但還未被應用程序accept的隊列長度。

 

全鏈接隊列滿,半鏈接隊列未滿:

客戶端發出syn分節,服務端收下,並向客戶端發出syn+ack。

客戶端收到服務端syn+ack後,成爲ESTAB狀態,向服務端發送第三次握手ack。

服務端收到ack後,發現全鏈接隊列已滿,默認狀況下,服務端什麼也不作,狀態依然是SYN_RECV。

客戶端會重傳syn和ack,當達到必定的閾值(/proc/sys/net/ipv4/tcp_synack_retries)時,客戶端與服務端斷開鏈接,服務端刪除客戶端在半鏈接隊列中的syn分節。

全鏈接、半鏈接隊列都滿:

客戶端發出syn分節,服務端發現半鏈接隊列已滿,直接丟棄syn,使客戶端重傳syn。

客戶端重傳syn,再次到達服務端後,服務端發現已經重傳過,則收下,並告訴客戶端syn+ack。

後續流程與上述一致,相比之下,多了一次客戶端重傳syn分節。

修改tcp參數配置:

tcp_synack_retries和tcp_syn_retries定義SYN 的重試鏈接次數

/etc/rc.d/rc.local文件中追加:

sysctl -w net.ipv4.tcp_synack_retries=3

sysctl -w net.ipv4.tcp_syn_retries=3

重啓。

也可直接執行命令:

sysctl -w net.ipv4.tcp_synack_retries=1

sysctl -w net.ipv4.tcp_syn_retries=3

關於隊列的長度:

半鏈接隊列:≈2 * min(backlog, net.ipv4.tcpmax_syn_backlog) 

全鏈接隊列:min(/proc/sys/net/core/somaxconn(本系統128), backlog),表示最多有 min() + 1個 ESTAB 的鏈接等待 accept()。

修改somaxconn,

在/etc/sysctl.conf中添加以下:

net.core.somaxconn = 2048

而後在終端中執行

sysctl -p

進一步試驗-------------------------------------------------------------------------------------------------------------------------------------------------------------------

在linux下,經過ss -ant進行觀察tcp queue

併發5個請求

 

acceptCount配置做爲socket中的backlog的值,若是acceptCount不設置或者設置爲0,則會取默認值,經測試是100。

全鏈接隊列大小爲 min(/proc/sys/net/core/somaxconn(本系統128), 2) + 1=3,即等待服務端accept的ESTAB狀態的鏈接最多有3個,如Recv-Q所示。

3個Recv-Q爲323(表示請求bytes數值)的ESTAB狀態的鏈接正等待server accept

1個Recv-Q爲0的ESTAB狀態的鏈接表示server端已經accept了請求,只是尚未返回結果(sleep中)。

1個SYN-RECV狀態是半鏈接狀態,位於半鏈接隊列當中(此時客戶端已經處於ESTAB狀態),全鏈接隊列已經滿了。

對於處在半鏈接狀態的鏈接,客戶端會定時重發,直至達到閾值,以下:

第一次握手

 第二次握手

 第三次握手

 客戶端發送數據包

但因爲此時服務端未能將鏈接從半鏈接隊列移至全鏈接隊列,狀態依然是SYN-RECV,即未獲得服務端ack,所以客戶端繼續發數據包

發送幾回以後,服務端有了迴應,告訴客戶端說,你以前發的包丟了

而後客戶端也告訴服務端,丟失的狀態、對應的id號及次數,這裏的43就是第三次握手的43,失敗次數是1

而後客戶端又開始重傳了

終於服務端受不了了,此時客戶端服務端完全斷開。

經過調整ipv4.tcp_synack_retries和ipv4.tcp_syn_retries,能夠增長重試次數

 

結論:

對於tomcat中的acceptCount只是全鏈接隊列的大小,就是說客戶端和服務端都已是ESTAB狀態的鏈接,不考慮connectionTime的狀況,在此隊列中的鏈接最終都會被處理。對於大於acceptCount的鏈接請求,若是在tcp重試閾值範圍以內完成半鏈接到全鏈接的狀態轉換,那麼仍是有機會被服務端accept並處理的。

所以,不能說只要大於acceptCount的鏈接就必定被拒絕!

 

 

參考文獻:

http://www.cnblogs.com/leezhxing/p/5329786.html

http://blog.chinaunix.net/uid-24782829-id-3456109.html

http://www.cnblogs.com/menghuanbiao/p/5212131.html

http://www.cnblogs.com/zengkefu/p/5606696.html 有詳細的源碼分析

相關文章
相關標籤/搜索