溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Tomcat8史上最全優化實踐

發布時間:2020-07-09 11:14:33 來源:網絡 閱讀:1286 作者:Java_老男孩 欄目:編程語言

1、Tomcat8優化

tomcat服務器在JavaEE項目中使用率非常高,所以在生產環境對tomcat的優化也變得非常重要了。
對于tomcat的優化,主要是從兩個方面入手,第一是,tomcat自身的配置,另一個是tomcat所運行的jvm虛擬機的。

1.1、Tomcat配置優化

1.1.1、部署安裝tomcat8

下載并安裝 :https://tomcat.apache.org/download-80.cgi?
Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

1.1.2 禁用AJP連接

在服務狀態頁面中可以看到,默認狀態下會啟用AJP服務,并且占用8009端口。
Tomcat8史上最全優化實踐

什么是AJP呢?
AJP(Apache JServer Protocol)
AJPv13協議是面向包的。WEB服務器和Servlet容器通過TCP連接來交互;為了節省Socket創建的昂貴代價,WEB服務器會
嘗試維護一個永久TCP連接到servlet容器,并且在多個請求和響應周期過程會重用連接。
Tomcat8史上最全優化實踐

我們一般是使用Nginx+tomcat的架構,所以用不著AJP協議,所以把AJP連接器禁用。修改conf下的server.xml文件,將AJP
服務禁用掉即可。
Tomcat8史上最全優化實踐

1.1.3、執行器(線程池)
在tomcat中每一個用戶請求都是一個線程,所以可以使用線程池提高性能。
修改server.xml文件 :

Tomcat8史上最全優化實踐

保存退出,重啟tomcat,查看效果。
Tomcat8史上最全優化實踐

1.1.4 3種運行模式
tomcat的運行模式有3種 :
    1. bio
        默認的模式,性能非常低下,沒有經過任何優化處理和支持。
    2. 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)更好的并發運行
        性能。
    3. apr
        安裝起來最空難,但是從操作系統級別來解決異步的IO問題,大幅度的提高性能。
推薦使用nio,不過,在tomcat8中有最新的nio2,速度更快,建議使用nio2.

Tomcat8史上最全優化實踐

建議tomcat8以下使用nio,tomcat8及以上使用nio2.

1.3、使用Apache JMeter進行測試

Apache JMeter是開源的壓力測試工具,測量tomcat的吞吐量等信息。

1.3.1、下載安裝

下載地址 :http://jmeter.apache.org/download_jmeter.cgi
Tomcat8史上最全優化實踐

安裝 :直接將下載好的zip壓縮包進行解壓即可。
Tomcat8史上最全優化實踐

1.3.2、修改主題和語言

默認的主題是黑色風格的主題并且語言是英語,這樣不太方便使用,所以需要修改一下主題和中文語言。

1.3.3、創建首頁的測試用例

第一步 :保存測試用例
Tomcat8史上最全優化實踐

第二步 :添加線程組,使用線程模擬用戶的并發
Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

第四步 :添加請求監控
Tomcat8史上最全優化實踐

1.3.4、啟動、進行測試

Tomcat8史上最全優化實踐

1.3.5、聚合報告

在聚合報告中,重點看吞吐量
Tomcat8史上最全優化實踐

1.4、調整tomcat參數進行優化

通過上面測試可以看出,tomcat在不做任何調整時,吞吐量為73次/秒。

1.4.1、禁用AJP服務

Tomcat8史上最全優化實踐

可以看到,禁用AJP服務后,吞吐量會有所提升。

1.4.2、設置線程池

通過設置線程池,調整線程池相關的參數進行測試tomcat的性能。

1.4.2.1、最大線程數為500,初始為50

Tomcat8史上最全優化實踐

測試結果 :

Tomcat8史上最全優化實踐

吞吐量為128次/秒。

1.4.2.2、最大線程數為1000,初始為200

Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

吞吐量為151,有所提升。

1.4.2.3、最大線程數為5000,初始為1000

是否是線程數最多,速度越快呢?
Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

可以看到,雖然最大線程已經設置到5000,但是實際測試效果并不理想,并且平均的響應時間也變長, 所以單純靠提升線程數量是不能一直得到性能提升的。

1.4.2.4、設置最大等待隊列數

默認情況下,請求發送到tomcat,如果tomcat正忙,那么該請求會一直等待。這樣雖然可以保證每個請求都能請求到,但是請求時間就會變長。
有些時候,我們也不一定要求請求一定等待,可以設置最大等待隊列大小,如果超過就不等待了。這樣雖然有些請求是失敗的,但是請求時間會縮短。
Tomcat8史上最全優化實踐

測試結果 :
平均響應時間 :2.5秒;響應時間明顯縮短。
錯誤率 :54%;錯誤率提升到一半,也可以理解,最大線程為500,測試的并發為1000。
吞吐量 :281次/秒;吞吐量明顯提升。
結論 :響應時間、吞吐量這2個指標需要找到平衡才能達到更好的性能。

1.4.3、設置nio2的運行模式

將最大線程設置為500進行測試 :
Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

可以看到,平均響應時間有縮短,吞吐量有提升,可以得出結論 :nio2的性能要高于nio。

1.5、調整JVM參數進行優化

為了測試一致性,依然將最大線程數設置為500,啟用nio2運行模式。

1.5.1、設置并行垃圾回收器

年輕代、老年代均使用并行收集器,初始堆內存64M,最大堆內存512M
JAVA_OPTS="-XX:+UseParallelGC -XX:UseParalleloldGC -Xms64 -Xmx512m -XX:+PrintGCDetails -XX:PringtGCTomeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:…/logs/gc.log"
Tomcat8史上最全優化實踐

測試結果與默認的JVM參數結果接近。

1.5.2、查看GC日志

Tomcat8史上最全優化實踐

在報告中線上,在5次GC時,系統所消耗的時間大于用戶時間,這反應出的服務器的性能存在瓶頸,調度CPU等資源所消耗的時間要長一些。
Tomcat8史上最全優化實踐

可以從關鍵指標中看出,吞吐量表現不錯,但是GC時,線程的暫停時間稍有點長。
Tomcat8史上最全優化實踐

通過GC的統計可以看出 :
年輕代的gc有74次,次數稍有點多,說明年輕代設置的大小不合適需要調整;
FullGC有8次,說明堆內存的大小不合適,需要調整。
Tomcat8史上最全優化實踐

從GC原因可以看出,年輕代大小設置不合理,導致了多次GC。

1.5.3、調整年輕代大小

JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParalleloldGC -Xms128m -Xmx1024m -XX:NewSize=64m -XX:MaxNewSize=256m -XX:PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:…/logs/gc.log"
將初始堆大小設置為128m,最大為1024m
初始年輕代大小64m,年輕代最大256m
Tomcat8史上最全優化實踐

從測試結果來看,吞吐量以及響應時間均有提升。
查看gc日志 :
Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

可以看到GC次數要明顯減少,說明調整是有效的。

1.5.4、設置G1垃圾回收器

設置最大停頓時間100毫秒,初始堆內存128m,最大堆內存1024m
JAVA_OPTS="-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -Xms128m -Xmx1024m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:…/logs/gc.log"
測試結果 :
Tomcat8史上最全優化實踐

可以看到,吞吐量有所提升,響應時間也有所縮短。

1.5.5、小結

通過上述測試,可以總結出,對tomcat性能優化就是需要不斷的進行調整參數,然后測試結果,可能會調優也可能會調差,這時就需要借助于gc的可視化工具來看gc的情況。再幫助我們做出決策應用調整那些參數。

2、JVM字節碼

通過tomcat本身的參數以及jvm的參數對tomcat做了優化,其實要想將應用程序跑的更快、效率更高,除了對tomcat容器以及jvm優化外,應用程序代碼本身如果寫的效率不高,那么也是不行的,所以,對于程序本身的優化也就很重要的。
對于程序本身的優化,需要通過查看編譯好的class文件中字節碼。
java編寫應用,需要先通過javac命令編譯成class文件,再通過jvm執行,jvm執行時是需要將class文件中的字節碼載入到jvm進行運行的。

2.1、通過javap命令查看class文件的字節碼內容

首先,看一個簡單的test1類的代碼 :
Tomcat8史上最全優化實踐

通過javap命令查看class文件中的字節碼內容 :
Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

內容大致分為四個部分 :
第一部分 :顯示了生成這個class的java源文件、版本信息、生成時間等。
第二部分 :顯示了該類中所涉及到常量池,共35個常量。
第三部分 :顯示該類的構造器,編譯器自動插入的。
第四部分 :顯示了main方法的信息。(這個需要重點關注)

2.2、常量池

Tomcat8史上最全優化實踐

2.3、描述符

2.3.1、字段描述符

Tomcat8史上最全優化實踐

2.3.2、方法描述符

Tomcat8史上最全優化實踐

2.4、解讀方法字節碼

Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

2.4.1、圖解

Tomcat8史上最全優化實踐

2.5、研究i++與++i的不同

測試代碼 :
Tomcat8史上最全優化實踐

2.5.1、對比

Tomcat8史上最全優化實踐

2.5.2、圖解

Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

區別 :
1++
只是在本地變量中對數字做了相加,并沒有將數據壓入到操作棧。
將前面拿到的數字1,再次從操作棧中拿到,壓入到本地變量中。
++i
將本地變量中的數字做了相加,并且將數據壓入到操作棧。
將操作棧中的數據,再次壓入到本地變量中。
小結 :可以通過查看字節碼的方式對代碼的底層做研究,探究其原理。

2.6、字符串拼接

字符串的拼接在開發過程中使用是非常頻繁的,常用的方式有三種 :
+號拼接 :str + “456”
StringBuilder拼接
StringBuffer拼接
StringBuffer是保證線程安全的,效率是比較低的,但是我們更多情況下是線程安全的,所以更多時候選擇StringBuilder,效率會高一些。
那么,問題來了,StringBuilder和“+”號拼接,那個效率高呢?可以通話字節碼的方式進行探究。
示例 :
Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

從解字節碼中可以看出,m1()方法源碼中是使用+號拼接,但是在字節碼中也被編譯成了StringBuilder方式。所以,可以得出結論,字符串拼接,+號和StringBuilder是相等的,效率一樣。
Tomcat8史上最全優化實踐

Tomcat8史上最全優化實踐

可以看到,m1()方法中的循環體內,每次循環都會創建StringBuilder對象,效率低于m2()方法。

2.7、小結

使用字節碼的方式可以很好查看代碼底層的執行,從而可以看出哪些實現效率高,哪些實現效率低??梢愿玫膶ξ覀兊拇a做優化。讓程序執行效率更高。

3、代碼優化

不僅僅在運行環境進行優化,還需要在代碼本身做優化,如果代碼本身存在性能問題,那么在其他方面再怎么優化也不可能達到最優效果。

3.1、盡可能使用局部變量

調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧中速度較快,其他變量,如靜態變量、實例變量等,都在堆中創建,速度較慢。另外,棧中創建的變量,隨著方法的運行結束,這些內容就沒了,不需要額外的垃圾回收。

3.2、盡量減少對變量的重復計算

明確一個概念,對方法的調用,即使方法中只有一條語句,也是有消耗的。例如 :
Tomcat8史上最全優化實踐

這樣,在list.size()很大的時候,就減少了很多的消耗。

3.3、盡量采用懶加載的策略,即在需要的時候才創建

Tomcat8史上最全優化實踐

3.4、異常不應該用來控制程序流程

異常對性能不利。拋出異常首先要創建一個新的對象,Throwable接口的構造函數調用名為fillInStackTrace()的本地同步方法,
filllnStackTrace()方法檢查堆棧,收集調用跟蹤信息。只要有異常拋出,Java虛擬機就必須調整調用堆棧,因為在處理過程中創建了一個新的對象。異常只能用于錯誤處理,不應該用來控制程序流程。

3.5、不要將數組聲明為public static final

因為毫無意義,這樣只是定義了引用為static final,數組的內容還是可以隨意改變的,將數組聲明為public更是一個安全漏洞,這意味著這個數組可以被外部類所改變。

3.6、不要創建一些不使用的對象,不要導入一些不使用的類

這毫無意義,如果代碼中出現“The value of local variable i is not used”、“The import java.util is never used”,那么請刪除這些無用的內容。

3.7、程序原先過程中避免使用反射

反射是Java提供給用戶一個很強大的功能,功能強大往往意味著效率不高。不建議在程序運行過程中使用尤其是頻繁使用返回機制,特別是Method的invoke方法。
如果確實有必要,一種建議性的做法是將那些需要通過反射加載的類在項目啟動的時候通過反射實例化出一個對象并放入內存。

其他優化

1、使用數據庫連接池和線程池,這樣可以重用對象,避免頻繁地打開和關閉連接,后者可以避免頻繁地創建和消耗線程。
2、容器初始化時盡可能指定長度,如 :new ArrayList<>(10);new HashMap<>(32);避免容器長度不足時,擴容帶來性能損耗。
3、ArrayList隨機遍歷快,LinkedList添加刪除快。
4、避免使用這種方式 :

Map<String, String> map = new HashMap<>();
for (String key : map.keySet()) {
    String value = map.get(key);
}

盡量使用這種方式 :

for (Map.Entry<String, String> entry : map.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();
}

5、不要手動調用System.gc();
6、String盡量少用正則表達式 :
正則表達式雖然功能強大,但是其效率較低,除非是有需要,否則盡可能少用。
replace() : 不支持正則
replaceAll() : 支持正則
如果僅僅是字符的替換建議使用replace();
7、日志的輸出要注意級別;
8、對資源的close()建議分開操作。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女