Tomcat监控与JVM监控实战

1. 概述

1.1 Tomcat监控的重要性

Tomcat监控是运维工作的核心环节,通过监控可以及时发现性能瓶颈、内存泄漏、线程死锁等问题,保障应用稳定运行。Tomcat作为Java应用服务器,其监控主要关注JVM内存、线程、GC(垃圾回收)等关键指标。

监控的价值

  • 性能优化:发现性能瓶颈,优化应用性能
  • 故障预防:提前发现潜在问题,避免故障发生
  • 资源管理:合理分配服务器资源
  • 问题定位:快速定位和解决生产问题

1.2 JVM监控工具

JDK自带监控工具

  • JConsole:图形化监控工具,简单易用
  • VisualVM:功能强大的可视化监控工具
  • jstat:命令行GC统计工具
  • jmap:内存映射工具
  • jstack:线程堆栈工具
  • jinfo:JVM配置信息工具

第三方监控工具

  • JProfiler:商业性能分析工具
  • YourKit:Java性能分析工具
  • MAT:内存分析工具
  • Prometheus + Grafana:监控指标收集和可视化

1.3 本文内容结构

本文将从以下几个方面详细介绍Tomcat和JVM监控:

  1. JMX监控基础:JMX原理和配置方式
  2. 无密码JMX监控:简单快速的监控配置
  3. 有密码JMX监控:安全的监控配置
  4. JConsole监控:使用JConsole进行监控
  5. VisualVM监控:使用VisualVM进行监控
  6. JVM命令行监控:jstat、jmap、jstack等工具
  7. 监控指标分析:关键指标解读和优化建议
  8. 生产环境监控方案:企业级监控实践

2. JMX监控基础

2.1 JMX简介

JMX(Java Management Extensions)是Java平台的管理和监控标准,提供了管理和监控Java应用程序的标准方法。通过JMX,可以监控JVM的内存、线程、GC等运行时信息。

JMX架构

  • MBean:管理Bean,暴露管理接口
  • MBeanServer:MBean服务器,管理MBean
  • Connector:连接器,提供远程访问
  • Protocol Adapter:协议适配器,支持不同协议

2.2 JMX监控方式

本地监控

  • 监控同一台机器上的Java应用
  • 无需额外配置
  • 直接连接本地进程

远程监控

  • 监控远程服务器上的Java应用
  • 需要配置JMX参数
  • 支持无密码和有密码两种方式

2.3 JMX端口说明

JMX端口

  • JMX端口:用于JMX连接(默认9999)
  • RMI端口:用于RMI通信(随机分配,可固定)

端口配置

  • com.sun.management.jmxremote.port:JMX连接端口
  • com.sun.management.jmxremote.rmi.port:RMI端口(可选)

3. 无密码方式JMX监控

3.1 配置说明

无密码方式适合内网环境或测试环境,配置简单,但安全性较低。

3.2 修改Tomcat配置

3.2.1 编辑catalina.sh

1
2
# 编辑Tomcat启动脚本
vim /application/tomcat/bin/catalina.sh

3.2.2 添加JMX参数

在catalina.sh文件中找到JAVA_OPTS配置位置,添加以下参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 设置JVM内存参数
JAVA_OPTS="$JAVA_OPTS -Xms128m -Xmx1024m -Xss1024K -XX:PermSize=512m -XX:MaxPermSize=512m"

# 设置JMX是否通过SSL连接(false表示不使用SSL)
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"

# 设置RMI远程连接IP地址(服务器IP地址)
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=192.168.6.13"

# 设置JMX远程连接端口号
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=12345"

# 设置JMX远程连接是否需要用户认证(false表示不需要认证)
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"

完整配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
# 在catalina.sh文件开头或JAVA_OPTS定义处添加
JAVA_OPTS="$JAVA_OPTS \
-server \
-Xms128m \
-Xmx1024m \
-Xss1024K \
-XX:PermSize=512m \
-XX:MaxPermSize=512m \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djava.rmi.server.hostname=192.168.6.13"

参数说明

参数 说明 示例值
-Xms 初始堆内存 128m
-Xmx 最大堆内存 1024m
-Xss 线程栈大小 1024K
-XX:PermSize 永久代初始大小 512m
-XX:MaxPermSize 永久代最大大小 512m
-Dcom.sun.management.jmxremote 启用JMX远程监控 -
-Dcom.sun.management.jmxremote.port JMX端口 12345
-Dcom.sun.management.jmxremote.ssl 是否使用SSL false
-Dcom.sun.management.jmxremote.authenticate 是否需要认证 false
-Djava.rmi.server.hostname RMI服务器主机名 192.168.6.13

注意

  • java.rmi.server.hostname必须设置为服务器的实际IP地址
  • 如果使用域名,确保客户端能够解析该域名
  • 生产环境建议使用有密码方式

3.3 启动Tomcat

1
2
3
4
5
6
7
8
9
10
# 启动Tomcat
/application/tomcat/bin/startup.sh

# 验证JMX端口是否监听
netstat -tunlp | grep 12345
# 或
ss -tunlp | grep 12345

# 查看Tomcat进程
ps -ef | grep [j]ava

验证输出

1
tcp        0      0 0.0.0.0:12345           0.0.0.0:*               LISTEN      12345/java

3.4 防火墙配置

1
2
3
4
5
6
7
# CentOS 7+ 使用firewalld
firewall-cmd --permanent --add-port=12345/tcp
firewall-cmd --reload

# 或使用iptables
iptables -A INPUT -p tcp --dport 12345 -j ACCEPT
service iptables save

3.5 使用JConsole连接

3.5.1 下载和安装JDK

Windows系统

Linux系统

  • 通常JDK已安装,JConsole位于:$JAVA_HOME/bin/jconsole

3.5.2 启动JConsole

Windows

1
2
3
4
5
# 方式1:直接运行
jconsole.exe

# 方式2:从开始菜单
开始 → 所有程序 → Java → JConsole

Linux

1
2
3
4
5
6
# 如果有图形界面
jconsole

# 或使用X11转发
ssh -X user@server
jconsole

3.5.3 连接远程Tomcat

连接步骤

  1. 启动JConsole

    • 打开JConsole工具
  2. 选择远程连接

    • 选择”远程进程”标签
    • 输入连接地址:192.168.6.13:12345
    • 点击”连接”
  3. 开始监控

    • 连接成功后,可以看到监控界面
    • 包含:概览、内存、线程、类、VM摘要、MBean等标签

连接地址格式

1
2
服务器IP:JMX端口
例如:192.168.6.13:12345

3.6 JConsole监控界面说明

3.6.1 概览(Overview)

显示内容

  • 堆内存使用情况
  • 线程数
  • 类加载数
  • CPU使用率

3.6.2 内存(Memory)

监控指标

  • 堆内存:Eden、Survivor、Old Generation
  • 非堆内存:Metaspace、Code Cache等
  • 内存使用趋势图

关键指标

  • 堆内存使用率
  • GC频率和耗时
  • 内存泄漏检测

3.6.3 线程(Threads)

监控指标

  • 活动线程数
  • 峰值线程数
  • 线程状态分布
  • 线程详细信息

关键指标

  • 线程死锁检测
  • 线程等待情况
  • 线程CPU使用率

3.6.4 类(Classes)

监控指标

  • 已加载类数
  • 已卸载类数
  • 类加载趋势

3.6.5 VM摘要(VM Summary)

显示内容

  • JVM版本信息
  • 运行时间
  • 线程统计
  • 内存统计
  • 系统属性

3.6.6 MBean

功能

  • 查看和操作MBean
  • 修改JVM参数(部分)
  • 触发GC
  • 查看详细信息

4. 有密码方式JMX监控

4.1 配置说明

有密码方式适合生产环境,提供安全认证,防止未授权访问。

4.2 JDK管理文件说明

JDK管理文件位置

1
$JAVA_HOME/jre/lib/management/

文件说明

  • jmxremote.access:用户名-权限文件
  • jmxremote.password.template:密码文件模板
  • jmxremote.password:密码文件(需要创建)
  • management.properties:管理配置文件

4.3 配置步骤

4.3.1 复制密码模板文件

1
2
3
4
5
6
7
8
# 进入JDK管理目录
cd $JAVA_HOME/jre/lib/management/

# 复制密码模板文件
cp jmxremote.password.template jmxremote.password

# 设置文件权限(必须设置为600,否则无法使用)
chmod 600 jmxremote.password

权限说明

  • 密码文件必须设置为600权限(仅所有者可读写)
  • 否则JMX会拒绝使用该文件

4.3.2 配置用户权限

编辑jmxremote.access文件

1
vim $JAVA_HOME/jre/lib/management/jmxremote.access

添加用户权限(文件末尾追加):

1
2
3
# 用户名 权限
admin readonly
monitor readwrite

权限类型

  • readonly:只读权限,只能查看监控信息
  • readwrite:读写权限,可以查看和修改配置
  • create:创建权限(通常不需要)

完整配置示例

1
2
3
# 文件格式:用户名 权限1,权限2,...
admin readonly
monitor readwrite

4.3.3 配置用户密码

编辑jmxremote.password文件

1
vim $JAVA_HOME/jre/lib/management/jmxremote.password

添加用户密码(文件末尾追加):

1
2
3
# 用户名 密码
admin 123456
monitor monitor123

完整配置示例

1
2
3
# 文件格式:用户名 密码
admin 123456
monitor monitor123

安全建议

  • 使用强密码
  • 定期更换密码
  • 限制密码文件访问权限

4.3.4 修改Tomcat配置

编辑catalina.sh

1
vim /application/tomcat/bin/catalina.sh

添加JMX参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 设置JVM内存参数
JAVA_OPTS="$JAVA_OPTS -Xms128m -Xmx1024m -Xss1024K -XX:PermSize=512m -XX:MaxPermSize=512m"

# 启用JMX远程监控
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote"

# 设置JMX端口
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=12345"

# 设置RMI服务器主机名
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=192.168.6.13"

# 启用用户认证
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=true"

# 指定密码文件路径(可选,默认使用$JAVA_HOME/jre/lib/management/jmxremote.password)
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.password.file=$JAVA_HOME/jre/lib/management/jmxremote.password"

# 指定权限文件路径(可选,默认使用$JAVA_HOME/jre/lib/management/jmxremote.access)
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.access.file=$JAVA_HOME/jre/lib/management/jmxremote.access"

# 是否使用SSL(生产环境建议使用SSL)
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"

完整配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
JAVA_OPTS="$JAVA_OPTS \
-server \
-Xms128m \
-Xmx1024m \
-Xss1024K \
-XX:PermSize=512m \
-XX:MaxPermSize=512m \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.authenticate=true \
-Dcom.sun.management.jmxremote.password.file=$JAVA_HOME/jre/lib/management/jmxremote.password \
-Dcom.sun.management.jmxremote.access.file=$JAVA_HOME/jre/lib/management/jmxremote.access \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=192.168.6.13"

4.3.5 启动Tomcat

1
2
3
4
5
# 启动Tomcat
/application/tomcat/bin/startup.sh

# 验证JMX端口
netstat -tunlp | grep 12345

4.4 使用JConsole连接

4.4.1 连接步骤

  1. 启动JConsole

    • 打开JConsole工具
  2. 选择远程连接

    • 选择”远程进程”标签
    • 输入连接地址:192.168.6.13:12345
    • 点击”连接”
  3. 输入用户名和密码

    • 弹出认证对话框
    • 输入用户名:admin
    • 输入密码:123456
    • 点击”确定”
  4. 开始监控

    • 连接成功后,可以查看监控信息
    • 根据用户权限,可以查看或修改配置

4.5 权限验证

只读用户(admin)

  • 可以查看所有监控信息
  • 不能修改JVM配置
  • 不能触发GC

读写用户(monitor)

  • 可以查看所有监控信息
  • 可以修改部分JVM配置
  • 可以触发GC

5. Java VisualVM监控

5.1 VisualVM简介

VisualVM是JDK自带的图形化监控工具,功能比JConsole更强大,提供了更丰富的监控和分析功能。

VisualVM特性

  • 多应用监控:同时监控多个Java应用
  • 性能分析:CPU和内存性能分析
  • 线程分析:线程转储和分析
  • 堆转储:生成和分析堆转储文件
  • 插件扩展:支持插件扩展功能

5.2 启动VisualVM

5.2.1 Windows系统

1
2
3
4
5
# 方式1:直接运行
jvisualvm.exe

# 方式2:从开始菜单
开始 → 所有程序 → Java → VisualVM

5.2.2 Linux系统

1
2
3
4
5
6
# 如果有图形界面
jvisualvm

# 或使用X11转发
ssh -X user@server
jvisualvm

5.3 添加JMX连接

5.3.1 添加远程连接

步骤

  1. 打开VisualVM

    • 启动VisualVM工具
  2. 添加JMX连接

    • 菜单:文件添加JMX连接...
    • 或右键左侧面板 → 添加JMX连接...
  3. 输入连接信息

    • 连接192.168.6.13:12345
    • 显示名称Tomcat-生产环境(可选)
    • 如果使用密码认证,会弹出认证对话框
  4. 连接

    • 点击”确定”连接

5.3.2 连接地址格式

1
2
服务器IP:JMX端口
例如:192.168.6.13:12345

5.4 VisualVM监控功能

5.4.1 概览(Overview)

显示内容

  • JVM版本和参数
  • 系统属性
  • 运行时间
  • 进程ID

5.4.2 监视(Monitor)

监控指标

  • CPU使用率:实时CPU使用情况
  • 堆内存:堆内存使用趋势
  • Metaspace:元空间使用情况
  • :已加载类数
  • 线程:活动线程数

功能

  • 实时图表显示
  • 数据导出
  • 性能分析

5.4.3 线程(Threads)

功能

  • 线程列表:查看所有线程
  • 线程状态:运行、等待、阻塞等
  • 线程转储:生成线程转储文件
  • 线程时间线:线程活动时间线

线程分析

  • 检测死锁
  • 查看线程堆栈
  • 分析线程等待情况

5.4.4 采样器(Sampler)

功能

  • CPU采样:分析CPU使用情况
  • 内存采样:分析内存使用情况

采样分析

  • 热点方法
  • 内存分配
  • 对象创建

5.4.5 Profiler(性能分析器)

功能

  • CPU性能分析:分析CPU使用热点
  • 内存性能分析:分析内存分配

注意

  • Profiler功能需要安装插件
  • 可能影响应用性能

5.4.6 堆转储(Heap Dump)

功能

  • 生成堆转储:生成堆内存快照
  • 分析堆转储:分析内存使用情况
  • 查找内存泄漏:定位内存泄漏问题

使用场景

  • 内存泄漏分析
  • 内存使用优化
  • 对象分布分析

5.5 VisualVM插件

5.5.1 安装插件

步骤

  1. 打开插件管理器

    • 菜单:工具插件
  2. 可用插件

    • 浏览可用插件
    • 选择需要的插件
  3. 安装插件

    • 点击”安装”
    • 等待安装完成

常用插件

  • Visual GC:GC可视化
  • Threads Inspector:线程检查器
  • MBeans Browser:MBean浏览器

6. JVM命令行监控工具

6.1 jstat - GC统计工具

6.1.1 基本用法

1
2
3
4
5
# 查看GC统计信息
jstat -gcutil <pid> <interval> <count>

# 示例:每1秒输出一次,共10次
jstat -gcutil 12345 1000 10

输出说明

1
2
S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
0.00 0.00 25.00 45.00 80.00 75.00 10 0.250 2 0.500 0.750

列说明

  • S0:Survivor 0使用率
  • S1:Survivor 1使用率
  • E:Eden区使用率
  • O:Old区使用率
  • M:Metaspace使用率
  • CCS:压缩类空间使用率
  • YGC:Young GC次数
  • YGCT:Young GC总耗时
  • FGC:Full GC次数
  • FGCT:Full GC总耗时
  • GCT:GC总耗时

6.1.2 常用选项

1
2
3
4
5
6
7
8
# 查看堆内存使用情况
jstat -gc <pid> 1000 10

# 查看类加载统计
jstat -class <pid> 1000 10

# 查看JIT编译统计
jstat -compiler <pid> 1000 10

6.2 jmap - 内存映射工具

6.2.1 查看堆内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 查看堆内存使用情况
jmap -heap <pid>

# 输出示例
Attaching to process ID 12345, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.60-b23

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 1073741824 (1024.0MB)
NewSize = 134217728 (128.0MB)
MaxNewSize = 134217728 (128.0MB)
OldSize = 939524096 (896.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
capacity = 100663296 (96.0MB)
used = 25165824 (24.0MB)
free = 75497472 (72.0MB)
25.0% used
...

6.2.2 生成堆转储

1
2
3
4
5
# 生成堆转储文件
jmap -dump:format=b,file=/tmp/heap_dump.hprof <pid>

# 使用live选项(只转储存活对象)
jmap -dump:live,format=b,file=/tmp/heap_dump.hprof <pid>

堆转储分析

  • 使用MAT(Memory Analyzer Tool)分析
  • 使用jhat分析(JDK自带)
  • 使用VisualVM分析

6.2.3 查看对象统计

1
2
3
4
5
# 查看对象实例统计
jmap -histo <pid> | head -20

# 查看存活对象统计
jmap -histo:live <pid> | head -20

6.3 jstack - 线程堆栈工具

6.3.1 生成线程转储

1
2
3
4
5
# 生成线程转储
jstack <pid> > /tmp/thread_dump.txt

# 查看线程转储
cat /tmp/thread_dump.txt

6.3.2 检测死锁

1
2
3
4
5
# 生成线程转储并检测死锁
jstack <pid> | grep -A 10 "deadlock"

# 或查看完整线程转储
jstack <pid> | grep -i "deadlock" -A 20

6.3.3 线程状态分析

线程状态

  • RUNNABLE:运行中
  • BLOCKED:阻塞
  • WAITING:等待
  • TIMED_WAITING:定时等待

分析命令

1
2
3
4
5
# 统计线程状态
jstack <pid> | grep "java.lang.Thread.State" | sort | uniq -c

# 查看等待线程
jstack <pid> | grep "WAITING" -A 5

6.4 jinfo - JVM配置信息

6.4.1 查看JVM参数

1
2
3
4
5
6
# 查看所有JVM参数
jinfo <pid>

# 查看特定参数
jinfo -flag MaxHeapSize <pid>
jinfo -flag UseG1GC <pid>

6.4.2 修改JVM参数(部分)

1
2
3
4
5
# 启用GC日志
jinfo -flag +PrintGCDetails <pid>

# 禁用GC日志
jinfo -flag -PrintGCDetails <pid>

注意

  • 只能修改部分JVM参数
  • 大部分参数需要在启动时设置

6.5 综合监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
cat > /usr/local/bin/jvm_monitor.sh << 'EOF'
#!/bin/bash

PID=$1
INTERVAL=${2:-5}
COUNT=${3:-12}

if [ -z "$PID" ]; then
echo "Usage: $0 <pid> [interval] [count]"
echo "Example: $0 12345 5 12"
exit 1
fi

echo "=== JVM Monitor for PID: $PID ==="
echo "Interval: ${INTERVAL}s, Count: ${COUNT}"
echo ""

# 1. 进程信息
echo "=== Process Info ==="
ps -p $PID -o pid,ppid,user,%cpu,%mem,rss,vsz,cmd
echo ""

# 2. GC统计
echo "=== GC Statistics ==="
jstat -gcutil $PID $INTERVAL $COUNT
echo ""

# 3. 堆内存
echo "=== Heap Memory ==="
jmap -heap $PID | grep -A 20 "Heap Usage"
echo ""

# 4. 线程统计
echo "=== Thread Statistics ==="
jstack $PID | grep "java.lang.Thread.State" | sort | uniq -c
echo ""

# 5. 死锁检测
echo "=== Deadlock Detection ==="
jstack $PID | grep -i "deadlock" -A 10
if [ $? -ne 0 ]; then
echo "No deadlock detected"
fi
EOF

chmod +x /usr/local/bin/jvm_monitor.sh

# 使用示例
# /usr/local/bin/jvm_monitor.sh 12345 5 12

7. 监控指标分析

7.1 内存监控指标

7.1.1 堆内存指标

关键指标

  • 堆内存使用率:应保持在70%以下
  • Eden区使用率:监控Young GC频率
  • Old区使用率:监控Full GC频率
  • Metaspace使用率:监控类加载情况

告警阈值

  • 堆内存使用率 > 80%:警告
  • 堆内存使用率 > 90%:严重告警
  • Full GC频率 > 1次/分钟:警告

7.1.2 内存泄漏检测

检测方法

  1. 趋势分析:堆内存持续增长
  2. GC分析:Full GC后内存不释放
  3. 堆转储分析:分析堆转储文件

分析工具

  • MAT(Memory Analyzer Tool)
  • VisualVM堆转储分析
  • jhat(JDK自带)

7.2 GC监控指标

7.2.1 GC频率

正常范围

  • Young GC:几秒到几分钟一次
  • Full GC:几分钟到几十分钟一次

异常情况

  • Young GC频率过高:Eden区过小或对象创建过快
  • Full GC频率过高:内存不足或内存泄漏

7.2.2 GC耗时

正常范围

  • Young GC:< 100ms
  • Full GC:< 1s

异常情况

  • GC耗时过长:堆内存过大或GC算法不当
  • Full GC频繁:需要优化内存配置

7.2.3 GC优化建议

优化策略

  1. 调整堆内存大小
  2. 选择合适的GC算法(G1、Parallel、CMS)
  3. 优化对象创建:减少临时对象
  4. 优化代码:避免内存泄漏

7.3 线程监控指标

7.3.1 线程数量

关键指标

  • 活动线程数:监控线程数量
  • 峰值线程数:监控线程峰值
  • 线程创建速率:监控线程创建情况

告警阈值

  • 活动线程数 > 1000:警告
  • 线程创建速率过快:警告

7.3.2 线程状态

关键指标

  • 运行线程:CPU使用情况
  • 等待线程:I/O等待情况
  • 阻塞线程:锁竞争情况

异常情况

  • 大量线程等待:可能存在性能瓶颈
  • 线程死锁:需要立即处理

7.4 CPU监控指标

7.4.1 CPU使用率

关键指标

  • 进程CPU使用率:监控进程CPU占用
  • 线程CPU使用率:定位CPU热点

告警阈值

  • CPU使用率 > 80%:警告
  • CPU使用率 > 95%:严重告警

7.4.2 CPU热点分析

分析方法

  1. VisualVM CPU采样
  2. JProfiler CPU分析
  3. jstack线程分析

8. 生产环境监控方案

8.1 监控架构

监控架构图

1
2
3
4
5
6
7
8
9
Tomcat应用

JMX暴露指标

├──→ JConsole/VisualVM(手动监控)
├──→ Prometheus(指标收集)
│ ↓
│ Grafana(可视化)
└──→ 告警系统(AlertManager)

8.2 Prometheus + JMX Exporter

8.2.1 安装JMX Exporter

1
2
3
4
5
6
7
8
# 下载JMX Exporter
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.17.0/jmx_prometheus_javaagent-0.17.0.jar

# 创建配置文件
cat > /application/tomcat/conf/jmx_prometheus_config.yml << 'EOF'
rules:
- pattern: '.*'
EOF

8.2.2 配置Tomcat

1
2
3
# 在catalina.sh中添加
JAVA_OPTS="$JAVA_OPTS \
-javaagent:/path/to/jmx_prometheus_javaagent-0.17.0.jar=12346:/application/tomcat/conf/jmx_prometheus_config.yml"

8.2.3 Prometheus配置

1
2
3
4
5
# prometheus.yml
scrape_configs:
- job_name: 'tomcat'
static_configs:
- targets: ['192.168.6.13:12346']

8.3 监控告警规则

8.3.1 内存告警

1
2
3
4
5
6
7
8
9
# Prometheus告警规则
groups:
- name: tomcat_memory
rules:
- alert: TomcatHeapMemoryHigh
expr: jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} > 0.8
for: 5m
annotations:
summary: "Tomcat堆内存使用率过高"

8.3.2 GC告警

1
2
3
4
5
- alert: TomcatFullGCFrequent
expr: rate(jvm_gc_collection_seconds_sum{gc="PS MarkSweep"}[5m]) > 0.01
for: 5m
annotations:
summary: "Tomcat Full GC频率过高"

8.4 监控最佳实践

  1. 多维度监控:内存、线程、GC、CPU
  2. 历史数据:保留至少30天历史数据
  3. 告警规则:设置合理的告警阈值
  4. 自动化处理:配置自动重启、扩容等
  5. 定期分析:定期分析监控数据,优化配置

9. 故障排查案例

9.1 案例1:内存泄漏

现象

  • 堆内存持续增长
  • Full GC频繁
  • 应用响应变慢

排查步骤

1
2
3
4
5
6
7
8
9
# 1. 查看堆内存使用趋势
jstat -gcutil <pid> 1000 60

# 2. 生成堆转储
jmap -dump:live,format=b,file=/tmp/heap_dump.hprof <pid>

# 3. 分析堆转储(使用MAT)
# 查找占用内存最大的对象
# 分析对象引用关系

解决方案

  • 修复内存泄漏代码
  • 增加堆内存大小(临时)
  • 优化对象创建

9.2 案例2:线程死锁

现象

  • 应用无响应
  • CPU使用率低
  • 线程数正常

排查步骤

1
2
3
4
5
6
7
8
# 1. 生成线程转储
jstack <pid> > /tmp/thread_dump.txt

# 2. 检测死锁
jstack <pid> | grep -i "deadlock" -A 20

# 3. 分析线程状态
jstack <pid> | grep "java.lang.Thread.State" | sort | uniq -c

解决方案

  • 修复死锁代码
  • 调整锁顺序
  • 使用超时锁

9.3 案例3:CPU占用高

现象

  • CPU使用率持续100%
  • 应用响应慢

排查步骤

1
2
3
4
5
6
7
8
9
# 1. 查看CPU使用情况
top -p <pid>

# 2. 生成线程转储
jstack <pid> > /tmp/thread_dump.txt

# 3. 查找CPU热点线程
# 查看RUNNABLE状态的线程
# 分析线程堆栈

解决方案

  • 优化热点代码
  • 减少循环计算
  • 使用缓存

10. 总结

10.1 核心要点

  1. JMX监控:无密码和有密码两种方式
  2. 监控工具:JConsole、VisualVM、命令行工具
  3. 监控指标:内存、GC、线程、CPU
  4. 故障排查:使用监控工具快速定位问题
  5. 生产实践:Prometheus + Grafana监控方案

10.2 架构师建议

  1. 监控设计

    • 多维度监控
    • 历史数据保留
    • 告警规则设计
  2. 工具选择

    • 开发环境:JConsole、VisualVM
    • 生产环境:Prometheus + Grafana
    • 故障排查:命令行工具
  3. 优化策略

    • 定期分析监控数据
    • 根据监控数据优化配置
    • 建立监控告警机制

10.3 学习路径

  1. 基础监控:JConsole、VisualVM使用
  2. 命令行工具:jstat、jmap、jstack
  3. 指标分析:理解关键监控指标
  4. 故障排查:掌握故障排查方法
  5. 生产实践:Prometheus监控方案

相关文章