Tomcat調(diào)優(yōu)詳解
前言
Tomcat作為一個Java Servlet容器,用于運行Web應(yīng)用程序,其性能和吞吐量對于確保應(yīng)用程序的快速響應(yīng)和高效運行至關(guān)重要。
因此,Tomcat調(diào)優(yōu)是為了最大限度地提高系統(tǒng)的性能和可擴(kuò)展性,以滿足高并發(fā)和大流量的需求。
由于Tomcat的運行依賴于JVM,從虛擬機(jī)的角度把Tomcat的調(diào)整分為外部環(huán)境調(diào)優(yōu)JVM和Tomcat自身調(diào)優(yōu)兩部分,當(dāng)然操作系統(tǒng)(內(nèi)核參數(shù))也需要配合調(diào)整優(yōu)化。
Tomcat 在目前的網(wǎng)絡(luò)編程中是舉足輕重的,由于Tomcat的運行依賴于JVM,從虛擬機(jī)的角度把Tomcat的調(diào)整分為外部環(huán)境調(diào)優(yōu) JVM 和 Tomcat 自身調(diào)優(yōu)兩部分:
一、JVM
1.JVM 組成
1.1 JVM 組成部分:
- 類加載子系統(tǒng): 使用Java語言編寫.java Source Code文件,通過 javac 編譯成.class Byte Code文件。class loader 類加載器將所需所有類加載到內(nèi)存,必要時將類實例化成實例
- 運行時數(shù)據(jù)區(qū): 最消耗內(nèi)存的空間,需要優(yōu)化
- 執(zhí)行引擎: 包括JIT (JustInTimeCompiler)即時編譯器, GC垃圾回收器
- 本地方法接口: 將本地方法棧通過JNI(Java Native Interface)調(diào)用Native Method Libraries, 比如:C,C++庫等,擴(kuò)展Java功能,融合不同的編程語言為Java所用
1.2jvm運行時,數(shù)據(jù)區(qū)的構(gòu)成:
- Method Area (線程共享):方法區(qū)是所有線程共享的內(nèi)存空間,存放已加載的類信息(構(gòu)造方法,接口定義),常量(final),靜態(tài)變量(static), 運行時常量池等。但實例變量存放在堆內(nèi)存中. 從JDK8開始此空間由永久代改名為元空間
- heap (線程共享):堆在虛擬機(jī)啟動時創(chuàng)建,存放創(chuàng)建的所有對象信息。如果對象無法申請到可用內(nèi)存將拋出OOM異常.堆是靠GC垃圾回收器管理的,通過-Xmx -Xms 指定最大堆和最小堆空間大小
- Java stack (線程私有):Java棧是每個線程會分配一個棧,存放java中8大基本數(shù)據(jù)類型,對象引用,實例的本地變量,方法參數(shù)和返回值等,基于FILO()(First In Last Out),每個方法為一個棧幀 1 50 %
- Program Counter Register (線程私有):PC寄存器就是一個指針,指向方法區(qū)中的方法字節(jié)碼,每一個線程用于記錄當(dāng)前線程正在執(zhí)行的字節(jié)碼指令地址。由執(zhí)行引擎讀取下一條指令.因為線程需要切換,當(dāng)一個線程被切換回來需要執(zhí)行的時候,知道執(zhí)行到哪里了
- Native Method stack (線程私有):本地方法棧為本地方法執(zhí)行構(gòu)建的內(nèi)存空間,存放本地方法執(zhí)行時的局部變量、操作數(shù)等。
1.3垃圾確定方法:
- 引用計數(shù): 每一個堆內(nèi)對象上都與一個私有引用計數(shù)器,記錄著被引用的次數(shù),引用計數(shù)清零,該對象所占用堆內(nèi)存就可以被回收。循環(huán)引用的對象都無法將引用計數(shù)歸零,就無法清除。Python中即使用此種方式。 簡單來說就是有個筆記本,記錄有沒有人在用,缺陷,AB 資源互相調(diào)用
- 根搜索(可達(dá))算法 Root Searching
2.垃圾回收基本算法
2.1 標(biāo)記-清除 Mark-Sweep:
分垃圾標(biāo)記階段和內(nèi)存釋放階段。
標(biāo)記階段,找到所有可訪問對象打個標(biāo)記。
清理階段,遍歷整個堆,對未標(biāo)記對象(即不再使用的對象)逐一進(jìn)行清理。
2.2 標(biāo)記壓縮(壓實)Mark-Compact:
分垃圾標(biāo)記階段和內(nèi)存整理階段。
標(biāo)記階段,找到所有可訪問對象打個標(biāo)記。
內(nèi)存清理階段時,整理時將對象向內(nèi)存一端移動,整理后存活對象連續(xù)的集中在內(nèi)存一端。
標(biāo)記-壓縮算法好處是整理后內(nèi)存空間連續(xù)分配,有大段的連續(xù)內(nèi)存可分配,沒有內(nèi)存碎片。
缺點是內(nèi)存整理過程有消耗,效率相對低下。
2.3 復(fù)制 Copying:
先將可用內(nèi)存分為大小相同兩塊區(qū)域A和B,每次只用其中一塊,比如A。
當(dāng)A用完后,則將A中存活的對象復(fù)制到B。
復(fù)制到B的時候連續(xù)的使用內(nèi)存,最后將A一次性清除干凈。
缺點是比較浪費內(nèi)存,只能使用原來一半內(nèi)存,因為內(nèi)存對半劃分了,復(fù)制過程畢竟也是有代價。
好處是沒有碎片,復(fù)制過程中保證對象使用連續(xù)空間,且一次性清除所有垃圾,所以效率很高。
過程:
2.4 多種算法總結(jié):
沒有最好的算法,在不同場景選擇最合適的算法
- 效率: 復(fù)制算法>標(biāo)記清除算法> 標(biāo)記壓縮算法
- 內(nèi)存整齊度: 復(fù)制算法=標(biāo)記壓縮算法> 標(biāo)記清除算法
- 內(nèi)存利用率: 標(biāo)記壓縮算法=標(biāo)記清除算法>復(fù)制算法
2.5 STW (Stop The World):
對于大多數(shù)垃圾回收算法而言,GC 線程工作時,停止所有工作的線程,稱為Stop The World。GC 完成時,恢復(fù)其他工作線程運行。這也是JVM運行中最頭疼的問題。
① 什么時候進(jìn)入STW狀態(tài)?
可達(dá)性分析算法中枚舉根節(jié)點(GC Roots)會導(dǎo)致所有Java執(zhí)行線程停頓,進(jìn)入STW狀態(tài)
② 為什么一定要STW停頓的原因?
分析工作必須在一個能確保一致性的快照中進(jìn)行,一致性指整個分析期間整個執(zhí)行系統(tǒng)看起來像被凍結(jié)在某個時間點上,如果出現(xiàn)分析過程中對象引用關(guān)系還在不斷變化,則分析結(jié)果的準(zhǔn)確性無法保證。被STW中斷的應(yīng)用程序線程會在完成GC之后恢復(fù),頻繁的中斷會讓用戶感覺卡頓。所以我們要減少STW的發(fā)生,也就相當(dāng)于要想辦法降低GC垃圾回收的頻率,STW狀態(tài)和采用哪款GC收集器無關(guān),所有的GC收集器都有這個狀態(tài),因為要保證一致性。 但是好的GC收集器可以減少停頓的時間。
3. 分代堆內(nèi)存GC策略:
3.1 堆內(nèi)存分代
上述垃圾回收算法都有優(yōu)缺點,能不能對不同數(shù)據(jù)進(jìn)行區(qū)分管理,不同分區(qū)對數(shù)據(jù)實施不同回收策略,分而治之。
將heap內(nèi)存空間分為三個不同類別: 年輕代、老年代、持久代
解釋:
Heap 堆內(nèi)存分為:
年輕代Young:Young Generation
- 伊甸園區(qū)eden: 只有一個,剛剛創(chuàng)建的對象
- 幸存(存活)區(qū)Servivor Space:有2個幸存區(qū),一個是from區(qū),一個是to區(qū)。大小相等、地位相 同、可互換。
老年代Tenured:Old Generation, 長時間存活的對象
默認(rèn)空間大小比例:
規(guī)律: 一般情況*99%的對象都是臨時對象
3.2 年輕代回收Minor GC:
- 起始時,所有新建對象(特大對象直接進(jìn)入老年代)都出生在eden,當(dāng)eden滿了,啟動**GC。這個稱為Young GC 或者 Minor GC。
- 先標(biāo)記eden存活對象,然后將存活對象復(fù)制到s0(假設(shè)本次是s0,也可以是s1,它們可以調(diào)換),eden剩余所有空間都清空。GC完成。
- 繼續(xù)新建對象,當(dāng)eden再次滿了,啟動GC。
- 先同時標(biāo)記eden和s0中存活對象,然后將存活對象復(fù)制到s1。將eden和s0清空,此次GC完成
- 繼續(xù)新建對象,當(dāng)eden滿了,啟動GC。
- 先標(biāo)記eden和s1中存活對象,然后將存活對象復(fù)制到s0。將eden和s1清空,此次GC完成以后就重復(fù)上面的步驟。
通常場景下,大多數(shù)對象都不會存活很久,而且創(chuàng)建活動非常多,新生代就需要頻繁垃圾回收。但是,如果一個對象一直存活,它最后就在from、to來回復(fù)制,如果from區(qū)中對象復(fù)制次數(shù)達(dá)到閾值(默認(rèn)15次,CMS為6次,可通過java的選項 -XX:MaxTenuringThreshold=N 指定),就直接復(fù)制到老年代。
3.3 老年代回收 Major GC::
進(jìn)入老年代的數(shù)據(jù)較少,所以老年代區(qū)被占滿的速度較慢,所以垃圾回收也不頻繁。如果老年代也滿了,會觸發(fā)老年代GC,稱為Old GC或者 Major GC。
由于老年代對象一般來說存活次數(shù)較長,所以較常采用標(biāo)記-壓縮算法。
當(dāng)老年代滿時,會觸發(fā) Full GC,即對所有"代"的內(nèi)存進(jìn)行垃圾回收
Minor GC比較頻繁,Major GC較少。但一般Major GC時,由于老年代對象也可以引用新生代對象,所以先進(jìn)行一次Minor GC,然后在Major GC會提高效率。可以認(rèn)為回收老年代的時候完成了一次Full GC。所以可以認(rèn)為 MajorGC = FullGC。
4. java 內(nèi)存調(diào)整相關(guān)參數(shù)
4.1 JVM 內(nèi)存常用相關(guān)參數(shù)
選項分類:
- -選項名稱 此為標(biāo)準(zhǔn)選項,所有HotSpot都支持
- -X選項名稱 為穩(wěn)定的非標(biāo)準(zhǔn)選項
- -XX:選項名稱 非標(biāo)準(zhǔn)的不穩(wěn)定選項,下一個版本可能會取消
參數(shù) | 說明 | 舉例 |
---|---|---|
-Xms | 設(shè)置應(yīng)用程序初始使用的堆內(nèi)存大?。贻p代+老年代) | -Xms2g |
-Xmx | 設(shè)置應(yīng)用程序能獲得的最大堆內(nèi)存早期JVM不建議超過32G,內(nèi)存管理效率下降 | -Xms4g |
-XX:NewSize | 設(shè)置初始新生代大小 | -XX:NewSize=128m |
-XX:MaxNewSize | 設(shè)置最大新生代內(nèi)存空間 | -XX:MaxNewSize=256m |
-Xmnsize | 同時設(shè)置-XX:NewSize 和 -XX:MaxNewSize,代 | -Xmn1g |
-XX:NewRatio | 以比例方式設(shè)置新生代和老年代 | -XX:NewRatio=2new/old=1/2 |
-XX:SurvivorRatio | 以比例方式設(shè)置eden和survivor(S0或S1) | -XX:SurvivorRatio=6eden/survivor=6/1new/survivor=8/1 |
-Xss | 設(shè)置每個線程私有的??臻g大小,依據(jù)具體線程 | -Xss256k |
-Xms 和 -Xmx 建議兩個值調(diào)一樣大小
標(biāo)準(zhǔn)選項:
[root@localhost ~]#java 用法: java [-options] class [args...] (執(zhí)行類) 或 java [-options] -jar jarfile [args...] (執(zhí)行 jar 文件) 其中選項包括: -d32 使用 32 位數(shù)據(jù)模型 (如果可用) -d64 使用 64 位數(shù)據(jù)模型 (如果可用) -server 選擇 "server" VM 默認(rèn) VM 是 server, 因為您是在服務(wù)器類計算機(jī)上運行。 -cp <目錄和 zip/jar 文件的類搜索路徑> -classpath <目錄和 zip/jar 文件的類搜索路徑> 用 : 分隔的目錄, JAR 檔案 和 ZIP 檔案列表, 用于搜索類文件。 -D<名稱>=<值> 設(shè)置系統(tǒng)屬性 -verbose:[class|gc|jni] 啟用詳細(xì)輸出 -version 輸出產(chǎn)品版本并退出 -version:<值> 警告: 此功能已過時, 將在 未來發(fā)行版中刪除。 需要指定的版本才能運行 -showversion 輸出產(chǎn)品版本并繼續(xù) -jre-restrict-search | -no-jre-restrict-search 警告: 此功能已過時, 將在 未來發(fā)行版中刪除。 在版本搜索中包括/排除用戶專用 JRE -? -help 輸出此幫助消息 -X 輸出非標(biāo)準(zhǔn)選項的幫助 -ea[:<packagename>...|:<classname>] -enableassertions[:<packagename>...|:<classname>] 按指定的粒度啟用斷言 -da[:<packagename>...|:<classname>] -disableassertions[:<packagename>...|:<classname>] 禁用具有指定粒度的斷言 -esa | -enablesystemassertions 啟用系統(tǒng)斷言 -dsa | -disablesystemassertions 禁用系統(tǒng)斷言 -agentlib:<libname>[=<選項>] 加載本機(jī)代理庫 <libname>, 例如 -agentlib:hprof 另請參閱 -agentlib:jdwp=help 和 -agentlib:hprof=help -agentpath:<pathname>[=<選項>] 按完整路徑名加載本機(jī)代理庫 -javaagent:<jarpath>[=<選項>] 加載 Java 編程語言代理, 請參閱 java.lang.instrument -splash:<imagepath> 使用指定的圖像顯示啟動屏幕
非標(biāo)準(zhǔn)的穩(wěn)定選項:
[root@localhost ~]#java -X -Xmixed 混合模式執(zhí)行 (默認(rèn)) -Xint 僅解釋模式執(zhí)行 -Xbootclasspath:<用 : 分隔的目錄和 zip/jar 文件> 設(shè)置搜索路徑以引導(dǎo)類和資源 -Xbootclasspath/a:<用 : 分隔的目錄和 zip/jar 文件> 附加在引導(dǎo)類路徑末尾 -Xbootclasspath/p:<用 : 分隔的目錄和 zip/jar 文件> 置于引導(dǎo)類路徑之前 -Xdiag 顯示附加診斷消息 -Xnoclassgc 禁用類垃圾收集 -Xincgc 啟用增量垃圾收集 -Xloggc:<file> 將 GC 狀態(tài)記錄在文件中 (帶時間戳) -Xbatch 禁用后臺編譯 -Xms<size> 設(shè)置初始 Java 堆大小 -Xmx<size> 設(shè)置最大 Java 堆大小 -Xss<size> 設(shè)置 Java 線程堆棧大小 -Xprof 輸出 cpu 配置文件數(shù)據(jù) -Xfuture 啟用最嚴(yán)格的檢查, 預(yù)期將來的默認(rèn)值 -Xrs 減少 Java/VM 對操作系統(tǒng)信號的使用 (請參閱文檔) -Xcheck:jni 對 JNI 函數(shù)執(zhí)行其他檢查 -Xshare:off 不嘗試使用共享類數(shù)據(jù) -Xshare:auto 在可能的情況下使用共享類數(shù)據(jù) (默認(rèn)) -Xshare:on 要求使用共享類數(shù)據(jù), 否則將失敗。 -XshowSettings 顯示所有設(shè)置并繼續(xù) -XshowSettings:all 顯示所有設(shè)置并繼續(xù) -XshowSettings:vm 顯示所有與 vm 相關(guān)的設(shè)置并繼續(xù) -XshowSettings:properties 顯示所有屬性設(shè)置并繼續(xù) -XshowSettings:locale 顯示所有與區(qū)域設(shè)置相關(guān)的設(shè)置并繼續(xù) -X 選項是非標(biāo)準(zhǔn)選項, 如有更改, 恕不另行通知。
有不穩(wěn)定選項的當(dāng)前生效值:
[root@centos7 ~]#java -XX:+PrintFlagsFinal
查看所有不穩(wěn)定選項的默認(rèn)值:
[root@centos7 ~]#java -XX:+PrintFlagsInitial
示例:
指定內(nèi)存空間:
#指定內(nèi)存空間 [root@centos7 ~]#java -Xms1024m -Xmx1024m -XX:+PrintGCDetails -cp . Heap #Heap 是一個腳本文件
二、Tomcat 配置文件參數(shù)優(yōu)化
1. 常用的優(yōu)化相關(guān)參數(shù)
- 【redirectPort】如果某連接器支持的協(xié)議是HTTP,當(dāng)接收客戶端發(fā)來的HTTPS 443 請求時,則轉(zhuǎn)發(fā)至此屬性定義的 8443 端口。
- 【maxThreads】Tomcat使用線程來處理接收的每個請求,這個值表示Tomcat可創(chuàng)建的最大的線程數(shù),即支持的最大并發(fā)連接數(shù),默認(rèn)值是 200。
- 【minSpareThreads】最小空閑線程數(shù),Tomcat 啟動時的初始化的線程數(shù),表示即使沒有人使用也開這么多空線程等待,默認(rèn)值是 10。
- 【maxSpareThreads】最大備用線程數(shù),一旦創(chuàng)建的線程超過這個值,Tomcat就會關(guān)閉不再需要的socket線程。默認(rèn)值是-1(無限制)。一般不需要指定。
- 【processorCache】進(jìn)程緩沖器,可以提升并發(fā)請求。默認(rèn)值是200,如果不做限制的話可以設(shè)置為-1,一般采用maxThreads的值或者-1。
- 【URIEncoding】指定 Tomcat 容器的 URL 編碼格式,網(wǎng)站一般采用UTF-8作為默認(rèn)編碼。
- 【connnectionTimeout】網(wǎng)絡(luò)連接超時,單位:毫秒,設(shè)置為 0 表示永不超時,這樣設(shè)置有隱患的。通常默認(rèn) 20000 毫秒就可以。
- 【enableLookups】是否反查域名,以返回遠(yuǎn)程主機(jī)的主機(jī)名,取值為:true 或 false,如果設(shè)置為 false,則直接返回 IP 地址,為了提高處理能力,應(yīng)設(shè)置為 false。
- 【disableUploadTimeout】上傳時是否使用超時機(jī)制。應(yīng)設(shè)置為 true。
- 【connectionUploadTimeout】上傳超時時間,畢竟文件上傳可能需要消耗更多的時間,這個根據(jù)你自己的業(yè)務(wù)需要自己調(diào),以使Servlet有較長的時間來完成它的執(zhí)行,需要與上一個參數(shù)一起配合使用才會生效。
- 【acceptCount】指定當(dāng)所有可以使用的處理請求的線程數(shù)都被使用時,可傳入連接請求的最大隊列長度,超過這個數(shù)的請求將不予處理,默認(rèn)為 100 個。
- 【maxKeepAliveRequests】指定一個長連接的最大請求數(shù)。默認(rèn)長連接是打開的,設(shè)置為1時,代表關(guān)閉長連接;為-1時,代表請求數(shù)無限制
- 【compression】是否對響應(yīng)的數(shù)據(jù)進(jìn)行GZIP壓縮,off:表示禁止壓縮;on:表示允許壓縮(文本將被壓縮)、force:表示所有情況下都進(jìn)行壓縮,默認(rèn)值為 off,壓縮數(shù)據(jù)后可以有效的減少頁面的大小,一般可以減小 1/3 左右,節(jié)省帶寬。
- 【compressionMinSize】表示壓縮響應(yīng)的最小值,只有當(dāng)響應(yīng)報文大小大于這個值的時候才會對報文進(jìn)行壓縮,如果開啟了壓縮功能,默認(rèn)值就是 2048。
- 【compressableMimeType】壓縮類型,指定對哪些類型的文件進(jìn)行數(shù)據(jù)壓縮。
- 【noCompressionUserAgents="gozilla, traviata"】對于以下的瀏覽器,不啟用壓縮 #如果已經(jīng)進(jìn)行了動靜分離處理,靜態(tài)頁面和圖片等數(shù)據(jù)就不需做 Tomcat 處理,也就不要在 Tomcat 中配置壓縮了。
2. 編輯全局配置
vim /usr/local/tomcat/conf/server.xml ...... <Connector port="8080" protocol="HTTP/11.1" connectionTimeout="20000" redirectPort="8443" --71行--插入 minSpareThreads="50" enableLookups="false" disableUploadTimeout="true" acceptCount="300" maxThreads="500" processorCache="500" URIEncoding="UTF-8" maxKeepAliveRequests="100" compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,image/gif,image /jpg,image/png"/>
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot初始教程之Servlet、Filter、Listener配置詳解
本篇文章主要介紹了SpringBoot初始教程之Servlet、Filter、Listener配置詳解,具有一定的參考價值,有興趣的可以了解一下2017-09-09Spring Boot 中的自動配置autoconfigure詳解
這篇文章主要介紹了Spring Boot 中的自動配置autoconfigure詳解,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01Spring?Boot?3.3?實現(xiàn)職責(zé)鏈模式輕松應(yīng)對電商訂單流程分析
在電商系統(tǒng)中,訂單處理流程包括庫存校驗、優(yōu)惠券驗證、運費計算等多個步驟,這些步驟具有順序依賴性,為了管理這些業(yè)務(wù)邏輯,職責(zé)鏈模式提供了解決方案,通過鏈?zhǔn)疥P(guān)系將處理邏輯模塊化,實現(xiàn)解耦和靈活擴(kuò)展,本文將探討如何結(jié)合SpringBoot實現(xiàn)職責(zé)鏈模式,優(yōu)化電商訂單處理流程2024-10-10關(guān)于idea引入spring boot <parent></parent>父依賴標(biāo)紅問題
這篇文章主要介紹了idea引入spring boot <parent></parent>父依賴標(biāo)紅問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10