tomcat 效能最佳化,tomcat
一、JVM最佳化
1、記憶體最佳化。
2、記憶體回收策略最佳化。
二、server.xml的connector最佳化(connector是與HTTP請求處理相關的容器,三個容器的初始化順序為:Server->Service->Connector)
(1)指定使用NIO模型來接受HTTP請求
(2)http connector的最佳化,指定處理線程數目
(3)線程池
(4)其他常規設定
三、設定session到期時間
四、apr外掛程式提高tomcat效能
五、叢集
六、問題定位
一、JVM最佳化
linux修改TOMCAT_HOME/bin/catalina.sh,在前面加入
JAVA_OPTS="-XX:PermSize=64M -XX:MaxPermSize=128m -Xms512m -Xmx1024m -Duser.timezone=Asia/Shanghai"
windows修改TOMCAT_HOME/bin/catalina.bat,在前面加入
set JAVA_OPTS=-XX:PermSize=64M -XX:MaxPermSize=128m -Xms512m -Xmx1024m
1.記憶體調優
記憶體方式的設定是在catalina.sh中,調整一下JAVA_OPTS變數即可,因為後面的啟動參數會把JAVA_OPTS作為JVM的啟動參數來處理。
具體設定如下:
JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4"
其各項參數如下:
-Xmx3550m:設定JVM最大可用記憶體為3550M。 Heap Size 最大不要超過可用實體記憶體的80%
-Xms3550m:設定JVM促使記憶體為3550m。此值可以設定與-Xmx相同,以避免每次記憶體回收完成後JVM重新分配記憶體。
-Xmn2g:設定年輕代大小為2G。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代後,將會減小年老代大小。此值對系統效能影響較大,Sun官方推薦配置為整個堆的3/8。
-Xss128k:設定每個線程的堆棧大小。JDK5.0以後每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應用的線程所需記憶體大小進行調整。在相同實體記憶體下,減小這個值能產生更多的線程。但是作業系統對一個進程內的線程數還是有限制的,不能無限產生,經驗值在3000~5000左右。
-XX:NewRatio=4:設定年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設定為4,則年輕代與年老代所佔比值為1:4,年輕代占整個堆棧的1/5
-XX:SurvivorRatio=4:設定年輕代中Eden區與Survivor區的大小比值。設定為4,則兩個Survivor區與一個Eden區的比值為2:4,一個Survivor區占整個年輕代的1/6
-XX:MaxPermSize=16m:設定持久代大小為16m。
-XX:MaxTenuringThreshold=0:設定垃圾最大年齡。如果設定為0的話,則年輕代對象不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。如果將此值設定為一個較大值,則年輕代對象會在Survivor區進行多次複製,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概論。
2.記憶體回收策略調優
記憶體回收的設定也是在catalina.sh中,調整JAVA_OPTS變數。
具體設定如下:
JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100"
具體的記憶體回收策略及相應策略的各項參數如下:
串列收集器(JDK1.5以前主要的回收方式)
-XX:+UseSerialGC:設定串列收集器
並行收集器(輸送量優先)
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
-XX:+UseParallelGC:選擇垃圾收集器為並行收集器。此配置僅對年輕代有效。即上述配置下,年輕代使用並發收集,而年老代仍舊使用串列收集。
-XX:ParallelGCThreads=20:配置並行收集器的線程數,即:同時多少個線程一起進行記憶體回收。此值最好配置與處理器數目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式為並行收集。JDK6.0支援對年老代並行收集
-XX:MaxGCPauseMillis=100:設定每次年輕代記憶體回收的最長時間,如果無法滿足此時間,JVM會自動調整年輕代大小,以滿足此值。
-XX:+UseAdaptiveSizePolicy:設定此選項後,並行收集器會自動選擇年輕代區大小和相應的Survivor區比例,以達到目標系統規定的最低相應時間或者收集頻率等,此值建議使用並行收集器時,一直開啟。
並發收集器(回應時間優先)
樣本:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC
-XX:+UseConcMarkSweepGC:設定年老代為並發收集。測試中配置這個以後,-XX:NewRatio=4的配置失效了,原因不明。所以,此時年輕代大小最好用-Xmn設定。
-XX:+UseParNewGC: 設定年輕代為並行收集。可與CMS收集同時使用。JDK5.0以上,JVM會根據系統配置自行設定,所以無需再設定此值。
-XX:CMSFullGCsBeforeCompaction:由於並發收集器不對記憶體空間進行壓縮、整理,所以運行一段時間以後會產生“片段”,使得運行效率降低。此值設定運行多少次GC以後對記憶體空間進行壓縮、整理。
-XX:+UseCMSCompactAtFullCollection:開啟對年老代的壓縮。可能會影響效能,但是可以消除片段
3.小結
在記憶體設定中需要做一下權衡
1)記憶體越大,一般情況下處理的效率也越高,但同時在做記憶體回收的時候所需要的時間也就越長,在這段時間內的處理效率是必然要受影響的。
2)在大多數的網路文章中都推薦 Xmx和Xms設定為一致,說是避免頻繁的回收,這個在測試的時候沒有看到明顯的效果,記憶體的佔用情況基本都是鋸齒狀的效果,所以這個還要根據實際情況來定。
二、Server.xml的Connection最佳化提高Tomcat的並發能力一些方法
1、Apache + Tomcat 結合起來用Apache 負責靜態頁面,Tomcat負責動態網頁面,同時減少connectionTimeout的時間,以應對並發量大線程回收來不及的情況。
2、壓力過大的問題,可以做負載平衡,一個TOMCAT無論如何也不可能擔當如此多的線程負載,而且JVM過大,其記憶體管理成本將顯著加大。2G的記憶體,做3-4個TOMCAT執行個體(512RAM*4),更為科學合理。
3、資料庫連接池,不少人,都推薦使用C3P0,能提高訪問資料庫的並發效能好幾倍。(有博文稱使用tomcat內建的jdbc-pool更好,還沒試過)
4、採用Tomcat叢集可以最大程度的發揮伺服器的效能,可以在配置較高的伺服器上部署多個Tomcat,也可以在多台伺服器上分別部署 Tomcat,Apache和Tomcat整合的方式還是JK方式。經過驗證,系統對大使用者量使用的回應程式面,Apache+3Tomccat叢集> Apache+2Tomcat叢集> Apache整合Tomcat >單個Tomcat。並且採用Apache+多Tomcat叢集的部署方式時,如果一個Tomcat出現宕機,系統可以繼續使用,所以在硬體系統效能足夠優越的情況下,需要盡量發揮軟體的效能,可以採用增加Tomcat叢集的方式。
5. 開啟KeepAlive支援
KeepAlive on, KeepAliveTimeout 15 MaxKeepAliveRequests 1000
根據實際經驗,通過Apache和Tomcat叢集的方式提高系統效能的效果十分明顯,這種方式可以最大化的利用硬體資源,通過多個Tomcat的處理來分擔單Tomcat時的壓力。
web server允許的最大串連數還受制於作業系統的核心參數設定,通常Windows是2000個左右,Linux是1000個左右。
1.指定使用NIO模型來接受HTTP請求
protocol="org.apache.coyote.http11.Http11NioProtocol" 指定使用NIO模型來接受HTTP請求。預設是BlockingIO,配置為protocol="HTTP/1.1"
acceptorThreadCount="2"使用NIO模型時接收線程的數目
2、指定處理線程數目
<Connector port="80" protocol="HTTP/1.1" maxThreads="600" minSpareThreads="100" maxSpareThreads="500" acceptCount="700"connectionTimeout="20000" redirectPort="8443" />
maxThreads="600" ///最大線程數
minSpareThreads="100"///初始化時建立的線程數
maxSpareThreads="500"///一旦建立的線程超過這個值,Tomcat就會關閉不再需要的socket線程。
acceptCount="700"//指定當所有可以使用的處理請求的線程數都被使用時,可以放到處理隊列中的請求數,超過這個數的請求將不予處理
這裡是http connector的最佳化,如果使用apache和tomcat做叢集的負載平衡,並且使用ajp協議做apache和tomcat的協議轉寄,那麼還需要最佳化ajp connector。
<Connector port="8009" protocol="AJP/1.3" maxThreads="600" minSpareThreads="100" maxSpareThreads="500" acceptCount="700"connectionTimeout="20000" redirectPort="8443" />
3、線程池
由於tomcat有多個connector,所以tomcat線程的配置,又支援多個connector共用一個線程池。
首先。開啟/conf/server.xml,增加
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500" minSpareThreads="20" maxIdleTime="60000" />
最大線程500(一般伺服器足以),最小空閑線程數20,線程最大空閑時間60秒。
然後,修改<Connector ...>節點,增加executor屬性,executor設定為線程池的名字:
<Connector executor="tomcatThreadPool" port="80" protocol="HTTP/1.1" connectionTimeout="60000" keepAliveTimeout="15000" maxKeepAliveRequests="1" redirectPort="443" />
可以多個connector公用1個線程池,所以ajp connector也同樣可以設定使用tomcatThreadPool線程池。
4.其它常用設定
maxHttpHeaderSize="8192"http要求標頭資訊的最大程度,超過此長度的部分不予處理。一般8K。
URIEncoding="UTF-8"指定Tomcat容器的URL編碼格式。不要遺漏URIEncoding=”GBK”,能使頁面url傳遞中文參數時保證正確。
disableUploadTimeout="true"上傳時是否使用逾時機制
enableLookups="false"--是否反查網域名稱,預設值為true。為了提高處理能力,應設定為false
compression="on" 開啟壓縮功能 。壓縮會增加Tomcat負擔,最好採用Nginx + Tomcat 或者 Apache + Tomcat 方式,壓縮交由Nginx/Apache 去做。
compressionMinSize="10240"啟用壓縮的輸出內容大小,預設為2KB
noCompressionUserAgents="gozilla, traviata" 對於以下的瀏覽器,不啟用壓縮
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" 哪些資源類型需要壓縮
5.小結
關於Tomcat的Nio和ThreadPool,本身的引入就提高了處理的複雜性,所以對於效率的提高有多少,需要實際驗證一下。
三、設定session到期時間
conf\web.xml中通過參數指定:
<session-config> <session-timeout>180</session-timeout> </session-config> 單位為分鐘。
四、Apr外掛程式提高Tomcat效能
Tomcat可以使用APR來提供超強的延展性和效能,更好地整合本機伺服器技術.
APR(Apache Portable Runtime)是一個高可移植庫,它是Apache HTTP Server 2.x的核心。APR有很多用途,包括訪問進階IO功能(例如sendfile,epoll和OpenSSL),OS層級功能(隨機數產生,系統狀態等等),本地進程管理(共用記憶體,NT管道和UNIX sockets)。這些功能可以使Tomcat作為一個通常的前台WEB伺服器,能更好地和其它本地web技術整合,總體上讓Java更有效率作為一個高效能web伺服器平台而不是簡單作為後台容器。
在產品環境中,特別是直接使用Tomcat做WEB伺服器的時候,應該使用Tomcat Native來提高其效能
要測APR給tomcat帶來的好處最好的方法是在慢速網路上(類比Internet),將Tomcat線程數開到300以上的水平,然後類比一大堆並發請求。
如果不配APR,基本上300個線程狠快就會用滿,以後的請求就只好等待。但是配上APR之後,並發的線程數量明顯下降,從原來的300可能會馬上下降到只有幾十,新的請求會毫無阻塞的進來。
在區域網路環境測,就算是400個並發,也是一瞬間就處理/傳輸完畢,但是在真實的Internet環境下,頁面處理時間只佔0.1%都不到,絕大部分時間都用來頁面傳輸。如果不用APR,一個線程同一時間只能處理一個使用者,勢必會造成阻塞。所以生產環境下用apr是非常必要的。
(1)安裝APR tomcat-native apr-1.3.8.tar.gz 安裝在/usr/local/apr #tar zxvf apr-1.3.8.tar.gz #cd apr-1.3.8 #./configure;make;make install apr-util-1.3.9.tar.gz 安裝在/usr/local/apr/lib #tar zxvf apr-util-1.3.9.tar.gz #cd apr-util-1.3.9 #./configure --with-apr=/usr/local/apr ----with-java-home=JDK;make;make install #cd apache-tomcat-6.0.20/bin #tar zxvf tomcat-native.tar.gz #cd tomcat-native/jni/native #./configure --with-apr=/usr/local/apr;make;make install (2)設定 Tomcat 整合 APR 修改 tomcat 的啟動 shell (startup.sh),在該檔案中加入啟動參數: CATALINA_OPTS="$CATALINA_OPTS -Djava.library.path=/usr/local/apr/lib" 。 (3)判斷安裝成功: 如果看到下面的開機記錄,表示成功。 2007-4-26 15:34:32 org.apache.coyote.http11.Http11AprProtocol init
五、叢集方案
單個Tomcat的處理效能是有限的,當並發量較大的時候,就需要有部署多套來進行負載平衡了。
叢集的關鍵點有以下幾點:
1.引入負載端
軟負載可以使用nginx或者apache來進行,主要是使用一個分發的功能
參考:
http://ajita.iteye.com/blog/1715312(nginx負載)
http://ajita.iteye.com/blog/1717121(apache負載)
2.共用session處理
目前的處理方式有如下幾種:
1).使用Tomcat本身的Session複製功能
參考http://ajita.iteye.com/blog/1715312(Session複製的配置)
方案的有點是配置簡單,缺點是當叢集數量較多時,Session複製的時間會比較長,影響響應的效率
2).使用第三方來存放共用Session
目前用的較多的是使用memcached來管理共用Session,藉助於memcached-sesson-manager來進行Tomcat的Session管理
參考http://ajita.iteye.com/blog/1716320(使用MSM管理Tomcat叢集session)
3).使用黏性session的策略
對於會話要求不太強(不涉及到計費,失敗了允許重新請求下等)的場合,同一個使用者的session可以由nginx或者apache交給同一個Tomcat來處理,這就是所謂的session sticky策略,目前應用也比較多
參考:http://ajita.iteye.com/blog/1848665(tomcat session sticky)
nginx預設不包含session sticky模組,需要重新編譯才行(windows下我也不知道怎麼重新編譯)
優點是處理效率高多了,缺點是強會話要求的場合不合適
3、每個網站一個執行個體。啟動多個tomcat.
不要使用Tomcat的虛擬機器主機,每個網站一個執行個體。即,啟動多個tomcat.
這也是PHP營運在這裡常犯的錯誤,PHP的做法是一個Web下面放置多個虛擬機器主機,而不是每個主機啟動一個web伺服器。Tomcat 是多線程,共用記憶體,任何一個虛擬機器主機中的應用出現崩潰,會影響到所有應用程式。採用多個執行個體方式雖然開銷比較大,但保證了應用程式隔離與安全。
4.小結
以上是實現叢集的要點,其中1和2可以組合使用,具體情境具體分析吧~
六、問題定位
對於Tomcat的處理耗時較長的問題主要有當時的並發量、session數、記憶體及記憶體的回收等幾個方面造成的。出現問題之後就要進行分析了。
1.關於Tomcat的session數目
這個可以直接從Tomcat的web管理介面去查看即可
或者藉助於第三方工具Lambda Probe來查看,它相對於Tomcat內建的管理稍微多了點功能,但也不多
2.監視Tomcat的記憶體使用量情況
使用JDK內建的jconsole可以比較明了的看到記憶體的使用方式,線程的狀態,當前載入的類的總量等
JDK內建的jvisualvm可以下載外掛程式(如GC等),可以查看更豐富的資訊。如果是分析本地的Tomcat的話,還可以進行記憶體抽樣等,檢查每個類的使用方式
3.列印類的載入情況及對象的回收情況
這個可以通過配置JVM的啟動參數,列印這些資訊(到螢幕(預設也會到catalina.log中)或者檔案),具體參數如下:
-XX:+PrintGC:輸出形式:[GC 118250K->113543K(130112K), 0.0094143 secs] [Full GC 121376K->10414K(130112K), 0.0650971 secs]
-XX:+PrintGCDetails:輸出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]
-XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可與上面兩個混合使用,輸出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-XX:+PrintGCApplicationConcurrentTime:列印每次記憶體回收前,程式未中斷的執行時間。可與上面混合使用。輸出形式:Application time: 0.5291524 seconds
-XX:+PrintGCApplicationStoppedTime:列印記憶體回收期間程式暫停時間。可與上面混合使用。輸出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:PrintHeapAtGC: 列印GC前後的詳細堆棧資訊
-Xloggc:filename:與上面幾個配合使用,把相關日誌資訊記錄到檔案以便分析
-verbose:class 監視載入的類的情況
-verbose:gc 在虛擬機器發生記憶體回收時在輸出裝置顯示資訊
-verbose:jni 輸出native方法調用的相關情況,一般用於診斷jni調用錯誤資訊
4.添加JMS遠程監控
對於部署在區域網路內其它機器上的Tomcat,可以開啟JMX監控連接埠,區域網路其它機器就可以通過這個連接埠查看一些常用的參數(但一些比較複雜的功能不支援),同樣是在JVM啟動參數中配置即可,配置如下:
-Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=192.168.71.38 設定JVM的JMS監控監聽的IP地址,主要是為了防止錯誤的監聽成127.0.0.1這個內網地址
-Dcom.sun.management.jmxremote.port=1090 設定JVM的JMS監控的連接埠
-Dcom.sun.management.jmxremote.ssl=false 設定JVM的JMS監控不實用SSL
-Dcom.sun.management.jmxremote.authenticate=false 設定JVM的JMS監控不需要認證
5.專業點的分析工具有
IBM ISA,JProfiler等,具體監控及分析方式去網上搜尋即可。