Sky's blog

          我和我追逐的夢

          常用鏈接

          統計

          其他鏈接

          友情鏈接

          最新評論

          glassfish下的性能調優:令人極度困惑的Max Connections參數



          近日做性能調優,主要是針對web service,運行于glassfish之上。前期通過修改優化代碼,基本搞定一些阻礙性能的問題,主要是代碼層次的不合理。

          之后還是發現性能上不去,而且表現明顯不合理:tps只能達到2k,而服務器cpu只停留在10%附近,壓力測試的客戶端cpu也不高,20%-30%吧。反復thread dump后檢查無果,不論是服務器端還是客戶端的工作線程都算正常,沒有發現線程/鎖之類的問題。分析發現主要的癥狀是服務器端和客戶端都壓不上去,服務器端工作線程很空閑,客戶端則忙于socket通訊及等待服務器返回。

          于是開始懷疑問題可能出現在網絡通訊上,一邊跑壓力測試,一邊用netstat命令查看socket狀態,很快發現問題,有大量多大數k的socket連接出現。感覺不正常,因為應該用的是長連接,按說正常情況socket連接數應該近似等于并發的線程數。測試工具為客戶端soapUI,直接連接到運行在glassfish上的web service. soapUI是支持長連接的,glassfish也是支持長連接的。

          做了一下驗證,只開一個工作線程,跑了幾個請求,通過抓包工具發現的確是只建立了一個連接,后面的請求都是跑在同一個socket連接上。試著增加http header Connection: Keep-Alive,發現和默認沒有這個參數時表現一致。故意設置為Connection: close,則每次請求都是重新建立連接。因此排除http 是短連接的問題。

          繼續回頭看socket狀態,發現出現的多達數k的socket有很多都是處于TIME_WAIT狀態,只有少數處于正常的ESTABLISHED狀態。TIME_WAIT意味著是服務器端主動要求close socket的,在長連接并且不斷有請求的情況下,服務器為什么會如此頻繁的關閉連接呢?

          試著只開一個壓力測試的工作線程,tps大概100+的情況下看服務器端的socket情況,很快發現問題:先是建立一個socket,ESTABLISHED狀態,然后大概2s左右重新建立一個新的socket,原有的這個狀態轉為TIME_WAIT,之后每隔2-3秒左右,都會有上訴的情況出現----原有連接被放棄,重建新的連接。這樣socket就成了1 + n的狀態:1個ESTABLISHED + n個TIME_WAIT,一定時間后TIME_WAIT的socket開始逐個消失。

          將壓力測試的工作線程加到100之后,上述情況開始變的極度激烈,大量TIME_WAIT的socket被建立,數目直接上到1w,2w乃至36000,之后開始偶爾報錯說無法連接。

          問題基本就定位在這里了,為什么明明建立好了長連接,服務器端確總是會不斷的關閉這些長連接導致無數的TIME_WAIT?

          試著查找資料,調整參數并反復測試,最終發現和兩個參數有關:

          1. http.maxConnections

          glassfish官網說明
          https://metro.dev.java.net/guide/HTTP_Persistent_Connections__keep_alive_.html

          HTTP keep-alive behavior can be controlled by the http.keepAlive (defaulttrue) and http.maxConnections (default5) system properties. For more information, see Networking Properties

          進入http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html 頁面查看相關的系統屬性,最后聚焦在http.maxConnections :

          http.maxConnections (default5)
          If HTTP keep
          -alive is enabled, this value is the number of idle connections that will be simultaneously kept alive, per-destination.

          從說明上看,應該是max idle connection,和命名maxConnections不大符合,maxConnections感覺像是最多容許開這么多長連接。考慮默認值為5明顯應該是max idle connection。

          后面的測試驗證,就是這個參數非常的致命,在修改為200之后,tps直接 *2。

          返回來分析這個參數,默認最多容許有5個空閑長連接。考慮到100個工作線程,正常應該長連接數目也在100附近,考慮每次請求都要先申請一個連接,用完之后再放回,100個工作線程同時操作,很有可能同時將超過5個的連接返還給連接池。如果服務器簡單的判斷說多于5個連接然后就立即close并釋放長連接,那么就會出現一方面連續釋放長連接,一方面因為連接數不夠不停的創建新的長連接。

          換言之,當100個線程并發在連接池中進行申請連接/返還連接的過程中,連接池內的可用連接數是時刻變化的,實際的數目會有大的波動。而默認的最大空閑參數過小(默認才5)使得這個波動有極大的幾率突破限制,從而造成連接池進行不必要的釋放所謂過多的“空閑”連接。

          glassfish中,對于這個參數的修改,非常簡單,在jvm參數中增加新的一項"-Dhttp.maxConnections=250",重啟即可。


          2. maxKeepAliveRequests

              前面的調整,雖然達到了tps * 2的良好效果,但是使用netstat查看socket時,還是發現有非常多的TIME_TIME狀態的socket,只是數目沒有原來那么直上3w那么夸張,大概穩定在2000附近。

              看來還是有其他的原因的,重新回頭看當時只開一個線程測試的場景:一個線程連續提交,會出現1個ESTABLISHED + n個TIME_WAIT。

              感覺上像是一個長連接上只要跑一段時間或者一定的請求,socket就會被服務器端關閉。修改測試方法,讓每次請求之間等待一段時間,降低tps,發現關閉連接的時間間隔大為增加。

              后來google到maxKeepAliveRequests這個參數,對于tomcat,apache等服務器都有支持,解釋如下:

          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.


              隨即google到grizzly也有類似的系統參數可以設置這個maxKeepAliveRequests

          -Dcom.sun.enterprise.web.connector.grizzly.maxKeepAliveRequests=-1

              使用關鍵字"glassfish maxKeepAliveRequests",發現glassfish還是有支持這個參數的,但是找不到具體設置的方法。后來在glassfish的控制臺-> Configuration -> http service -> Keep Alive 下
          發現了一個Max Connections參數,默認值250,解釋為"Maximum number of connections in the Keep-Alive mode",和maxKeepAliveRequests似乎完全不是一回事。

              但是試著將這個參數修改為2500之后,非常驚訝的發現,見效了!單線程測試長連接釋放的速度明顯放慢,大體算了一下時間間隔和tpc,無論是之前的默認250還是現在新修改的2500都和測試結果
          很合拍。開到100個線程測試,發現原有的2000附近的TIME_WAIT連接被降低到了大概300附近,明顯改觀。后面發現,可以用下面的參數直接設置:
          asadmin set --user admin --passwordfile passwords.txt --port 47348 "server.http-service.keep-alive.max-connections=2500"

              這里就有點奇怪了,從測試結果來看,這個參數的表現和maxKeepAliveRequests參數的功能是一致的,但是這個參數明明叫做Max Connections,而且旁邊的注釋"Maximum number of connections in the Keep-Alive mode"也證明了這點。很令人費解,并且這里的Max Connections前面的http.maxConnections有重名嫌疑而作用明顯不同。

          下面是一個簡單的列表,其他情況相同下,分別修改者兩個參數前后的對比:

          keep-alive.max-connections   http.maxConnections     test result     
          250                                      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  

              最終的結果,還是比較理想的,修改了上述兩個參數之后,cpu終于壓上去了,tps也有了巨大的提升,而且TIME_WAIT的連接也大為減少。但是這兩個參數的名稱,注釋和實際測試中的效果,都有名不副實的感覺,令人困惑。

          后續更新:
          1. 經同事提醒,有新的發現,maxKeepAliveRequests得以確認

              http://docs.sun.com/app/docs/doc/820-4343/abefk?a=view
               這里是sun的官方資料,其中對
          Max Connections 參數解釋如下:
          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"參數的確就是通常意義上的"maxKeepAliveRequests"。這里sun的命名不大合適,容易造成誤解。

          posted on 2010-04-29 17:10 sky ao 閱讀(6771) 評論(1)  編輯  收藏 所屬分類: web service

          評論

          # re: glassfish下的性能調優:令人極度困惑的Max Connections參數 2010-04-30 12:02 99書城

          案件快速的既驕傲  回復  更多評論   

          主站蜘蛛池模板: 贺州市| 进贤县| 昌黎县| 平谷区| 台东县| 大英县| 大城县| 璧山县| 延庆县| 忻州市| 浦江县| 方城县| 东兰县| 郧西县| 县级市| 扎兰屯市| 兴业县| 西吉县| 邯郸市| 永昌县| 镇原县| 山东省| 翼城县| 彰化市| 会同县| 北安市| 临城县| 谢通门县| 华阴市| 广水市| 新巴尔虎右旗| 察雅县| 赤壁市| 分宜县| 平凉市| 南平市| 陆丰市| 铜梁县| 布拖县| 五常市| 灌南县|