Tomcat 企業級運維實戰系列(四):Tomcat 企業級監控
- 一:監控工具
- 1)概述
- 2)流程
- 3)部署
- 二:監控命令
- 1)`jps`
- 2)`jstack`
- 3)`jmap`
- 4)`MAT` 工具分析
- 三:監控腳本
- 四:Java 系統負載與性能排查流程
- 1)初步觀察系統負載
- 2)判斷負載來源
- 3)確定問題進程
- 4)進一步分析
- 5)問題解決與總結
- 總結
🚀 Tomcat 系列文章導航
本系列系統講解 Linux 環境下 Apache Tomcat 的部署、配置、管理與優化,并最終帶你完成 企業級前后端分離項目上線。無論你是初學者還是想進階的運維人員,這份路線圖都能幫你快速構建完整的知識體系。
?? 該系列所有涉及的軟件包和項目都可以私信博主免費獲取
- 👉 第一部分:Tomcat 核心概念與基礎部署
- 👉 第二部分:Tomcat 系統化管理與應用部署
- 👉 第三部分:Tomcat 配置解析與集群化部署
- 👉 第四部分:Tomcat 企業級監控
- 👉 第五部分:Tomcat 優化和安全加固
- 👉 第六部分:綜合項目實戰:Java 前后端分離架構部署
一:監控工具
1)概述
-
可通過 Zabbix / Grafana / Prometheus 等工具監控 Tomcat/Java。
-
需要在 Tomcat 中開啟 Java 遠程監控功能(JMX Remote)。
-
也可在 Windows 安裝 JDK,使用 jconsole / jvisualvm 工具遠程連接 Tomcat 進行監控。
2)流程
-
在 Linux 修改 Tomcat 啟動參數,開啟 JMX 遠程監控功能。
-
重啟 Tomcat 使配置生效。
-
查看進程確認參數是否加載。
-
在 Windows 安裝 JDK,并使用工具連接。
3)部署
-
修改
Tomcat
啟動參數參數 說明 -Dcom.sun.management.jmxremote
開啟遠程監控功能 -Dcom.sun.management.jmxremote.port=12345
指定 JMX 端口 -Dcom.sun.management.jmxremote.authenticate=false
關閉認證 -Dcom.sun.management.jmxremote.ssl=false
關閉 SSL 加密 -Djava.rmi.server.hostname=192.168.2.104
綁定監聽的 IP(通常填內網IP) [root@web01 ~]# vim /opt/module/tomcat-8.5.87/bin/catalina.sh
?? 注意:Tomcat 8.5+ 中配置需用
\
換行。CATALINA_OPTS="$CATALINA_OPTS \ -Dcom.sun.management.jmxremote \ -Dcom.sun.management.jmxremote.port=12345 \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -Djava.rmi.server.hostname=192.168.2.104"
-
啟動
Tomcat
[root@web01 ~]# systemctl start tomcat
-
Window
安裝JDK
配置環境變量:
JAVA_HOME=D:\...\jdk1.8.0_212
Path=%JAVA_HOME%\bin;
C:\Users\86152>java -version java version "1.8.0_212" Java(TM) SE Runtime Environment (build 1.8.0_212-b10) Java HotSpot(TM) 64-Bit Server VM (build 25.212-b10, mixed mode)
-
監控
-
使用
JConsole
監控路徑:
D:\...\jdk1.8.0_212\bin\jconsole.exe
1. 打開 JConsole2. 選擇 遠程連接 → 輸入 IP:指定 JMX 端口3. 如果關閉認證/SSL,則為“不安全連接”4. 進入控制臺即可查看 JVM 的內存、線程、類加載等信息
-
使用
JVisualVM
監控路徑:
D:\...\jdk1.8.0_212\bin\jvisualvm.exe
1. 打開 JVisualVM2. 添加遠程主機 → 輸入主機名/IP(不用帶端口)3. 添加 JMX 連接 → 輸入 IP:指定 JMX 端口4. 雙擊連接,即可查看監控效果
-
二:監控命令
1)jps
-
作用:查看正在運行的 Java 進程(類似
ps -ef | grep java
,但只顯示 Java 進程)。 -
常用命令
# 查看所有 Java 進程 jps# 查看詳細信息(主類名、JVM參數等) jps -lvm | grep tomcat
2)jstack
-
作用:查看指定 Java 進程的線程信息,用于分析線程狀態、死鎖等問題。
-
操作步驟
線程狀態說明:
- NEW:新建
- RUNNABLE:就緒
- RUNNING:運行中
- BLOCKED:阻塞(常見于 IO)
- DEAD:死亡
# 查看 Java 進程 PID jps 80177 Bootstrap# 查看該進程的線程棧信息 jstack 80177# 僅查看線程狀態 jstack 80177 | grep -i state
3)jmap
-
作用:查看或導出 JVM 內存信息。
-
常用命令
# 查看 JVM 內存使用情況 jmap -heap 80177# 導出 JVM 內存鏡像文件(用于分析) jmap -dump:format=b,file=8080.hprof 80177
4)MAT
工具分析
-
作用:圖形化分析
.hprof
堆內存鏡像文件,排查內存泄漏、對象占用過大等問題。 -
使用步驟
-
在 Linux 導出堆文件:
jmap -dump:format=b,file=8080.hprof 80177sz 8080.hprof # 傳輸到本地
-
Windows/Mac/Linux 安裝
MAT
下載地址: Memory Analyzer (MAT) | The Eclipse Foundation
-
打開
.hprof
文件1. 歡迎頁選擇 Open a Heap Dump2. 選擇 Leak Suspects Report 查看內存泄漏報告
-
三:監控腳本
show-busy-java-thread.sh
顯示當前環境中,所有繁忙的java線程. 以百分數顯示使用率最高的前幾個線程.
#!/bin/bash
# @Function
# Find out the highest cpu consumed threads of java, and print the stack of these threads.
#
# @Usage
# $ ./show-busy-java-threads.sh
#
# @author Jerry Leereadonly PROG=`basename $0`
readonly -a COMMAND_LINE=("$0" "$@")usage() {cat <<EOF
Usage: ${PROG} [OPTION]...
Find out the highest cpu consumed threads of java, and print the stack of these threads.
Example: ${PROG} -c 10Options:-p, --pid find out the highest cpu consumed threads from the specifed java process,default from all java process.-c, --count set the thread count to show, default is 5-h, --help display this help and exit
EOFexit $1
}readonly ARGS=`getopt -n "$PROG" -a -o c:p:h -l count:,pid:,help -- "$@"`
[ $? -ne 0 ] && usage 1
eval set -- "${ARGS}"while true; docase "$1" in-c|--count)count="$2"shift 2;;-p|--pid)pid="$2"shift 2;;-h|--help)usage;;--)shiftbreak;;esac
done
count=${count:-5}redEcho() {[ -c /dev/stdout ] && {# if stdout is console, turn on color output.echo -ne "\033[1;31m"echo -n "$@"echo -e "\033[0m"} || echo "$@"
}yellowEcho() {[ -c /dev/stdout ] && {# if stdout is console, turn on color output.echo -ne "\033[1;33m"echo -n "$@"echo -e "\033[0m"} || echo "$@"
}blueEcho() {[ -c /dev/stdout ] && {# if stdout is console, turn on color output.echo -ne "\033[1;36m"echo -n "$@"echo -e "\033[0m"} || echo "$@"
}# Check the existence of jstack command!
if ! which jstack &> /dev/null; then[ -z "$JAVA_HOME" ] && {redEcho "Error: jstack not found on PATH!"exit 1}! [ -f "$JAVA_HOME/bin/jstack" ] && {redEcho "Error: jstack not found on PATH and $JAVA_HOME/bin/jstack file does NOT exists!"exit 1}! [ -x "$JAVA_HOME/bin/jstack" ] && {redEcho "Error: jstack not found on PATH and $JAVA_HOME/bin/jstack is NOT executalbe!"exit 1}export PATH="$JAVA_HOME/bin:$PATH"
fireadonly uuid=`date +%s`_${RANDOM}_$$cleanupWhenExit() {rm /tmp/${uuid}_* &> /dev/null
}
trap "cleanupWhenExit" EXITprintStackOfThread() {local linelocal count=1while IFS=" " read -a line ; dolocal pid=${line[0]}local threadId=${line[1]}local threadId0x=`printf %x ${threadId}`local user=${line[2]}local pcpu=${line[4]}local jstackFile=/tmp/${uuid}_${pid}[ ! -f "${jstackFile}" ] && {{if [ "${user}" == "${USER}" ]; thenjstack ${pid} > ${jstackFile}elseif [ $UID == 0 ]; thensudo -u ${user} jstack ${pid} > ${jstackFile}elseredEcho "[$((count++))] Fail to jstack Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user})."redEcho "User of java process($user) is not current user($USER), need sudo to run again:"yellowEcho " sudo ${COMMAND_LINE[@]}"echocontinuefifi} || {redEcho "[$((count++))] Fail to jstack Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user})."echorm ${jstackFile}continue}}blueEcho "[$((count++))] Busy(${pcpu}%) thread(${threadId}/0x${threadId0x}) stack of java process(${pid}) under user(${user}):"sed "/nid=0x${threadId0x} /,/^$/p" -n ${jstackFile}done
}ps -Leo pid,lwp,user,comm,pcpu --no-headers | {[ -z "${pid}" ] &&awk '$4=="java"{print $0}' ||awk -v "pid=${pid}" '$1==pid,$4=="java"{print $0}'
} | sort -k5 -r -n | head --lines "${count}" | printStackOfThread
四:Java 系統負載與性能排查流程
1)初步觀察系統負載
-
使用
w
/top
/uptime
查看系統整體負載 -
如果 負載 > CPU 核心數 × 60%~70%,說明系統存在瓶頸
-
命令:
w uptime lscpu top -1
2)判斷負載來源
-
CPU 負載
- 命令:
top
→ 觀察%us
(用戶態 CPU 占比) - 若 CPU 過高,說明是計算型壓力
- 工具:
ps aux
/htop
/top
- 命令:
-
IO 負載
- 命令:
top
→ 觀察%wa
(I/O 等待占比) - 若 IO 過高,說明磁盤或網絡瓶頸
- 工具:
iotop
- 命令:
3)確定問題進程
- 使用
ps aux
/htop
/top
查找占用 CPU/內存較高的進程 - 獲取 Java 進程 ID (PID)
4)進一步分析
-
查看日志
- 檢查應用日志(如
catalina.out
),排查異常或錯誤
- 檢查應用日志(如
-
線程分析
-
使用
jstack
查看線程堆棧信息 -
關注線程狀態(Runnable、Blocked、Waiting 等)
-
示例:
jstack <pid> jstack <pid> | grep -i state
-
-
JVM 內存分析
-
導出堆內存鏡像:
jmap -dump:format=b,file=/root/jvm.hprof <pid>
-
查看 JVM 內存使用情況:
jmap -heap <pid>
-
-
堆文件分析
- 將
.hprof
文件傳至本地 - 使用 MemoryAnalyzer Tool (MAT) 或 Eclipse MAT 插件打開
- 重點查看:
- Leak Suspects Report(內存泄漏嫌疑報告)
- 對象占用情況(哪些類實例過多/占用大)
- 將
5)問題解決與總結
- 根據
jstack
定位線程死鎖/阻塞點 - 根據
jmap
+ MAT 分析內存泄漏問題 - 結合日志和監控,優化代碼或調整 JVM 參數
- 驗證問題是否解決
總結
📌 本節重點回顧
-
監控工具
-
學會了通過 JMX 遠程監控,結合 JConsole、JVisualVM 等工具查看 JVM 內存、線程、類加載等運行狀態。
-
掌握了在 Linux 修改 catalina.sh 啟動參數 的方法,開啟遠程監控端口。
-
-
監控命令
-
jps → 查看 Java 進程
-
jstack → 分析線程堆棧,定位死鎖/阻塞
-
jmap → 導出內存快照,分析堆使用情況
-
配合 MAT 工具 圖形化分析 .hprof,排查內存泄漏
-
-
監控腳本
- 通過 show-busy-java-thread.sh 快速定位 最耗 CPU 的線程,并打印線程堆棧信息,便于排錯。
-
性能排查流程
-
先看系統整體負載(w、top、uptime)
-
判斷是 CPU 負載 還是 IO 負載
-
確定問題進程 → 結合 jstack / jmap 分析
-
使用 日志 + 堆分析工具(MAT) 找出瓶頸
-
優化代碼、JVM 參數或系統資源配置
-
? 至此,你已經掌握了 Tomcat 與 JVM 的監控手段,能從 進程 → 線程 → 內存 → 系統層面 全方位排查性能問題。
下一篇將進入 Tomcat 優化與安全加固,進一步打造穩定、高性能的生產環境。