Tomcat性能監控與調優
Tomcat是目前被應用得最多的一款Java Web服務器,很多人都會使用Tomcat來作為項目的服務器。也經常需要在開發的時候對Tomcat進行debug。在本地對Tomcat進行debug相信很多人都會,但如果需要對遠程的Tomcat進行debug,相信有部分小夥伴還是沒接觸過的,而本小節將簡單介紹一下如何對Tomcat進行遠程debug。
Tomcat遠程debug是基於 JDWP 協議實現的,關於 JDWP 協議,可參考以下文檔:
https://www.ibm.com/developerworks/cn/java/j-lo-jpda3/
想要進行遠程Debug,首先得配置一下遠程的Tomcat,讓其開啟遠程Debug模式。如下:
[root@server ~]# vim /home/tomcat/apache-tomcat-8.5.8/bin/startup.sh # 在最後一行增加jdpa參數 exec "$PRGDIR"/"$EXECUTABLE" jpda start "$@" [root@server ~]# vim /home/tomcat/apache-tomcat-8.5.8/bin/catalina.sh # 將原本的localhost:8000改為9000 if [ -z "$JPDA_ADDRESS" ]; then JPDA_ADDRESS="9000" fi [root@server ~]# /home/tomcat/apache-tomcat-8.5.8/bin/startup.sh # 啟動Tomcat Using CATALINA_BASE: /home/tomcat/apache-tomcat-8.5.8 Using CATALINA_HOME: /home/tomcat/apache-tomcat-8.5.8 Using CATALINA_TMPDIR: /home/tomcat/apache-tomcat-8.5.8/temp Using JRE_HOME: /usr Using CLASSPATH: /home/tomcat/apache-tomcat-8.5.8/bin/bootstrap.jar:/home/tomcat/apache-tomcat-8.5.8/bin/tomcat-juli.jar Tomcat started. [root@server ~]# netstat -lntp |grep 9000 # 查看9000端口是否已被監聽 tcp 0 0 0.0.0.0:9000 0.0.0.0:* LISTEN 17380/java [root@server ~]#
然後我們新建一個Controller,用於演示遠程debug,所以代碼也比較簡單。代碼如下:
package org.zero01.monitor_tuning.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * @program: monitor_tuning * @description: Tomcat遠程debug演示 * @author: 01 * @create: 2018-07-15 17:58 **/ @RestController @RequestMapping("/remote/debug") public class TomcatRemoteDebugController { @RequestMapping("/hello") public String hello(@RequestParam(value = "size", defaultValue = "10") int size) { StringBuilder str = new StringBuilder(); for (int i = 0; i < size; i++) { str.append(i); } return str.toString(); } }
因為我們需要打成war包上傳到遠程的服務器上,所以需要讓SpringBoot的啟動類繼承 SpringBootServletInitializer ,並且重寫其中的configure方法。代碼如下:
package org.zero01.monitor_tuning;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class MonitorTuningApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MonitorTuningApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(MonitorTuningApplication.class);
}
}
接著將pom.xml配置文件中的打包方式,指定為war包:
<groupId>org.zero01</groupId>
<artifactId>monitor_tuning</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
最後使用maven命令進行打包,命令如下:
mvn clean package -Dmaven.skip.test=true
打包好後,上傳到遠程的服務器上,我這裏使用的是rz命令上傳的,也可以使用ftp工具來上傳。將上傳好的war包放到Tomcat的webapps目錄下:
[root@server ~]# ls
monitor_tuning-0.0.1-SNAPSHOT.war
[root@server ~]# mv monitor_tuning-0.0.1-SNAPSHOT.war monitor_tuning.war
[root@server ~]# ls
monitor_tuning.war
[root@server ~]# mv monitor_tuning.war /home/tomcat/apache-tomcat-8.5.8/webapps/
[root@server ~]# ls /home/tomcat/apache-tomcat-8.5.8/webapps/ # Tomcat會自動解壓war包
monitor_tuning monitor_tuning.war ROOT simple-blog
[root@server ~]#
Tomcat能夠正常解壓war包後,到瀏覽器上進行訪問看看能否訪問到我們編寫的接口,如下就是訪問成功的:
遠程的服務器配置好後,回到我們的工程中,添加一個遠程的Tomcat:
配置Debug的端口號:
以及服務器的ip地址和端口號:
完成以上配置後,在測試的代碼上打一個斷點,如下:
然後使用Debug模式進行啟動:
啟動成功後,和之前一樣到瀏覽器上訪問測試接口。可以看到,成功進入到斷點的位置了,這就表示我們可以進行遠程Debug了:
如果我們希望普通的Java進程也能支持遠程Debug的話,只需要在啟動的時候加入如下啟動參數即可:
-agentlib:jdwp=transport=$JPDA_TRANSPORT address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND
例如Tomcat其實就是加了這段參數:
-agentlib:jdwp=transport=dt_socket,address=9000,server=y,suspend=n
tomcat-manager監控
tomcat-manager是Tomcat自帶的一個監控及管理工具,在低版本的Tomcat中,該監控工具默認是開啟的。而在高版本的Tomcat中,由於一些安全上的問題,默認是不開啟的。
官方文檔地址如下(Tomcat9.0版本):
https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html
在高版本的Tomcat中我們需要手動開啟這個監控工具,開啟步驟如下:
- 在 conf/tomcat-users.xml 文件中添加管理員用戶
- 新建 conf/Catalina/localhost/manager.xml 文件,在該文件中配置允許的遠程連接
- 重啟Tomcat服務
首先是第一步,在 conf/tomcat-users.xml
文件的 < tomcat-users >
標簽內,增加如下配置內容:
[root@server ~]# vim /home/tomcat/apache-tomcat-8.5.8/conf/tomcat-users.xml // 配置內容如下
<role rolename="tomcat"/>
<role rolename="manager-status"/>
<role rolename="manager-gui"/>
<user username="zeroJun" password="123456a." roles="tomcat,manager-status,manager-gui"/>
第二步,新建 conf/Catalina/localhost/manager.xml 文件,在該文件中配置允許的遠程連接
[root@server ~]# vim /home/tomcat/apache-tomcat-8.5.8/conf/Catalina/localhost/manager.xml // 配置內容如下
<?xml version="1.0" encoding="UTF-8"?>
<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|101.106.102.*" /> // 配置允許訪問的ip
<Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>
第三步,啟動/重啟Tomcat服務:
[root@server ~]# /home/tomcat/apache-tomcat-8.5.8/bin/startup.sh
Using CATALINA_BASE: /home/tomcat/apache-tomcat-8.5.8
Using CATALINA_HOME: /home/tomcat/apache-tomcat-8.5.8
Using CATALINA_TMPDIR: /home/tomcat/apache-tomcat-8.5.8/temp
Using JRE_HOME: /usr
Using CLASSPATH: /home/tomcat/apache-tomcat-8.5.8/bin/bootstrap.jar:/home/tomcat/apache-tomcat-8.5.8/bin/tomcat-juli.jar
Tomcat started.
[root@server ~]#
啟動好後,在瀏覽器上訪問Tomcat的管理頁面,會要求輸入用戶名和密碼才能進行登錄:
登錄成功後,管理界面如下:
點擊 ”List Applications“ 可以看到當前的Tomcat部署的web應用列表:
在這裏點擊相應的按鈕,就可以重啟、重載、取消部署以及設置session過期時間:
在這裏可以上傳war包進行部署:
點擊右上角的 “Server Status” 可以看到Tomcat服務器的狀態信息:
如下:
我們在監控Tomcat的時候,就主要是查看這個界面中展示的信息,JVM一欄展示的是內存信息,而http-nio-8080一欄則是展示線程信息,一般我們關註這兩個地方就差不多了。
在該界面中,點擊右上角的 “Complete Server Status” 則能夠查看更完整的信息:
psi-probe監控
在上一小節中,我們簡單介紹了Tomcat自帶的監控工具,因為是自帶的,所以功能並不算很強大。而本小節將介紹更加強大的Tomcat監控工具,那就是psi-probe。
這家夥改了三次名,之前叫做lambdaprobe,最終的名字改為了psi-probe,之前是在googlecode下載,現在已經遷移到了github。
psi-probe的github地址如下:
https://github.com/psi-probe/psi-probe
使用git命令將psi-probe克隆到本地倉庫中,或者直接下載zip包再上傳到服務器也可以:
[root@01server ~]# cd /tmp
[root@01server /tmp]# git clone https://github.com/psi-probe/psi-probe.git
然後進入到psi-probe工程目錄中,使用maven命令進行編譯打包,這個編譯打包過程需要一段時間:
[root@01server /tmp]# cd psi-probe/
[root@01server /tmp/psi-probe]# mvn package -Dmaven.skip.test
打包完成後,將war包放到Tomcat的webapps目錄中:
[root@01server /tmp/psi-probe]# mv web/target/probe.war /usr/local/tomcat-8.5.32/webapps/
我這裏為了保證流程的完整,我這裏在另一臺服務器上安裝了新的Tomcat,所以我們還需要和之前一樣去開啟這個Tomcat的manager權限。
第一步,在 conf/tomcat-users.xml
文件的 < tomcat-users >
標簽內,增加如下配置內容:
[root@01server ~]# vim /usr/local/tomcat-8.5.32/conf/tomcat-users.xml // 配置內容如下
<role rolename="tomcat"/>
<role rolename="manager-status"/>
<role rolename="manager-gui"/>
<user username="zeroJun" password="123456a." roles="tomcat,manager-status,manager-gui"/>
第二步,新建 conf/Catalina/localhost/manager.xml 文件,在該文件中配置允許的遠程連接
[root@01server ~]# vim /usr/local/tomcat-8.5.32/conf/Catalina/localhost/manager.xml // 配置內容如下
<?xml version="1.0" encoding="UTF-8"?>
<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|101.106.102.*" /> // 配置允許訪問的ip
<Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>
第三步,啟動/重啟Tomcat服務:
[root@01server ~]# startup.sh
Using CATALINA_BASE: /usr/local/tomcat-8.5.32
Using CATALINA_HOME: /usr/local/tomcat-8.5.32
Using CATALINA_TMPDIR: /usr/local/tomcat-8.5.32/temp
Using JRE_HOME: /usr/local/jdk1.8
Using CLASSPATH: /usr/local/tomcat-8.5.32/bin/bootstrap.jar:/usr/local/tomcat-8.5.32/bin/tomcat-juli.jar
Tomcat started.
[root@01server ~]#
啟動好後,在瀏覽器上訪問psi-probe的管理頁面,同樣的會要求輸入用戶名和密碼才能進行登錄:
登錄成功後,主頁面如下,在這裏可以看到當前這個Tomcat服務器上的web應用:
在這個頁面上,可以看到web應用的統計信息、請求信息以及session信息,還可以對jsp進行預編譯。
在 “Data Source” 選項卡裏,可以看到數據源的相關信息,因為這裏目前沒有連接數據庫的應用,所以這塊是空的:
在 “Deployment” 選項卡裏,可以上傳war包到Tomcat上進行部署:
在 “logs” 選項卡裏,可以查看應用的日誌文件:
在 “Threads” 選項卡裏,可以查看到很詳細線程信息,和jstack打印出來的信息一樣:
在 “Cluster” 選項卡裏,可以查看到集群信息,由於沒有進行集群,所以這裏也是空的:
在 “System” 選項卡裏,可以查看到系統信息,例如JVM內存信息、系統屬性信息、操作系統信息等等:
在這個選項卡裏,我們還能實時看到內存信息,而且是圖表化的,很直觀:
在 “Connectors” 選項卡裏,可以查看到Tomcat的連接信息,例如請求數量、請求的處理時間以及請求響應字節數等信息,也是圖表化的:
在 “Gertificates” 選項卡裏,可以查看到證書相關的信息,我這裏也沒有配置證書,所以是空白的:
在 “Quick check” 選項卡裏,可以進行快速檢查,以此驗證服務環境是否是正常的:
Tomcat優化
在以上小節中,我們介紹了如何使用監控工具去監控Tomcat的運行狀況,而在監控之上就是調優。所以本小節將介紹一些簡單的Tomcat優化方式,主要涉及以下兩種優化(因為內存優化方面會單獨在另一篇JVM層GC調優文章中介紹):
- 線程優化
- 配置優化
1.線程優化:
我們都知道Tomcat是一個Web服務器,所以對於線程優化這方面主要還是關註用於http連接的線程。在以下官方文檔中,有對http連接線程相關參數的說明:
http://tomcat.apache.org/tomcat-8.5-doc/config/http.html
通過設置這些參數,我們能把Tomcat調整到一個較優的狀態。當然,這個調整需要根據服務器的具體配置及Tomcat的實際監控數據進行調整。常用的線程優化參數如下:
- maxConnections:最大連接數,當達到最大連接數時,請求會被放到請求隊列裏等待處理,對於NiO和NiO2,默認值為10000。對於APR/本機,默認值為8192
- acceptCount:最大請求隊列長度,當隊列滿時收到的任何請求都將被拒絕,默認值為100
- MaxThreads:最大工作線程數量,該參數的值決定了可處理的並發請求的最大數量,默認值為200
- minSpareThreads:最小空閑的工作線程數量,默認值為10
- enableLookups:該參數用於在執行
request.getRemoteHost();
語句時,能夠以DNS方式進行查詢,並返回遠程客戶端的實際主機名。默認值為false,會跳過DNS查詢,直接以字符串形式返回IP地址(從而提高性能),所以在生產環境下不要打開這個參數。 - protocol:該參數用於配置http協議,默認值為HTTP/1.1。該參數還可以設置連接器,默認情況下它使用自動切換機制來選擇基於NIO的連接器或基於APR/本機的連接器。如果是高並發場景下使用APR連接器性能會更高些,可選的值如下:
- org.apache.coyote.http11.Http11NioProtocol : NIO連接器
- org.apache.coyote.http11.Http11Nio2Protocol :NIO2連接器
- org.apache.coyote.http11.Http11AprProtocol :APR連接器
2.配置優化:
關於配置參數方面的介紹,官方文檔裏描述的也比較詳細了,地址如下:
http://tomcat.apache.org/tomcat-8.5-doc/config/host.html
http://tomcat.apache.org/tomcat-8.5-doc/config/context.html
常用的配置參數如下:
- autoDeploy:該參數用於指定是否開啟熱部署,默認值為true。因為實現熱部署需要單獨開啟一個線程去周期性的檢查server.xml中appBase屬性所配置的目錄,默認為webapps目錄,所以會影響Tomcat的性能。在線上一般都是關閉的,也就是設置為false
- reloadable:該參數用於開啟自動檢測代碼更改,當代碼更改時,會自動重新加載Web應用程序。默認值為false,該參數不應該在生產環境中開啟,會影響性能。但在開發過程中比較實用,所以挺多人會開啟這個參數,在上線時應該檢查該參數是否已關閉。
末尾:雖然現在的項目基本都是前後端分離了,JSP已經很少再用了,但不乏還是會出現JSP編寫的項目。如果是JSP項目,可以在不需要使用到session的JSP頁面上禁用session,不然每訪問一個JPS都開啟session的話,會影響性能。
Tomcat性能監控與調優