一. jvm參數調優
常見的生產環境tomcat啟動腳本里常見如下的參數,我們依次來解釋各個參數意義.
export JAVA_OPTS="-server -Xms1400M -Xmx1400M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=31 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true "
-server
如果tomcat是運行在生產環境中的,這個參數必須加上,-server參數可以使tomcat以server模式運行,這個模式下將擁有:更大、更高的並發處理能力,更快更強捷的JVM垃圾回收機 制,可以有更大的負載與吞吐量
-Xms<size>和-Xmx<size>
前者表示JVM初始化堆的大小,后者表示JVM堆的最大值。一般認為把Xms與Xmx兩個值設成一樣是最優的做法,否則會導致jvm有較為頻繁的GC,影響系統性能。因此一開始我們就把這兩個設成一樣,使得Tomcat在啟動時就為最大化參數充分利用系統的效率。 如何確定當前OS jvm最大可用內存呢?在命令行下執行
java -Xmx2048 -version
命令,如果提示下圖的信息,則證明當前內存數可以用
如果提示下面的錯誤,則當前數值不可用.
-Xss
設定每個線程的堆棧大小。依據具體應用,看一個線程大約占用多少內存、有多少線程同時運行等。一般不宜設置超過1M,要不然容易出現out ofmemory
–Xmn
設置年輕代大小為512m。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代后,將會減小年老代大小。此值對系統性能影響較大,Sun 官方推薦配置為整個堆的3/8。
-XX:+AggressiveOpts
啟用這個參數,則每當JDK版本升級時,你的JVM都會使用最新加入的優化技術(如果有的話)
-XX:+UseBiasedLocking
啟用一個優化了的線程鎖。對於應用服務器(ApplicationServer)來說每個http請求就是一個線程,由於請求需要的時長不一,在並發較大的時候會有請求排隊、甚至還會出現線程阻塞的現象,這個配置可以改善這個問題。
-XX:PermSize 和 -XX:MaxPermSize
JVM使用-XX:PermSize設置非堆內存初始值,默認是物理內存的1/64;使用XX:MaxPermSize設置最大非堆內存的大小,默認是物理內存的1/4。
XX:MaxPermSize設置過小會導致java.lang.OutOfMemoryError,說說為什么會內存益出:
(1)這一部分內存用於存放Class和Meta的信息,Class在被 Load的時候被放入PermGen space區域,它和存放Instance的Heap區域不同。
(2)GC(Garbage Collection)不會在主程序運行期對PermGen space進行清理,所以如果你的APP會LOAD很多CLASS 的話,就很可能出現PermGen space錯誤。
這種錯誤常見在web服務器對JSP進行pre compile的時候。
XX:+DisableExplicitGC
在程序代碼中不允許有顯示的調用”System.gc()”。
-XX:+UseParNewGC
對年輕代采用多線程並行回收,這樣收得快。
-XX:+UseConcMarkSweepGC
即CMS gc,這一特性只有jdk1.5即后續版本才具有的功能,它使用的是gc估算觸發和heap占用觸發。
我們知道頻頻繁的GC會造面JVM的大起大落從而影響到系統的效率,使用了CMS GC后可以在GC次數增多的情況下使每次GC的響應時間卻很短。
-XX:MaxTenuringThreshold
設置垃圾最大年齡。如果設置為0的話,則年輕代對象不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。
如果將此值設置為一個較大值,則年輕代對象會在Survivor區進行多次復制,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概率。
這個值的設置是根據本地的jprofiler監控后得到的一個理想的值,不能一概而論原搬照抄。
-XX:+CMSParallelRemarkEnabled
在使用UseParNewGC 的情況下, 盡量減少 mark 的時間
-XX:+UseCMSCompactAtFullCollection
在使用concurrent gc 的情況下, 防止 memoryfragmention, 對live object 進行整理, 使 memory 碎片減少。
-XX:LargePageSizeInBytes
指定 Java heap的分頁頁面大小
-XX:+UseFastAccessorMethods
get,set 方法轉成本地代碼
-XX:+UseCMSInitiatingOccupancyOnly
指示只有在 oldgeneration 在使用了初始化的比例后concurrent collector 啟動收集
-XX:CMSInitiatingOccupancyFraction=70
CMSInitiatingOccupancyFraction,這個參數設置有很大技巧,基本上滿足
(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就不會出現promotion failed。
在我的應用中Xmx是6000,Xmn是512,那么Xmx-Xmn是5488兆,也就是年老代有5488 兆,CMSInitiatingOccupancyFraction=90
說明年老代到90%滿的時候開始執行對年老代的並發垃圾回收(CMS),這時還 剩10%的空間是5488*10%=548兆,
所以即使Xmn(也就是年輕代共512兆)里所有對象都搬到年老代里,548兆的空間也足夠了,所以只要滿足上面的公式
,就不會出現垃圾回收時的promotion failed;因此這個參數的設置必須與Xmn關聯在一起。
-Djava.awt.headless=true
這個參數一般我們都是放在最后使用的,這全參數的作用是這樣的,有時我們會在我們的J2EE工程中使用一些圖表工具如:jfreechart,用於在web網頁輸出GIF/JPG等流,在winodws環境下,一般我們的app server在輸出圖形時不會碰到什么問題,但是在linux/unix環境下經常會碰到一個exception導致你在winodws開發環境下圖片顯示的好好可是在linux/unix下卻顯示不出來,因此加上這個參數以免避這樣的情況出現。
-Dsun.net.client.defaultConnectTimeout=60000
連接建立超時設置
-Dsun.net.client.defaultReadTimeout=60000
內容獲取超時設置
-Djmagick.systemclassloader
生成縮略圖的一個框架的配置=60000
-Dnetworkaddress.cache.ttl=300
jvm dns緩存超時的設置
-Dsun.net.inetaddr.ttl=300
jvm dns緩存超時的設置
二 .tomcat配置優化
在tomcat的server.xml中有類似:
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="60000"
redirectPort="8443"
maxThreads="5000"
acceptCount="500"
minSpareThreads="100"
maxSpareThreads="5000"
enableLookups="false"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"
disableUploadTimeout="true"
URIEncoding="UTF-8"/>
的配置, 其中:
port: 服務端口
protocol: 服務協議
connectionTimeout: 超時時間單位是ms,並發要求高的話,將此值減少!
redirectPort: 重定向端口 需要安全通信的場合,將把客戶請求轉發至SSL的redirectPort端口
acceptCount: 當指定的連接數被用盡時,可放到出列隊列中的數量,也即可接受的排隊數量.
maxThreads: Tomcat可創建的最大的線程數(每一個線程對應一個請求), maxThreads決定了tomcat的最大線程閥值,需要設置的大一些
minSpareThreads: 最小備用(空閑)線程數
maxSpareThreads: 最大備用(空閑)線程數,如果空閑線程超過這個值,Tomcat就會關閉不活動線程;
enableLookups: 關閉DNS查詢
URIEncoding: 設置tomcat默認的轉碼格式 查看$TOMCAT_HOME/webapps/tomcat-docs/config/http.html這個說明文檔,有如下說明:
URIEncoding:This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used.
也就是說,如果沒有設置URIEncoding, Tomcat默認是按ISO-8859-1進行URL解碼,ISO-8859-1並未包括中文字符,這樣的話中文字符肯定就不能被正確解析了。
useURIValidationHack: 如果把useURIValidationHack設成"false",可以減少它對一些url的不必要的檢查從而減省開銷。
disableUploadTimeout:
compression、compressionMinSize、 compressableMimeType:omcat配置gzip壓縮(HTTP壓縮)功能
1)compression="on" 打開壓縮功能
2)compressionMinSize="2048" 啟用壓縮的輸出內容大小,這里面默認為2KB
3)noCompressionUserAgents="gozilla, traviata" 對於以下的瀏覽器,不啟用壓縮
4)compressableMimeType="text/html,text/xml" 壓縮類型
在實現中,我們發現使用該配置,連接數上去之后很難下降,導致CPU一直維持在一個比較高的水平. 后來我們換了一種連接方式,采用線程池的方式,首先定義一個Executor:
<Executor name="tomcatThreadPool" namePrefix="tomcatThreadPool-" maxThreads="1000" maxIdleTime="300000" minSpareThreads="200"/>
參數的意義和上述相同 ,在Connector中使用定義的這個連接池:
<Connector executor="tomcatThreadPool" port="20003" protocol="HTTP/1.1" acceptCount="800" minProcessors="300" maxProcessors = "1000" redirectPort="8443"/>
此處 minProcessors 參數對應前一種配置方式中的minSpareThreads, maxProcessors則與maxThreads意義差不多.
使用連接池以后: 發現連接數上升之后如果一段時間內請求數下降了,連接數會很快下降,CPU的消耗也會隨之下降,處理能力得到了增強.
補充:
如何查看當前tomcat的連接數呢?
假設服務器上開啟了 2個tomcat實例,分別監聽8040和8050端口
netstat -na | grep ESTAB | grep 8040 | wc -l netstat -na | grep ESTAB | grep 8050 | wc -l
二者之和,就是所有tomcat的連接數