注意:調優tomcat需要了解使用的tomcat是什么版本,隨着tomcat版本發展有新參數引入,同時有舊參數廢棄。本文檔以tomcat7為例進行調優
一. 線程池(Thread Pool)優化
編輯“Tomcat安裝目錄/conf/server.xml”文件,找到如下內容
<!-- <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/> --> |
取消注釋,參數做如下調整
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="1000" minSpareThreads="25" maxIdleTime="600000" acceptCount="500"/> |
參數說明:
name 這個是線程池的名字,必須唯一,默認即可,我們在后面的配置里要用到這個東西
namePrefix 線程的名字前綴,用來標記線程名字的,這樣每個線程就用這個前綴加上線程編號了,比如 catalina-exec-1 catalina-exec-2
maxThreads 線程池可以容納的最大線程數,tomcat使用線程來處理接收的請求每一個線程處理一個請求,這個值決定了同時能夠處理的最大請求數,缺省值為200
minSpareThreads 最小的保持活躍的線程數量,缺省值為4(tomcat5有此參數,而tomcat6無此參數,到了tomcat7又重新使用此參數,順便提下5和7中這兩個參數含義並不相同有興趣可以查看官方文檔)
maxIdleTime 關閉一個空閑線程之前允許空閑線程持續的時間,只有當前空閑線程數大於minSpareThread的值,才會關閉空閑線程
acceptCount 當所有可用的請求處理線程都被使用的時候,連接請求隊列的最大長度。當該隊列滿了以后的所有請求都被拒絕,缺省值為10
順便提下如下3個參數maxSpareThreads、maxProcessors和minProcessors
maxSpareThreads:允許存在的空閑線程的最大數量,tomcat5及以前版本才有的參數,tomcat6和tomcat7均無此參數 |
二. 連接器(Connector)優化
編輯“Tomcat安裝目錄/conf/server.xml”文件,找到如下內容將其注釋掉
<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> |
再找到如下內容,取消注釋
<!-- <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> --> |
參數做如下調整
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" URIEncoding="UTF-8" enableLookups="false" disableUploadTimeout="true" connectionTimeout="20000" keepAliveTimeout="15000" maxKeepAliveRequests="1000" useURIValidationHack="false" compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" redirectPort="8443"/> |
AJP/1.3協議負責和其他HTTP服務器建立連接,監聽的是8009端口,比如tomcat和apache或者iis集成時使用這個連接器,此時則需優化8009端口的Connector。
<!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" protocol="AJP/1.3" URIEncoding="UTF-8" enableLookups="false" disableUploadTimeout="true" connectionTimeout="20000" keepAliveTimeout="15000" maxKeepAliveRequests="1000" useURIValidationHack="false" compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" redirectPort="8443" /> |
參數說明:
executor="tomcatThreadPool" 在 Connector里指定使用共享線程池的名稱
port="8080" 指定服務器端要創建的端口號,並在這個端口監聽來自客戶端的請求
protocol="HTTP/1.1" 負責建立HTTP連接,web應用通過瀏覽器訪問tomcat服務器用的就是這個連接器,默認監聽的是8080端口。所以我們優化的是8080端口的Connector
URIEncoding="UTF-8" URI解碼所使用的字符集,只影響GET請求的URI解碼,不影響post的解碼
enableLookups="false" 禁用DNS查詢,默認值為true,為了提高處理能力應設置為false
disableUploadTimeout="true" 允許servlet container在一個servlet執行的時候,使用一個不同的,更長的連接超時。最終的結果是給servlet更長的時間以便完成其執行,或者在數據上載的時候更長的超時時間。如果沒有指定默認為false
connectionTimeout="20000" 在Connector接受一個連接以后,等待發生第一個請求的時間,單位毫秒。缺省值為60000(60秒)
keepAliveTimeout="15000" 在一個長連接中2次請求之間的最大間隔時間,超過此時間連接斷開,單位毫秒
maxKeepAliveRequests="1000" 在server關閉連接之前,接受的HTTP請求的最大數目。如果該值設為1,會禁止HTTP/1.0保活,同時也會禁止HTTP/1.1保活和pipelining。如果沒有指定默認值100。
useURIValidationHack="false" 減少它對一些url的不必要的檢查從而減省開銷
compression="on" 設為on開啟Connector使用HTTP/1.1的GZIP壓縮,可節省服務器帶寬
compressionMinSize="2048" 啟用壓縮的輸出內容大小,這里面設置為2KB
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" 壓縮文件的類型
redirectPort="8443" 如果Connector支持非SSL請求,在收到一個要求使用SSL傳輸的請求以后,Catalina會自動將該請求重定向到這里指定的端口號
三. JAVA虛擬機(JVM)優化
注意調優JVM需要了解使用的JDK是什么版本,隨着JDK版本發展有新參數引入,同時有舊參數廢棄。本文檔以JDK7為例進行調優
下圖為JDK7及之前老JDK版本的JVM內存結構圖,優化JVM前必須清楚它的內存結構,有興趣可以多查資料了解,在此不做過多描述。
JDK7的JVM內存由Heap(堆空間)和Perm(持久代)組成. 其中Heap = {Old + young = { Eden , from, to } }
JDK8的JVM已經將Perm(持久代)從內存空間移除
Linux平台,編輯“Tomcat安裝目錄/conf/catalina.sh”文件,該文件開頭是一大段由#包裹的注釋,在注釋的最后添加如下內容
export JAVA_OPTS="-server -Xms3072M -Xmx3072M -Xmn512M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSMaxAbortablePrecleanTime=5 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -Djava.awt.headless=true" |
如果想要打印JVM運行日志信息,則可以再添加如下參數,-Xloggs指定日志路徑
-Xloggc:/path/jvm.log -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCDetails |
Windows平台,則編輯“Tomcat安裝目錄/conf/catalina.bat”文件
set JAVA_OPTS=-server -Xms3072M -Xmx3072M -Xmn512M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSMaxAbortablePrecleanTime=5 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -Djava.awt.headless=true |
如果想要打印JVM運行日志信息,則可以再添加如下參數,-Xloggs指定日志路徑
-Xloggc:D:\path\jvm.log -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCDetails |
參數說明:
-server 指定JAVA虛擬機運行在server模式
-Xms 初始Heap內存大小,本文檔設置了3G,需要結合服務器CPU核數,內存總量等實際情況來設置合適數值,此值並非越大越好,過大將增加垃圾回收的壓力
-Xmx 最大Heap內存大小,本文檔設置了3G,需要結合服務器CPU核數,內存總量等實際情況來設置合適數值,此值並非越大越好,過大將增加垃圾回收的壓力
-Xmn 新生代內存大小
-Xss 每個線程的堆棧大小
-XX:+AggressiveOpts 啟用JVM開發團隊最新的調優成果,例如:編譯優化,偏向鎖,並行老年代收集,JDK5.6后引入,JDK6默認開啟
-XX:+UseBiasedLocking 啟用一個優化了的線程鎖(偏向鎖),JDK5.6后引入,JDK6默認開啟
-XX:PermSize 初始持久代內存大小,需要注意永久代在JDK8中被完全的移除了,永久代的參數-XX:PermSize和-XX:MaxPermSize也被移除了
-XX:MaxPermSize 最大持久代內存大小,需要注意永久代在JDK8中被完全的移除了,永久代的參數-XX:PermSize和-XX:MaxPermSize也被移除了
-XX:+DisableExplicitGC 禁止顯示的調用System.gc()方法進行GC
-XX:+UseConcMarkSweepGC 使用並發標記清除(CMS)垃圾收集器 它是對年老代進行垃圾收集的。CMS收集器通過多線程並發進行垃圾回收,盡量減少垃圾收集造成的停頓。采用這種垃圾收集器默認會開啟-XX:+UseParNewGC參數對新生代使用Parallel GC(並行垃圾回收器)
-XX:+UseParNewGC 新生代使用Parallel GC(並行垃圾回收器),如果老年代使用了CMS垃圾回收期,則新生代默認就是這種垃圾回收器
-XX:+CMSParallelRemarkEnabled CMS垃圾回收器回收對象時,應用有2次停頓,第一次是初始標記,第二次是重新標記,開啟並行remark可以降低重新標記停頓時間,
-XX:+UseCMSCompactAtFullCollection CMS不會整理堆碎片,為了防止堆碎片引起full gc,設置此參數使CMS垃圾回收時進行合並碎片,開啟這個選項一定程度上會影響性能
-XX:CMSMaxAbortablePrecleanTime
-XX:+CMSClassUnloadingEnabled 開啟CMS回收持久代,避免Perm區滿引起的full gc
-XX:LargePageSizeInBytes 指定Java heap的分頁頁面大小
-XX:+UseFastAccessorMethods 將get(),set()方法轉成本地代碼,默認開啟
-XX:+UseCMSInitiatingOccupancyOnly 只有達到-XX:CMSInitiatingOccupancyFraction指定的使用百分比才進行老年代的垃圾回收
-XX:CMSInitiatingOccupancyFraction 指定老年代在使用了多少百分比空間時開始進行垃圾回收,JDK5默認68%,JDK6默認92%
-Djava.awt.headless 解決J2EE工程中的圖表工具在Linux/Unix環境下會導致圖片顯示不出來
-Xloggc 指定JVM日志輸出到文件
-XX:+PrintGCDateStamps 打印GC發生的時間,JDK6和JDK7才支持,如果是JDK5請使用-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationStoppedTime 打印GC造成應用停頓的時間
-XX:+PrintGCApplicationConcurrentTime 打印GC時應用並發執行的時間
-XX:+PrintGCDetails 打印GC詳細信息
四. 調整Tomcat Connector的運行模式
首先大致了解Tomcat Connector的三種運行模式:bio、nio和apr
bio
bio(blocking I/O),顧名思義,即阻塞式I/O操作,表示Tomcat使用的是傳統的Java I/O操作(即java.io包及其子包)。Tomcat在默認情況下,就是以bio模式運行的。遺憾的是,就一般而言,bio模式是三種運行模式中性能最低的一種。我們可以通過Tomcat Manager來查看服務器的當前狀態。
nio
nio(new I/O),是Java SE 1.4及后續版本提供的一種新的I/O操作方式(即java.nio
包及其子包)。Java nio是一個基於緩沖區、並能提供非阻塞I/O操作的Java API,因此nio也被看成是non-blocking I/O
的縮寫。它擁有比傳統I/O操作(bio)更好的並發運行性能。要讓Tomcat以nio模式來運行也比較簡單,我們只需要在Tomcat安裝目錄/conf/server.xml
文件中將如下配置:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> |
中的protocol屬性值改為org.apache.coyote.http11.Http11NioProtocol
即可
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443" /> |
此時,我們就可以在Tomcat Manager中看到當前服務器狀態頁面的HTTP協議的Connector運行模式已經從http-bio-8080
變成了
apr
apr(Apache Portable Runtime/Apache可移植運行時),是Apache HTTP服務器的支持庫。你可以簡單地理解為,Tomcat將以JNI的形式調用Apache HTTP服務器的核心動態鏈接庫來處理文件讀取或網絡傳輸操作,從而大大地提高Tomcat對靜態文件的處理性能。 Tomcat apr也是在Tomcat上運行高並發應用的首選模式。如果我們的Tomcat不是在apr模式下運行,在啟動Tomcat的時候,我們可以在日志信息中看到類似如下信息:
2015-12-13 16:17:49 org.apache.catalina.core.AprLifecycleListener init 信息: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: xxx/xxx(這里是路徑信息) |
Tomcat apr運行模式的配置是三種運行模式之中相對比較麻煩的一種。據官方文檔所述,Tomcat apr模式需要安裝以下三個組件:
• APR library[APR庫]
• JNI wrappers for APR used by Tomcat (libtcnative) [在Windows操作系統上,就是一個名為tcnative-1.dll的動態鏈接庫文件]
• OpenSSL libraries[OpenSSL庫]
Tomcat6.x從6.0.32開始以及Tomcat7.x從7.0.30開始,Windows版的Tomcat已經在bin目錄下自帶了tcnative-1.dll
等文件,並且啟動后默認就運行在apr模式下,因此對於Windows操作系統我們只需要下載最新版本的Tomcat直接使用即可。而Linux版的Tomcat在bin目錄下自帶的是tomcat-native.tar.gz,這個包是需要和APR庫一起編譯安裝后才能使用的。
2015-12-13 15:17:05 org.apache.catalina.core.AprLifecycleListener init 信息: Loaded APR based Apache Tomcat Native library 1.1.20. 2015-12-13 15:17:05 org.apache.catalina.core.AprLifecycleListener init 信息: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true]. 2015-12-13 15:17:05 org.apache.coyote.http11.Http11AprProtocol init |
apr-iconv-1.2.1.tar.gz
apr-util-1.5.4.tar.gz
tar zxvf apr-1.5.2.tar cd apr-1.5.2 ./configure --prefix=/usr/local/apr make make install |
tar -zxvf apr-iconv-1.2.1.tar.gz cd apr-iconv-1.2.1 ./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr make make install |
tar zxvf apr-util-1.5.4.tar.gz cd apr-util-1.5.4 ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-apr-iconv=/usr/local/apr-iconv/bin/apriconv make make install |
tar zxvf tomcat-native-1.2.2-src.tar.gz cd tomcat-native-1.2.2-src/native ./configure --with-apr=/usr/local/apr --with-java-home=/usr/java/jdk1.7.0_80 --with-ssl=yes make make install |
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib
Jul 20, 2011 15:27:32 PM org.apache.catalina.core.AprLifecycleListener init INFO: Loaded APR based Apache Tomcat Native library 1.1.20. |