2 壓測環境配置
壓測發起設備:windows 10
網絡:局域網
壓測軟件:Jmeter 5.0
壓測系統內存:Ubuntu 4核8G
PHP 版本:php7.1.23
Nginx 版本:nginx1.14.0
MySQL版本:5.7.24
Redis: 開啟
CDN:關閉
3 報錯信息描述
壓測的初期,在設置了 150qps/s 的並發數下壓測幾分鍾后 Jmeter
就出現了如下報錯。
JAVA.NET.BINDEXCEPTION: ADDRESS ALREADY IN USE: CONNECT
- 1
- 2
4 問題排查
開始考慮的方向是Nginx、PHP、MySQL做了相關限制導致線程被占用, 但是修改對應的配置后發現沒有任何效果,該報錯的還是報錯。 查了一波資料,發現 windows 環境下的端口循環回收需要消耗2~4分鍾。由此猜測可能是由於 windows下壓測端口數有限,端口資源被占滿,沒有及時循環回收,導致報錯。
5 初步解決之擴大端口數量
設置 windows下最大端口數 65534,嘗試將端口資源數設置為最大,windows最大能支持65534個端口。
步驟1
使用 win + R 快捷鍵打開 cmd
,輸入 regedit
命令打開注冊表
步驟2 設置 MAXUSERPORT 數量
2.1 找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
目錄。
2.2 右擊 Parameters
,添加一個新的 DWORD
,命名為MaxUserPort
。
2.3 然后雙擊 MaxUserPort
,輸入 65534,基數選擇 十進制(如果是分布式運行的話,控制機器和負載機器都需要這樣操作)。
2.4 修改配置完畢后, 需要重啟 windows 才會生效。
6 初步實踐
采用上述的解決方案之后,windows 下設置 150qps/s 並發數進行壓測,暫時解決了端口占用的問題。在此基礎上,將壓測的並發數提高至 700qps/s,兩分鍾內達到 66000+
個請求,數量超過了 65534
端口數,再次出現了同一報錯。
擴大 WINDOWS 端口資源數量, 能夠支持 150QPS/S 並發數的壓測。 但是在高並發數(700QPS/S)的壓測下,即使 WINDOWS 端口資源數量設置為最大,也會出現端口占用的問題。
7 深入研究之提高端口使用率
又是一波海量搜索,定位到了兩個影響端口使用率的主要因素,具體如下。
-
windows下的端口
Time_Wait
導致端口無法使用 -
windows下的端口
CLOSE_WAIT
導致端口無法使用
7.1 TIME_WAIT 解決方案
主要思路是通過縮短
TIME_WAIT
的等待時間,提高端口的使用率。
step1: 使用 win + R 快捷鍵打開 cmd
,輸入 regedit
命令打開注冊表。
step2: 找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
目錄。
step3: 右擊 parameters
,添加一個新的DWORD,命名為 TcpTimedWaitDelay
,將值設置為30
, 縮短 TIME_WAIT
的等待時間。
step4: 重啟windows,配置項生效。
7.2 CLOSE_WAIT
CLOSE_WAIT 引發問題
Close_Wait
會占用一個連接,網絡可用連接小。當數量過多時,可能會引起網絡性能下降,並占用系統非換頁內存。尤其是在有連接池的情況下(比如 HttpRequest
),會耗盡連接池的網絡連接數,導致無法建立網絡連接。
CLOSE_WAIT 產生原因
-
一般情況下是因為 TCP 連接沒有調用關閉方法,需要應用來處理網絡鏈接關閉。
-
如果是Web請求,經常是因為
Response
的BodyStream
沒有調用Close
。舉個例子,Widnows 下使用HttpWebRequest
一定要保證GetRequestStream
和GetResponse
對象關閉,否則容易造成連接處於CLOSE_WAIT
狀態。 -
TCP的
KeepLive
功能, 操作系統 默認7200秒
(2小時) 自動清理一次CLOSE_WAIT
的連接,滿足不了高並發下的端口需求數。支持自定義配置。
CLOSE_WAIT 解決方案
step1: 使用 win + R 快捷鍵打開 cmd
,輸入 regedit
命令打開注冊表。
step2: 找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
目錄。
step3: 在該目錄下添加新的配置項。設置合理的Keepalive
參數。
KeepAliveTime
KeepAliveTime的值控制系統嘗試驗證空閑連接是否仍然完好的頻率。如果該連接在一段時間內沒有活動,那么系統會發送保持連接的信號,如果網絡正常並且接收方是活動的,它就會響應。如果需要對丟失接收方的情況敏感,也就是說需要更快地發現是否丟失了接收方,請考慮減小該值。而如果長期不活動的空閑連接的出現次數較多,但丟失接收方的情況出現較少,那么可能需要增大該值以減少開銷。
缺省情況下,如果空閑連接在7200000毫秒(2小時)內沒有活動,系統就會發送保持連接的消息。 通常建議把該值設為1800000毫秒,從而丟失的連接會在30分鍾內被檢測到。具體操作:
瀏覽至HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters注冊表子鍵,在Parameters子鍵下創建或修改名為KeepAliveTime的REG_DWORD值,為該值設置適當的毫秒數。
KeepAliveInterval
KeepAliveInterval的值表示未收到另一方對“保持連接”信號的響應時,系統重復發送“保持連接”信號的頻率。在無任何響應的情況下,連續發送“保持連接”信號的次數超過TcpMaxDataRetransmissions(下文將介紹)的值時,將放棄該連接。如果網絡環境較差,允許較長的響應時間,則考慮增大該值以減少開銷;如果需要盡快驗證是否已丟失接收方,則考慮減小該值或TcpMaxDataRetransmissions值。
缺省情況下,在未收到響應而重新發送“保持連接”的信號之前,系統會等待1000毫秒(1秒),可以根據具體需求修改,具體操作:
瀏覽至HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters注冊表子鍵,在Parameters子鍵下創建或修改名為KeepAliveInterval的REG_DWORD值,為該值設置適當的毫秒數。
TcpMaxDataRetransmissions
TcpMaxDataRetransmissions的值表示TCP數據重發,系統在現有連接上對無應答的數據段進行重發的次數。如果網絡環境很差,可能需要提高該值以保持有效的通信,確保接收方收到數據;如果網絡環境很好,或者通常是由於丟失接收方而導致數據的丟失,那么可以減小該值以減少驗證接收方是否丟失所花費的時間和開銷。
缺省情況下,系統會重新發送未返回應答的數據段5次,可以根據具體需求修改,具體操作:
瀏覽至HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters注冊表子鍵,在Parameters子鍵下創建或修改名為TcpMaxDataRetransmissions的REG_DWORD值,該值的范圍是從0到4294967295,缺省值為5,根據實際情況進行設置。
TcpMaxConnectRetransmisstions
TcpMaxConnectRetransmisstions的值表示TCP連接重發,TCP退出前重發非確認連接請求(SYN)的次數。對於每次嘗試,重發超時是成功重發的兩倍。在Windows Server 2003中默認超時次數是2,默認超時時間為3秒(在注冊表項TCPInitialRTT中)。速度較慢的WAN連接中超時時間可相應增加,不同環境中可能會有不同的最優化設置,需要在實際環境中測試確定。超時時間不要設置太大否則將不會發生網絡連接超時時間。具體操作:
瀏覽至HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters注冊表子鍵,在Parameters子鍵下創建或修改名為TcpMaxConnectRetransmisstions的REG_DWORD值,該值的范圍是從0到255,缺省值為2,根據實際情況進行設置。然后在Parameters子鍵下創建或修改名為TCPInitialRTT的REG_DWORD值,同樣根據實際情況進行設置。
TcpAckFrequency
TcpAckFrequency的值表示系統發送應答消息的頻率。如果值為2,那么系統將在接收到2個分段之后發送應答,或是在接收到1個分段但在200毫秒內沒有接收到任何其他分段的情況下發送應答;如果值為3,那么系統將在接收到3個分段之后發送應答,或是在接收到1個或2個分段但在200毫秒內沒有接收到任何其他分段的情況下發送應答,以此類推。如果要通過消除應答延遲來縮短響應時間,那么建議將該值設為1。在此情況下,系統會立即發送對每個分段的應答;如果連接主要用於傳輸大量數據,而200毫秒的延遲並不重要,那么可以減小該值以降低應答的開銷。
缺省情況下,系統將該值設為2,即每隔一個分段應答一次。該值的有效范圍是0到255,其中0表示使用缺省值2,可以根據具體需求修改,具體操作:
瀏覽至HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters\Interfaces\xx(xx由網絡適配器決定)注冊表子鍵,在xx子鍵下創建或修改名為TcpAckFrequency的REG_DWORD值,該值的范圍是從1到13,缺省值為2,根據希望每發送幾個分段返回一個應答而設置該值,建議百兆網絡設為5,千兆網絡設為13。
"KeepAliveTime"=dword:006ddd00 "KeepAliveInterval"=dword:000003e8 "MaxDataRetries"="5"
step4: 重啟windows,配置項生效。