1. 程式人生 > >Tomcat 調優及 JVM 引數優化

Tomcat 調優及 JVM 引數優化

Tomcat 的預設配置是不能穩定長期執行的,也就是不適合生產環境,它會宕機,讓你不斷重新啟動,甚至在午夜時分喚醒你。對於作業系統優化來說,是儘可能的增大可使用的記憶體容量、提高CPU 的頻率,保證檔案系統的讀寫速率等。經過壓力測試驗證,在併發連線很多的情況下,CPU 的處理能力越強,系統執行速度越快。

Tomcat 7.png

Tomcat 的優化不像其它軟體那樣,簡簡單單的修改幾個引數就可以了,它的優化主要有三方面,分為系統優化,Tomcat 本身的優化,Java 虛擬機器(JVM)調優。系統優化就不在介紹了,接下來就詳細的介紹一下 Tomcat 本身與 JVM 優化,以 Tomcat 7 為例。

一、Tomcat 本身優化

Tomcat 的自身引數的優化,這塊很像 ApacheHttp Server。修改一下 xml 配置檔案中的引數,調整最大連線數,超時等。此外,我們安裝 Tomcat 是,優化就已經開始了。

1、工作方式選擇

為了提升效能,首先就要對程式碼進行動靜分離,讓 Tomcat 只負責 jsp 檔案的解析工作。如採用 Apache 和 Tomcat 的整合方式,他們之間的連線方案有三種選擇,JK、http_proxy 和 ajp_proxy。相對於 JK 的連線方式,後兩種在配置上比較簡單的,靈活性方面也一點都不遜色。但就穩定性而言不像JK 這樣久經考驗,所以建議採用 JK 的連線方式。 

2、Connector 聯結器的配置

之前檔案介紹過的 Tomcat 聯結器的三種方式: bio、nio 和 apr,三種方式效能差別很大,apr 的效能最優, bio 的效能最差。而 Tomcat 7 使用的 Connector  預設就啟用的 Apr 協議,但需要系統安裝 Apr 庫,否則就會使用 bio 方式。

3、配置檔案優化

配置檔案優化其實就是對 server.xml 優化,可以提大大提高 Tomcat 的處理請求的能力,下面我們來看 Tomcat 容器內的優化。

預設配置下,Tomcat 會為每個聯結器建立一個繫結的執行緒池(最大執行緒數 200),服務啟動時,預設建立了 5 個空閒執行緒隨時等待使用者請求。

首先,開啟 ${TOMCAT_HOME}/conf/server.xml,搜尋【<Executor name="tomcatThreadPool"】,開啟並調整為

1 2 <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500" minSpareThreads="20" maxSpareThreads="50" maxIdleTime="60000"/>

注意, Tomcat 7 在開啟執行緒池前,一定要安裝好 Apr 庫,並可以啟用,否則會有錯誤報出,shutdown.sh 指令碼無法關閉程序。

然後,修改<Connector …>節點,增加 executor 屬性,搜尋【port="8080"】,調整為

1 2 3 4 5 6 7 8 9 10 11 12 13 14 <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" URIEncoding="UTF-8" connectionTimeout="30000" enableLookups="false" disableUploadTimeout="false" connectionUploadTimeout="150000" acceptCount="300" keepAliveTimeout="120000" maxKeepAliveRequests="1" compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,image/gif,image/jpg,image/png"  redirectPort="8443" />

maxThreads :Tomcat 使用執行緒來處理接收的每個請求,這個值表示 Tomcat 可建立的最大的執行緒數,預設值是 200

minSpareThreads:最小空閒執行緒數,Tomcat 啟動時的初始化的執行緒數,表示即使沒有人使用也開這麼多空執行緒等待,預設值是 10。

maxSpareThreads:最大備用執行緒數,一旦建立的執行緒超過這個值,Tomcat 就會關閉不再需要的 socket 執行緒。

上邊配置的引數,最大執行緒 500(一般伺服器足以),要根據自己的實際情況合理設定,設定越大會耗費記憶體和 CPU,因為 CPU 疲於執行緒上下文切換,沒有精力提供請求服務了,最小空閒執行緒數 20,執行緒最大空閒時間 60 秒,當然允許的最大執行緒連線數還受制於作業系統的核心引數設定,設定多大要根據自己的需求與環境。當然執行緒可以配置在“tomcatThreadPool”中,也可以直接配置在“Connector”中,但不可以重複配置。

URIEncoding:指定 Tomcat 容器的 URL 編碼格式,語言編碼格式這塊倒不如其它 WEB 伺服器軟體配置方便,需要分別指定。

connnectionTimeout: 網路連線超時,單位:毫秒,設定為 0 表示永不超時,這樣設定有隱患的。通常可設定為 30000 毫秒,可根據檢測實際情況,適當修改。

enableLookups: 是否反查域名,以返回遠端主機的主機名,取值為:true 或 false,如果設定為false,則直接返回IP地址,為了提高處理能力,應設定為 false。

disableUploadTimeout:上傳時是否使用超時機制。

connectionUploadTimeout:上傳超時時間,畢竟檔案上傳可能需要消耗更多的時間,這個根據你自己的業務需要自己調,以使Servlet有較長的時間來完成它的執行,需要與上一個引數一起配合使用才會生效。

acceptCount:指定當所有可以使用的處理請求的執行緒數都被使用時,可傳入連線請求的最大佇列長度,超過這個數的請求將不予處理,預設為100個。

keepAliveTimeout:長連線最大保持時間(毫秒),表示在下次請求過來之前,Tomcat 保持該連線多久,預設是使用 connectionTimeout 時間,-1 為不限制超時。

maxKeepAliveRequests:表示在伺服器關閉之前,該連線最大支援的請求數。超過該請求數的連線也將被關閉,1表示禁用,-1表示不限制個數,預設100個,一般設定在100~200之間。

compression:是否對響應的資料進行 GZIP 壓縮,off:表示禁止壓縮;on:表示允許壓縮(文字將被壓縮)、force:表示所有情況下都進行壓縮,預設值為off,壓縮資料後可以有效的減少頁面的大小,一般可以減小1/3左右,節省頻寬。

compressionMinSize:表示壓縮響應的最小值,只有當響應報文大小大於這個值的時候才會對報文進行壓縮,如果開啟了壓縮功能,預設值就是2048。

compressableMimeType:壓縮型別,指定對哪些型別的檔案進行資料壓縮。

noCompressionUserAgents="gozilla, traviata": 對於以下的瀏覽器,不啟用壓縮。

如果已經對程式碼進行了動靜分離,靜態頁面和圖片等資料就不需要 Tomcat 處理了,那麼也就不需要配置在 Tomcat 中配置壓縮了。

以上是一些常用的配置引數屬性,當然還有好多其它的引數設定,還可以繼續深入的優化,HTTP Connector 與 AJP Connector 的引數屬性值,可以參考官方文件的詳細說明:

二、JVM 優化

 Tomcat 啟動命令列中的優化引數,就是 JVM 的優化 。Tomcat 首先跑在 JVM 之上的,因為它的啟動其實也只是一個 java 命令列,首先我們需要對這個 JAVA 的啟動命令列進行調優。不管是 YGC 還是 Full GC,GC 過程中都會對導致程式執行中中斷,正確的選擇不同的 GC 策略,調整 JVM、GC 的引數,可以極大的減少由於 GC 工作,而導致的程式執行中斷方面的問題,進而適當的提高 Java 程式的工作效率。但是調整 GC 是以個極為複雜的過程,由於各個程式具備不同的特點,如:web 和 GUI 程式就有很大區別(Web可以適當的停頓,但GUI停頓是客戶無法接受的),而且由於跑在各個機器上的配置不同(主要 cup 個數,記憶體不同),所以使用的 GC 種類也會不同。

1、JVM 引數配置方法

Tomcat 的啟動引數位於安裝目錄 ${JAVA_HOME}/bin目錄下,Linux 作業系統就是 catalina.sh 檔案。JAVA_OPTS,就是用來設定 JVM 相關執行引數的變數,還可以在 CATALINA_OPTS 變數中設定。關於這 2 個變數,還是多少有些區別的:

JAVA_OPTS:用於當 Java 執行時選項“start”、“stop”或“run”命令執行。

CATALINA_OPTS:用於當 Java 執行時選項“start”或“run”命令執行。

為什麼有兩個不同的變數?它們之間都有什麼區別呢?

首先,在啟動 Tomcat 時,任何指定變數的傳遞方式都是相同的,可以傳遞到執行“start”或“run”命令中,但只有設定在 JAVA_OPTS 變數裡的引數被傳遞到“stop”命令中。對於 Tomcat 執行過程,可能沒什麼區別,影響的是結束程式,而不是啟動程式。

第二個區別是更微妙,其他應用程式也可以使用 JAVA_OPTS 變數,但只有在 Tomcat 中使用 CATALINA_OPTS 變數。如果你設定環境變數為只使用 Tomcat,最好你會建議使用 CATALINA_OPTS 變數,而如果你設定環境變數使用其它的 Java 應用程式,例如 JBoss,你應該把你的設定放在JAVA_OPTS 變數中。

2、JVM 引數屬性

32 位系統下 JVM 對記憶體的限制:不能突破 2GB ,那麼這時你的 Tomcat 要優化,就要講究點技巧了,而在 64 位作業系統上無論是系統記憶體還是 JVM 都沒有受到 2GB 這樣的限制。

針對於 JMX 遠端監控也是在這裡設定,以下為 64 位系統環境下的配置,記憶體加入的引數如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 CATALINA_OPTS=" -server  -Xms6000M  -Xmx6000M  -Xss512k  -XX:NewSize=2250M  -XX:MaxNewSize=2250M  -XX:PermSize=128M -XX:MaxPermSize=256M   -XX:+AggressiveOpts  -XX:+UseBiasedLocking  -XX:+DisableExplicitGC  -XX:+UseParNewGC  -XX:+UseConcMarkSweepGC  -XX:MaxTenuringThreshold=31  -XX:+CMSParallelRemarkEnabled  -XX:+UseCMSCompactAtFullCollection  -XX:LargePageSizeInBytes=128m  -XX:+UseFastAccessorMethods  -XX:+UseCMSInitiatingOccupancyOnly -Duser.timezone=Asia/Shanghai  -Djava.awt.headless=true"

為了看著方便,將每個引數單獨寫一行。上面引數好多啊,可能有人寫到現在都沒見過一個在 Tomcat 的啟動命令里加了這麼多引數,當然,這些引數只是我機器上的,不一定適合你,尤其是引數後的 value(值)是需要根據你自己的實際情況來設定的。

上述這樣的配置,基本上可以達到:

系統響應時間增快;

JVM回收速度增快同時又不影響系統的響應率;

JVM記憶體最大化利用;

執行緒阻塞情況最小化。

JVM 常用引數詳解:

-server:一定要作為第一個引數,在多個 CPU 時效能佳,還有一種叫 -client 的模式,特點是啟動速度比較快,但執行時效能和記憶體管理效率不高,通常用於客戶端應用程式或開發除錯,在 32 位環境下直接執行 Java 程式預設啟用該模式。Server 模式的特點是啟動速度比較慢,但執行時效能和記憶體管理效率很高,適用於生產環境,在具有 64 位能力的 JDK 環境下預設啟用該模式,可以不配置該引數。

-Xms:表示 Java 初始化堆的大小,-Xms 與-Xmx 設成一樣的值,避免 JVM 反覆重新申請記憶體,導致效能大起大落,預設值為實體記憶體的 1/64,預設(MinHeapFreeRatio引數可以調整)空餘堆記憶體小於 40% 時,JVM 就會增大堆直到 -Xmx 的最大限制。

-Xmx:表示最大 Java 堆大小,當應用程式需要的記憶體超出堆的最大值時虛擬機器就會提示記憶體溢位,並且導致應用服務崩潰,因此一般建議堆的最大值設定為可用記憶體的最大值的80%。如何知道我的 JVM 能夠使用最大值,使用 java -Xmx512M -version 命令來進行測試,然後逐漸的增大 512 的值,如果執行正常就表示指定的記憶體大小可用,否則會列印錯誤資訊,預設值為實體記憶體的 1/4,預設(MinHeapFreeRatio引數可以調整)空餘堆記憶體大於 70% 時,JVM 會減少堆直到-Xms 的最小限制。

-Xss:表示每個 Java 執行緒堆疊大小,JDK 5.0 以後每個執行緒堆疊大小為 1M,以前每個執行緒堆疊大小為 256K。根據應用的執行緒所需記憶體大小進行調整,在相同實體記憶體下,減小這個值能生成更多的執行緒,但是作業系統對一個程序內的執行緒數還是有限制的,不能無限生成,經驗值在 3000~5000 左右。一般小的應用, 如果棧不是很深, 應該是128k 夠用的,大的應用建議使用 256k 或 512K,一般不易設定超過 1M,要不然容易出現out ofmemory。這個選項對效能影響比較大,需要嚴格的測試。

-XX:NewSize:設定新生代記憶體大小。

-XX:MaxNewSize:設定最大新生代新生代記憶體大小

-XX:PermSize:設定持久代記憶體大小

-XX:MaxPermSize:設定最大值持久代記憶體大小,永久代不屬於堆記憶體,堆記憶體只包含新生代和老年代。

-XX:+AggressiveOpts:作用如其名(aggressive),啟用這個引數,則每當 JDK 版本升級時,你的 JVM 都會使用最新加入的優化技術(如果有的話)。

-XX:+UseBiasedLocking:啟用一個優化了的執行緒鎖,我們知道在我們的appserver,每個http請求就是一個執行緒,有的請求短有的請求長,就會有請求排隊的現象,甚至還會出現執行緒阻塞,這個優化了的執行緒鎖使得你的appserver內對執行緒處理自動進行最優調配。

-XX:+DisableExplicitGC:在 程式程式碼中不允許有顯示的呼叫“System.gc()”。每次在到操作結束時手動呼叫 System.gc() 一下,付出的代價就是系統響應時間嚴重降低,就和關於 Xms,Xmx 裡的解釋的原理一樣,這樣去呼叫 GC 導致系統的 JVM 大起大落。

-XX:+UseConcMarkSweepGC:設定年老代為併發收集,即 CMS gc,這一特性只有 jdk1.5
後續版本才具有的功能,它使用的是 gc 估算觸發和 heap 佔用觸發。我們知道頻頻繁的 GC 會造面 JVM
的大起大落從而影響到系統的效率,因此使用了 CMS GC 後可以在 GC 次數增多的情況下,每次 GC 的響應時間卻很短,比如說使用了 CMS
GC 後經過 jprofiler 的觀察,GC 被觸發次數非常多,而每次 GC 耗時僅為幾毫秒。

-XX:+UseParNewGC:對新生代採用多執行緒並行回收,這樣收得快,注意最新的 JVM 版本,當使用 -XX:+UseConcMarkSweepGC 時,-XX:UseParNewGC 會自動開啟。因此,如果年輕代的並行 GC 不想開啟,可以通過設定 -XX:-UseParNewGC 來關掉。

-XX:MaxTenuringThreshold:設定垃圾最大年齡。如果設定為0的話,則新生代物件不經過 Survivor 區,直接進入老年代。對於老年代比較多的應用(需要大量常駐記憶體的應用),可以提高效率。如果將此值設定為一 個較大值,則新生代物件會在 Survivor 區進行多次複製,這樣可以增加物件在新生代的存活時間,增加在新生代即被回收的概率,減少Full GC的頻率,這樣做可以在某種程度上提高服務穩定性。該引數只有在序列 GC 時才有效,這個值的設定是根據本地的 jprofiler 監控後得到的一個理想的值,不能一概而論原搬照抄。

-XX:+CMSParallelRemarkEnabled:在使用 UseParNewGC 的情況下,儘量減少 mark 的時間。

-XX:+UseCMSCompactAtFullCollection:在使用 concurrent gc 的情況下,防止 memoryfragmention,對 live object 進行整理,使 memory 碎片減少。

-XX:LargePageSizeInBytes:指定 Java heap 的分頁頁面大小,記憶體頁的大小不可設定過大, 會影響 Perm 的大小。

-XX:+UseFastAccessorMethods:使用 get,set 方法轉成原生代碼,原始型別的快速優化。

-XX:+UseCMSInitiatingOccupancyOnly:只有在 oldgeneration 在使用了初始化的比例後 concurrent collector 啟動收集。

-Duser.timezone=Asia/Shanghai:設定使用者所在時區。

-Djava.awt.headless=true:這個引數一般我們都是放在最後使用的,這全引數的作用是這樣的,有時我們會在我們的 J2EE 工程中使用一些圖表工具如:jfreechart,用於在 web 網頁輸出 GIF/JPG 等流,在 winodws 環境下,一般我們的 app server 在輸出圖形時不會碰到什麼問題,但是在linux/unix 環