你還不懂 Tomcat 的優化嗎?

經典雞翅發表於2020-05-25

前言

Tomcat 伺服器是一個開源的輕量級Web應用伺服器,在中小型系統和併發量小的場合下被普遍使用,是開發和除錯Servlet、JSP 程式的首選。相信大家對於 Tomcat 已經是非常熟悉了,本篇將介紹tomcat的常見優化。那麼為什麼要對tomcat進行優化呢。因為Tomcat預設引數是為開發環境制定,而非適合生產環境,尤其是記憶體和執行緒的配置,預設都很低,容易成為效能瓶頸。相信大家看完這篇部落格,會有一定的收穫。

Tomcat聯結器協議優化

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

nio如何配置

進入到tomcat的server.xml找到connector。更改其中的protocol屬性即可。

apr如何配置

apr的配置需要安裝依賴

yum -y install openssl-devel
yum -y install apr-devel

安裝之後,去tomcat官網下載native元件,native可以看成是tomcat和apr互動的中間環節,下載地址是:http://tomcat.apache.org/download-native.cgi 這裡下載最新的版本1.2.10
解壓並安裝

tar -xvzf tomcat-native-1.2.10-src.tar.gz
cd tomcat-native-1.2.10-src/native/
./configure

至此apr安裝成功,進入server.xml。更改協議將預設的protocol="HTTP/1.1"修改為protocol="org.apache.coyote.http11.Http11AprProtocol"。

Tomcat配置檔案方面的優化

配置檔案方面是我們主要的tomcat優化的地方。我們將常見的優化直接在配置檔案中放置。
1、connectionTimeout="30000":網路連線超時,單位:毫秒,設定為 0 表示永不超時,這樣設定有隱患的。通常可設定為 30000 毫秒,可根據檢測實際情況,適當修改
2、enableLookups="false":是否反查域名,以返回遠端主機的主機名,取值為:true 或 false,如果設定為false,則直接返回IP地址,為了提高處理能力,應設定為 false。
3、disableUploadTimeout="false":上傳時是否使用超時機制。
4、connectionUploadTimeout="150000":上傳超時時間,畢竟檔案上傳可能需要消耗更多的時間,這個根據你自己的業務需要自己調,以使Servlet有較長的時間來完成它的執行,需要與上一個引數一起配合使用才會生效。
5、acceptCount="300":指定當所有可以使用的處理請求的執行緒數都被使用時,可傳入連線請求的最大佇列長度,超過這個數的請求將不予處理,預設為100個。
6、keepAliveTimeout="120000":長連線最大保持時間(毫秒),表示在下次請求過來之前,Tomcat 保持該連線多久,預設是使用 connectionTimeout 時間,-1 為不限制超時。
7、maxKeepAliveRequests="1":表示在伺服器關閉之前,該連線最大支援的請求數。超過該請求數的連線也將被關閉,1表示禁用,-1表示不限制個數,預設100個,一般設定在100~200之間。
8、compression="on":是否對響應的資料進行 GZIP 壓縮,off:表示禁止壓縮;on:表示允許壓縮(文字將被壓縮)、force:表示所有情況下都進行壓縮,預設值為off,壓縮資料後可以有效的減少頁面的大小,一般可以減小1/3左右,節省頻寬。
9、compressionMinSize="2048":表示壓縮響應的最小值,只有當響應報文大小大於這個值的時候才會對報文進行壓縮,如果開啟了壓縮功能,預設值就是2048。
10、compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,image/gif,image/jpg,image/png":壓縮型別,指定對哪些型別的檔案進行資料壓縮。

<Connector executor="tomcatThreadPool"
 
port="8080" protocol="HTTP/1.1"
 
URIEncoding="UTF-8"
 
connectionTimeout="30000"
 //網路連線超時,單位:毫秒,設定為 0 表示永不超時,這樣設定有隱患的。通常可設定為 30000 毫秒,可根據檢測實際情況,適當修改

enableLookups="false"
//是否反查域名,以返回遠端主機的主機名,取值為:true 或 false,如果設定為false,則直接返回IP地址,為了提高處理能力,應設定為 false。
 
disableUploadTimeout="false"
//上傳時是否使用超時機制。

connectionUploadTimeout="150000"
//上傳超時時間,畢竟檔案上傳可能需要消耗更多的時間,這個根據你自己的業務需要自己調,以使Servlet有較長的時間來完成它的執行,需要與上一個引數一起配合使用才會生效。
 
acceptCount="300"
//指定當所有可以使用的處理請求的執行緒數都被使用時,可傳入連線請求的最大佇列長度,超過這個數的請求將不予處理,預設為100個。
 
keepAliveTimeout="120000"
//長連線最大保持時間(毫秒),表示在下次請求過來之前,Tomcat 保持該連線多久,預設是使用 connectionTimeout 時間,-1 為不限制超時。
 
maxKeepAliveRequests="1"
//表示在伺服器關閉之前,該連線最大支援的請求數。超過該請求數的連線也將被關閉,1表示禁用,-1表示不限制個數,預設100個,一般設定在100~200之間。
 
compression="on"
//是否對響應的資料進行 GZIP 壓縮,off:表示禁止壓縮;on:表示允許壓縮(文字將被壓縮)、force:表示所有情況下都進行壓縮,預設值為off,壓縮資料後可以有效的減少頁面的大小,一般可以減小1/3左右,節省頻寬。
 
compressionMinSize="2048"
//表示壓縮響應的最小值,只有當響應報文大小大於這個值的時候才會對報文進行壓縮,如果開啟了壓縮功能,預設值就是2048。
 
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,image/gif,image/jpg,image/png"
//壓縮型別,指定對哪些型別的檔案進行資料壓縮。
 
redirectPort="8443" />

Tomcat的jvm方面的優化

找到catalina.sh在檔案開頭增加如下設定:JAVA_OPTS=’-Xms256m-Xmx512m’

-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:+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:+UseCMSCompactAtFullCollection:在使用 concurrent gc 的情況下,防止 memoryfragmention,對 live object 進行整理,使 memory 碎片減少。

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

-Djava.awt.headless=true:這個引數一般我們都是放在最後使用的,這全引數的作用是這樣的,有時我們會在我們的 J2EE 工程中使用一些圖表工具如:jfreechart,用於在 web 網頁輸出 GIF/JPG 等流,在 winodws 環境下,一般我們的 app server 在輸出圖形時不會碰到什麼問題,但是在linux/unix 環境下經常會碰到一個 exception 導致你在 winodws 開發環境下圖片顯示的好好可是在 linux/unix 下卻顯示不出來,因此加上這個引數以免避這樣的情況出現。

-Xmn:新生代的記憶體空間大小,注意:此處的大小是(eden+ 2 survivor space)。與 jmap -heap 中顯示的 New gen 是不同的。整個堆大小 = 新生代大小 + 老生代大小 + 永久代大小。在保證堆大小不變的情況下,增大新生代後,將會減小老生代大小。此值對系統效能影響較大,Sun官方推薦配置為整個堆的 3/8。

-XX:NewRatio:年輕代(包括 Eden 和兩個 Survivor 區)與年老代的比值(除去持久代),-XX:NewRatio=4 表示年輕代與年老代所佔比值為 1:4,年輕代佔整個堆疊的 1/5,Xms=Xmx 並且設定了 Xmn 的情況下,該引數不需要進行設定。

-XX:SurvivorRatio:Eden 區與 Survivor 區的大小比值,設定為 8,表示 2 個 Survivor 區(JVM 堆記憶體年輕代中預設有 2 個大小相等的 Survivor 區)與 1 個 Eden 區的比值為 2:8,即 1 個 Survivor 區佔整個年輕代大小的 1/10。

-XX:+UseSerialGC:設定序列收集器。

-XX:+UseParallelGC:設定為並行收集器。此配置僅對年輕代有效。即年輕代使用並行收集,而年老代仍使用序列收集。

-XX:+UseParallelOldGC:配置年老代垃圾收集方式為並行收集,JDK6.0 開始支援對年老代並行收集。

-XX:OldSize:設定 JVM 啟動分配的老年代記憶體大小,類似於新生代記憶體的初始大小 -XX:NewSize。

Tomcat的字符集配置優化

Tomcat 的語言編碼,配置起來很慢,要經過多次設定才可以了,否則中文很有可能出現亂碼情況。譬如漢字“中”,以 UTF-8 編碼後得到的是 3 位元組的值 %E4%B8%AD,然後通過 GET 或者 POST 方式把這 3 個位元組提交到 Tomcat 容器,如果你不告訴 Tomcat 我的引數是用 UTF-8編碼的,那麼 Tomcat 就認為你是用 ISO-8859-1 來編碼的,而 ISO8859-1(相容 URI 中的標準字符集 US-ASCII)是相容 ASCII 的單位元組編碼並且使用了單位元組內的所有空間,因此 Tomcat 就以為你傳遞的用 ISO-8859-1 字符集編碼過的 3 個字元,然後它就用 ISO-8859-1 來解碼。

設定起來不難使用“ -D<名稱>=<值> ”來設定系統屬性:

-Djavax.servlet.request.encoding=UTF-8

-Djavax.servlet.response.encoding=UTF-8

-Dfile.encoding=UTF-8

-Duser.country=CN

-Duser.language=zh

總結

Tomcat優化到此結束,你現在懂了嗎?文中難免有不足,歡迎批評指正。

相關文章