天天看點

tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

tomcat8優化實踐以及優化建議

tomcat8的部署安裝

下載下傳資源:

tomcat下載下傳 :

https://tomcat.apache.org/download-80.cgi

修改配置檔案,配置tomcat的管理使用者

cd apache-tomcat-8.5.34/conf
vim tomcat-users.xml           

寫入如下内容:

<role rolename="manager"/">"
<role rolename="manager-gui"/">"
<role rolename="admin"/">"
<role rolename="admin-gui"/">"
<user username="tomcat" password="tomcat" roles="admin-gui,admin,manager-gui,manager"/">"           

如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403

vim webapps/manager/META-INF/context.xml           

将valve的内容注釋掉

<Context antiResourceLocking="false" privileged="true" ">"
<!-- <Valve className="org.apache.catalina.valves.RemoteAddrValve"
    allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /">" --">"
點選“Server Status”,輸入使用者名、密碼進行登入,tomcat/tomcat
<Manager sessionAttributeValueClassNameFilter="java\.lang\.
(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFi
lter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/">"
</Context">"           

儲存退出即可

啟動tomcat

cd /tmp/apache-tomcat-8.5.34/bin/
./startup.sh && tail -f ../logs/catalina.out           

輸入位址進行通路:

http://ip

:8080/

點選“Server Status”,輸入使用者名、密碼進行登入,tomcat/tomcat

禁用AJP連接配接

AJP服務:

tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

什麼是AJP呢?

AJP(Apache JServer Protocol) AJPv13協定是面向包的。WEB伺服器和Servlet容器通過TCP連接配接來互動;為了節省SOCKET建立的昂貴代價,WEB伺服器會嘗試維護一個永久TCP連接配接到servlet容器,并且在多個請求和響應周期過程會重用連接配接。

tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

我們一般是使用Nginx+tomcat的架構,是以用不着AJP協定,是以把AJP連接配接器禁用。

修改conf下的server.xml檔案,将AJP服務禁用掉即可。

<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /">" --">"           

重新開機tomcat看到AJP服務就沒有了

tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

設定線程池

  • 設定conf/server.xml,找到以下内容将注釋打開
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
    maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true"
maxQueueSize="100"/">"           
  • 參數說明:

maxThreads:最大并發數,預設設定 200,一般建議在 500 ~ 1000,根據硬體設施和業務來判斷

minSpareThreads:Tomcat 初始化時建立的線程數,預設設定 25

prestartminSpareThreads: 在 Tomcat 初始化的時候就初始化 minSpareThreads 的參數值,如果不等于

true,minSpareThreads 的值就沒啥效果了

maxQueueSize,最大的等待隊列數,超過則拒絕請求

  • 在Connector中設定executor屬性指向上面的執行器
<Connector executor="tomcatThreadPool"  port="8080" protocol="HTTP/1.1"
       connectionTimeout="20000"
       redirectPort="8443" /">"           

重新開機tomcat檢視效果

tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat
  • 在頁面中顯示最大線程數為-1,這個是正常的,僅僅是顯示的問題,實際使用的指定的值。

也有人遇到這樣的問題:

https://blog.csdn.net/weixin_38278878/article/details/80144397

設定NIO2運作模式

  • 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.

設定nio2:

<Connector executor="tomcatThreadPool"  port="8080"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
       connectionTimeout="20000"
       redirectPort="8443" /">"           

重新開機tomcat檢視效果:

tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

調整tomcat參數進行優化

禁用AJP服務

在 conf/server.xml中找到以下内容,并将其注釋掉

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /">"           

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
    maxThreads="1000" minSpareThreads="200" prestartminSpareThreads="true"/">"           

注:線城池不是越大越好,不同的機器又不同的臨界值,設定太大會影響性能

設定最大等待數

線上程池中設定最大等待數

<!--最大等待數為100--">"
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
    maxThreads="500" minSpareThreads="100" prestartminSpareThreads="true"
maxQueueSize="100"/">"           

注:設定最大等待數為100,如果超過最大的等待數,服務會拒絕連接配接,是以響應速度和吞吐量會有所提升。但是相應的錯誤率也會提升

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
    maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true"/">"
<!-- 設定nio2 --">"
<Connector executor="tomcatThreadPool" port="8080"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
       connectionTimeout="20000"
       redirectPort="8443" /">"           

注:tomcat7中支援NIO,tomcat8以上支援NIO2

調整JVM參數進行優化

設定并行的垃圾回收器

編輯 /bin/catalina.sh檔案,在注釋結束的第一行加入以下代碼

#年輕代、老年代均使用并行收集器,初始堆記憶體64M,最大堆記憶體512M,在logs檔案夾中輸出log日志
JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xms64m -Xmx512m -
XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -
Xloggc:../logs/gc.log"           

注:我的gc輸出一直找不到檔案,此時Xloggc:後需要配置絕對路徑

檢視gc日志檔案

  • 将gc.log檔案上傳到 https://gceasy.io 網站上進行分析
  • 檢視響應的名額
  • 問題一:
tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

在報告中顯示,在5次GC時,系統所消耗的時間大于使用者時間,這反應出的伺服器的性能存在瓶頸,排程CPU等資源所消耗的時間要長一些。

  • 問題二:
tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

可以關鍵名額中可以看出,吞吐量表現不錯,但是gc時,線程的暫停時間稍有點長。

問題三:

tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

1、年輕代的gc有74次,次數稍有多,說明年輕代設定的大小不合适需要調整

2、FullGC有8次,說明堆記憶體的大小不合适,需要調整

問題四:

tomcat8優化實踐以及優化建議tomcat8優化實踐以及優化建議修改配置檔案,配置tomcat的管理使用者寫入如下内容:如果是tomcat7,配置了tomcat使用者就可以登入系統了,但是tomcat8中不行,還需要修改另一個配置檔案,否則通路不了,提示403将valve的内容注釋掉儲存退出即可啟動tomcat

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

調整年輕代的大小

将初始堆大小設定為128m,最大為1024m

初始年輕代大小64m,年輕代最大256m

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"           

設定G1垃圾收集器

-XX:+UseG1GC

注意在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"           

代碼優化建議

  • 盡量使用局部變量

調用方法時傳遞的參數以及在調用中建立的臨時變量都儲存在棧中速度較快,其他變量,如靜态變量、執行個體變量等,都在堆中建立,速度較慢。另外,棧中建立的變量,随着方法的運作結束,這些内容就沒了,不需要額外的垃圾回收。

  • 盡量減少對變量的重複計算
for (int i = 0; i < list.size(); i++)
{...}           

替換為:

int length = list.size();
for (int i = 0,  i < length; i++)
{...}           
  • 盡量采用懶加載的政策,即在需要的時候才建立
String str = "aaa";
if (i == 1){
list.add(str);
}           
if (i == 1){
String str = "aaa";
list.add(str);
}           
  • 異常不應該用來控制程式流程

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

  • 不要将數組聲明為public static final

因為這毫無意義,這樣隻是定義了引用為static final,數組的内容還是可以随意改變的,将數組聲明為public更是

一個安全漏洞,這意味着這個數組可以被外部類所改變。

  • 不要建立一些不使用的對象,不要導入一些不使用的類

這毫無意義,如果代碼中出現"The value of the local variable i is not used"、"The import java.util is never

used",那麼請删除這些無用的内容

  • 程式運作過程中避免使用反射

反射是Java提供給使用者一個很強大的功能,功能強大往往意味着效率不高。不建議在程式運作過程中使用尤其是頻繁使用反射機制,特别是 Method的invoke方法。

如果确實有必要,一種建議性的做法是将那些需要通過反射加載的類在項目啟動的時候通過反射執行個體化出一個對象并放入記憶體。

  • 使用資料庫連接配接池和線程池

這兩個池都是用于重用對象的,前者可以避免頻繁地打開和關閉連接配接,後者可以避免頻繁地建立和銷毀線程。

  • 容器初始化時盡可能指定長度

容器初始化時盡可能指定長度,如:new ArrayList<">"(10); new HashMap<">"(32); 避免容器長度不足時,擴容帶來的性能損耗。

  • ArrayList随機周遊快,LinkedList添加删除快
  • 使用Entry周遊Map
Map<String,String">" map = new HashMap<">"();
for (String key : map.keySet()) {
  String value = map.get(key);
}           
Map<String,String">" map = new HashMap<">"();
for (Map.Entry<String,String">" entry : map.entrySet()) {
  String key = entry.getKey();
  String value = entry.getValue();
}           
  • 不要手動調用System.gc();
  • String盡量少用正規表達式

正規表達式雖然功能強大,但是其效率較低,除非是有需要,否則盡可能少用。

replace() 不支援正則 replaceAll() 支援正則

如果僅僅是字元的替換建議使用replace()。

  • 日志的輸出要注意級别
// 目前的日志級别是error
LOGGER.info("儲存出錯!" + user);           
  • 對資源的close()建議分開操作
try{
  XXX.close();
  YYY.close();
}
catch (Exception e){
 ...
}           
try{
  XXX.close();
}
catch (Exception e){
 ...
}
try{
  YYY.close();
}
catch (Exception e){
 ...
}           

"

">"