glassfish下的性能調(diào)優(yōu):令人極度困惑的Max Connections參數(shù)
近日做性能調(diào)優(yōu),主要是針對web service,運行于glassfish之上。前期通過修改優(yōu)化代碼,基本搞定一些阻礙性能的問題,主要是代碼層次的不合理。
之后還是發(fā)現(xiàn)性能上不去,而且表現(xiàn)明顯不合理:tps只能達(dá)到2k,而服務(wù)器cpu只停留在10%附近,壓力測試的客戶端cpu也不高,20%-30%吧。反復(fù)thread dump后檢查無果,不論是服務(wù)器端還是客戶端的工作線程都算正常,沒有發(fā)現(xiàn)線程/鎖之類的問題。分析發(fā)現(xiàn)主要的癥狀是服務(wù)器端和客戶端都壓不上去,服務(wù)器端工作線程很空閑,客戶端則忙于socket通訊及等待服務(wù)器返回。
于是開始懷疑問題可能出現(xiàn)在網(wǎng)絡(luò)通訊上,一邊跑壓力測試,一邊用netstat命令查看socket狀態(tài),很快發(fā)現(xiàn)問題,有大量多大數(shù)k的socket連接出現(xiàn)。感覺不正常,因為應(yīng)該用的是長連接,按說正常情況socket連接數(shù)應(yīng)該近似等于并發(fā)的線程數(shù)。測試工具為客戶端soapUI,直接連接到運行在glassfish上的web service. soapUI是支持長連接的,glassfish也是支持長連接的。
做了一下驗證,只開一個工作線程,跑了幾個請求,通過抓包工具發(fā)現(xiàn)的確是只建立了一個連接,后面的請求都是跑在同一個socket連接上。試著增加http header Connection: Keep-Alive,發(fā)現(xiàn)和默認(rèn)沒有這個參數(shù)時表現(xiàn)一致。故意設(shè)置為Connection: close,則每次請求都是重新建立連接。因此排除http 是短連接的問題。
繼續(xù)回頭看socket狀態(tài),發(fā)現(xiàn)出現(xiàn)的多達(dá)數(shù)k的socket有很多都是處于TIME_WAIT狀態(tài),只有少數(shù)處于正常的ESTABLISHED狀態(tài)。TIME_WAIT意味著是服務(wù)器端主動要求close socket的,在長連接并且不斷有請求的情況下,服務(wù)器為什么會如此頻繁的關(guān)閉連接呢?
試著只開一個壓力測試的工作線程,tps大概100+的情況下看服務(wù)器端的socket情況,很快發(fā)現(xiàn)問題:先是建立一個socket,ESTABLISHED狀態(tài),然后大概2s左右重新建立一個新的socket,原有的這個狀態(tài)轉(zhuǎn)為TIME_WAIT,之后每隔2-3秒左右,都會有上訴的情況出現(xiàn)----原有連接被放棄,重建新的連接。這樣socket就成了1 + n的狀態(tài):1個ESTABLISHED + n個TIME_WAIT,一定時間后TIME_WAIT的socket開始逐個消失。
將壓力測試的工作線程加到100之后,上述情況開始變的極度激烈,大量TIME_WAIT的socket被建立,數(shù)目直接上到1w,2w乃至36000,之后開始偶爾報錯說無法連接。
問題基本就定位在這里了,為什么明明建立好了長連接,服務(wù)器端確總是會不斷的關(guān)閉這些長連接導(dǎo)致無數(shù)的TIME_WAIT?
試著查找資料,調(diào)整參數(shù)并反復(fù)測試,最終發(fā)現(xiàn)和兩個參數(shù)有關(guān):
1. http.maxConnections
glassfish官網(wǎng)說明
https://metro.dev.java.net/guide/HTTP_Persistent_Connections__keep_alive_.html
HTTP keep-alive behavior can be controlled by the http.keepAlive (default: true) and http.maxConnections (default: 5) system properties. For more information, see Networking Properties
進(jìn)入http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html 頁面查看相關(guān)的系統(tǒng)屬性,最后聚焦在http.maxConnections :
http.maxConnections (default: 5)
If HTTP keep-alive is enabled, this value is the number of idle connections that will be simultaneously kept alive, per-destination.
If HTTP keep-alive is enabled, this value is the number of idle connections that will be simultaneously kept alive, per-destination.
從說明上看,應(yīng)該是max idle connection,和命名maxConnections不大符合,maxConnections感覺像是最多容許開這么多長連接。考慮默認(rèn)值為5明顯應(yīng)該是max idle connection。
后面的測試驗證,就是這個參數(shù)非常的致命,在修改為200之后,tps直接 *2。
返回來分析這個參數(shù),默認(rèn)最多容許有5個空閑長連接。考慮到100個工作線程,正常應(yīng)該長連接數(shù)目也在100附近,考慮每次請求都要先申請一個連接,用完之后再放回,100個工作線程同時操作,很有可能同時將超過5個的連接返還給連接池。如果服務(wù)器簡單的判斷說多于5個連接然后就立即close并釋放長連接,那么就會出現(xiàn)一方面連續(xù)釋放長連接,一方面因為連接數(shù)不夠不停的創(chuàng)建新的長連接。
換言之,當(dāng)100個線程并發(fā)在連接池中進(jìn)行申請連接/返還連接的過程中,連接池內(nèi)的可用連接數(shù)是時刻變化的,實際的數(shù)目會有大的波動。而默認(rèn)的最大空閑參數(shù)過小(默認(rèn)才5)使得這個波動有極大的幾率突破限制,從而造成連接池進(jìn)行不必要的釋放所謂過多的“空閑”連接。
glassfish中,對于這個參數(shù)的修改,非常簡單,在jvm參數(shù)中增加新的一項"-Dhttp.maxConnections=250",重啟即可。
2. maxKeepAliveRequests
前面的調(diào)整,雖然達(dá)到了tps * 2的良好效果,但是使用netstat查看socket時,還是發(fā)現(xiàn)有非常多的TIME_TIME狀態(tài)的socket,只是數(shù)目沒有原來那么直上3w那么夸張,大概穩(wěn)定在2000附近。
看來還是有其他的原因的,重新回頭看當(dāng)時只開一個線程測試的場景:一個線程連續(xù)提交,會出現(xiàn)1個ESTABLISHED + n個TIME_WAIT。
感覺上像是一個長連接上只要跑一段時間或者一定的請求,socket就會被服務(wù)器端關(guān)閉。修改測試方法,讓每次請求之間等待一段時間,降低tps,發(fā)現(xiàn)關(guān)閉連接的時間間隔大為增加。
后來google到maxKeepAliveRequests這個參數(shù),對于tomcat,apache等服務(wù)器都有支持,解釋如下:
maxKeepAliveRequests:
The maximum number of HTTP requests which can be pipelined until the connection is closed by the server. Setting this attribute to 1 will disable HTTP/1.0 keep-alive, as well as HTTP/1.1 keep-alive and pipelining. Setting this to -1 will allow an unlimited amount of pipelined or keep-alive HTTP requests. If not specified, this attribute is set to 100.
The maximum number of HTTP requests which can be pipelined until the connection is closed by the server. Setting this attribute to 1 will disable HTTP/1.0 keep-alive, as well as HTTP/1.1 keep-alive and pipelining. Setting this to -1 will allow an unlimited amount of pipelined or keep-alive HTTP requests. If not specified, this attribute is set to 100.
隨即google到grizzly也有類似的系統(tǒng)參數(shù)可以設(shè)置這個maxKeepAliveRequests
-Dcom.sun.enterprise.web.connector.grizzly.maxKeepAliveRequests=-1
使用關(guān)鍵字"glassfish maxKeepAliveRequests",發(fā)現(xiàn)glassfish還是有支持這個參數(shù)的,但是找不到具體設(shè)置的方法。后來在glassfish的控制臺-> Configuration -> http service -> Keep Alive 下
發(fā)現(xiàn)了一個Max Connections參數(shù),默認(rèn)值250,解釋為"Maximum number of connections in the Keep-Alive mode",和maxKeepAliveRequests似乎完全不是一回事。
但是試著將這個參數(shù)修改為2500之后,非常驚訝的發(fā)現(xiàn),見效了!單線程測試長連接釋放的速度明顯放慢,大體算了一下時間間隔和tpc,無論是之前的默認(rèn)250還是現(xiàn)在新修改的2500都和測試結(jié)果
很合拍。開到100個線程測試,發(fā)現(xiàn)原有的2000附近的TIME_WAIT連接被降低到了大概300附近,明顯改觀。后面發(fā)現(xiàn),可以用下面的參數(shù)直接設(shè)置:
asadmin set --user admin --passwordfile passwords.txt --port 47348 "server.http-service.keep-alive.max-connections=2500"
這里就有點奇怪了,從測試結(jié)果來看,這個參數(shù)的表現(xiàn)和maxKeepAliveRequests參數(shù)的功能是一致的,但是這個參數(shù)明明叫做Max Connections,而且旁邊的注釋"Maximum number of connections in the Keep-Alive mode"也證明了這點。很令人費解,并且這里的Max Connections前面的http.maxConnections有重名嫌疑而作用明顯不同。
下面是一個簡單的列表,其他情況相同下,分別修改者兩個參數(shù)前后的對比:
keep-alive.max-connections http.maxConnections test result250 5 TPS=650-700 TIME-WAIT=32600
250 200 TPS=1200 TIME-WAIT=300
2500 5 TPS=650-700 TIME-WAIT=32600
2500 200 TPS=1200 TIME-WAIT=300
最終的結(jié)果,還是比較理想的,修改了上述兩個參數(shù)之后,cpu終于壓上去了,tps也有了巨大的提升,而且TIME_WAIT的連接也大為減少。但是這兩個參數(shù)的名稱,注釋和實際測試中的效果,都有名不副實的感覺,令人困惑。
后續(xù)更新:
1. 經(jīng)同事提醒,有新的發(fā)現(xiàn),maxKeepAliveRequests得以確認(rèn)
http://docs.sun.com/app/docs/doc/820-4343/abefk?a=view
這里是sun的官方資料,其中對Max Connections 參數(shù)解釋如下:
Max Connections
Max Connections controls the number of requests that a particular client can make over a keep-alive connection. The range is any positive integer, and the default is 256.
Adjust this value based on the number of requests a typical client makes in your application. For best performance specify quite a large number, allowing clients to make many requests.
Max Connections controls the number of requests that a particular client can make over a keep-alive connection. The range is any positive integer, and the default is 256.
Adjust this value based on the number of requests a typical client makes in your application. For best performance specify quite a large number, allowing clients to make many requests.
因此可見這個"max connections"參數(shù)的確就是通常意義上的"maxKeepAliveRequests"。這里sun的命名不大合適,容易造成誤解。
posted on 2010-04-29 17:10 sky ao 閱讀(6771) 評論(1) 編輯 收藏 所屬分類: web service