Java 监控
1. 概述
Java 监控是运维工作的重要组成部分,通过监控 JVM 内存、线程、GC、类加载等指标,可以及时发现和解决 Java 应用性能问题,保证系统稳定运行。在梵医云系统中,使用 Spring Boot Actuator + Micrometer + Prometheus 进行 Java 监控。本文档介绍如何配置和使用 Java 监控。
2. 监控体系架构
2.1 监控组件
梵医云系统 Java 监控包含以下组件:
- Spring Boot Actuator:应用监控端点
- Micrometer:监控指标收集库
- Prometheus:指标采集和存储
- Grafana:数据可视化
- JMX:Java 管理扩展
- Arthas:Java 诊断工具(可选)
2.2 监控架构
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Java App │ ───> │ Actuator │ ───> │ Prometheus │ ───> │ Grafana │
│ │ │ Micrometer │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ JMX │
└─────────────┘3. Spring Boot Actuator 配置
3.1 添加依赖
在 pom.xml 中添加依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>3.2 配置 Actuator
编辑 application.yaml:
yaml
management:
# 端点配置
endpoints:
# 默认启用所有端点
enabled-by-default: false
# 暴露的端点
web:
exposure:
include: "*"
# 只暴露特定端点
# include: "health,info,metrics,prometheus"
# 端点详情
endpoint:
# 健康检查端点
health:
# 显示详细信息
show-details: ALWAYS
# 显示组件信息
show-components: ALWAYS
# 指标端点
metrics:
enabled: true
# Prometheus 端点
prometheus:
enabled: true
# 信息端点
info:
enabled: true
# 环境端点
env:
enabled: true
# 日志端点
loggers:
enabled: true
# 线程转储端点
threaddump:
enabled: true
# 堆转储端点
heapdump:
enabled: true
# 端点基础路径
web:
base-path: /actuator
# 健康检查配置
health:
# 默认健康检查
defaults:
enabled: true
# Redis 健康检查
redis:
enabled: true
# DB 健康检查
db:
enabled: true
# 指标配置
metrics:
# 导出配置
export:
# Prometheus 导出
prometheus:
enabled: true
# 标签配置
tags:
application: ${spring.application.name}
env: ${spring.profiles.active}
# 启用 JVM 指标
enable:
jvm: true
process: true
system: true
tomcat: true
hikaricp: true
# 分布配置
distribution:
# 百分位数
percentiles-histogram:
http.server.requests: true
# 百分位数值
percentiles:
http.server.requests: 0.5,0.95,0.99
# SLA
slo:
http.server.requests: 100ms,200ms,500ms,1s,2s3.3 访问监控端点
启动应用后,可以访问以下端点:
- 健康检查:
http://localhost:48080/actuator/health - 指标信息:
http://localhost:48080/actuator/metrics - Prometheus 指标:
http://localhost:48080/actuator/prometheus - 环境信息:
http://localhost:48080/actuator/env - 日志信息:
http://localhost:48080/actuator/loggers - 线程转储:
http://localhost:48080/actuator/threaddump - 堆转储:
http://localhost:48080/actuator/heapdump - 应用信息:
http://localhost:48080/actuator/info
4. Micrometer 配置
4.1 自定义指标
创建自定义指标类:
java
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Component;
@Component
public class CustomMetrics {
private final Counter orderCounter;
private final Timer orderTimer;
public CustomMetrics(MeterRegistry registry) {
// 创建计数器
this.orderCounter = Counter.builder("order.count")
.description("订单数量")
.tag("type", "create")
.register(registry);
// 创建计时器
this.orderTimer = Timer.builder("order.duration")
.description("订单处理时间")
.tag("type", "create")
.register(registry);
}
public void incrementOrderCount() {
orderCounter.increment();
}
public void recordOrderTime(Runnable task) {
orderTimer.record(task);
}
}4.2 使用自定义指标
在业务代码中使用自定义指标:
java
@Service
public class OrderService {
private final CustomMetrics customMetrics;
public OrderService(CustomMetrics customMetrics) {
this.customMetrics = customMetrics;
}
public void createOrder(Order order) {
// 记录订单处理时间
customMetrics.recordOrderTime(() -> {
// 业务逻辑
saveOrder(order);
});
// 增加订单计数
customMetrics.incrementOrderCount();
}
}4.3 配置 Metrics
编辑 application.yaml:
yaml
fanyi:
metrics:
# 是否启用 Metrics
enable: true5. JMX 监控
5.1 启用 JMX
编辑 application.yaml:
yaml
spring:
jmx:
# 启用 JMX
enabled: true
# 唯一名称
unique-names: true5.2 使用 JMX 注解
创建 JMX 管理类:
java
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
@Component
@ManagedResource(objectName = "com.fanyi.cloud:type=OrderService,name=OrderService")
public class OrderService {
private int orderCount = 0;
@ManagedAttribute(description = "订单数量")
public int getOrderCount() {
return orderCount;
}
@ManagedOperation(description = "创建订单")
public void createOrder(String orderId) {
orderCount++;
// 业务逻辑
}
@ManagedOperation(description = "重置订单数量")
public void resetOrderCount() {
orderCount = 0;
}
}5.3 使用 JConsole 连接
- 打开 JConsole(JDK 自带)
- 输入连接信息:
- 远程进程:
192.168.1.10:48080 - 用户名密码(如果配置了认证)
- 远程进程:
- 连接成功后,可以查看和管理 MBean
5.4 使用 VisualVM 连接
- 打开 VisualVM
- 添加远程主机:
192.168.1.10 - 添加 JMX 连接:
192.168.1.10:48080 - 连接成功后,可以查看:
- 概览
- 监控(CPU、内存、类、线程)
- 线程
- MBeans
6. Prometheus 配置
6.1 配置 Prometheus 采集 Java 指标
编辑 prometheus.yml:
yaml
scrape_configs:
- job_name: 'fanyi-gateway'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
static_configs:
- targets: ['192.168.1.10:48080']
labels:
service: 'gateway'
env: 'dev'
instance: 'gateway-1'
- job_name: 'fanyi-system'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
static_configs:
- targets: ['192.168.1.10:48081']
labels:
service: 'system'
env: 'dev'
instance: 'system-1'
- job_name: 'fanyi-member'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
static_configs:
- targets: ['192.168.1.10:48087']
labels:
service: 'member'
env: 'dev'
instance: 'member-1'
- job_name: 'fanyi-trade'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
static_configs:
- targets: ['192.168.1.10:48090']
labels:
service: 'trade'
env: 'dev'
instance: 'trade-1'7. JVM 监控指标
7.1 内存指标
堆内存:
jvm_memory_used_bytes{area="heap"}:堆内存使用量jvm_memory_committed_bytes{area="heap"}:堆内存已提交量jvm_memory_max_bytes{area="heap"}:堆内存最大值jvm_memory_used_bytes{area="heap"}/jvm_memory_max_bytes{area="heap"}:堆内存使用率
非堆内存:
jvm_memory_used_bytes{area="nonheap"}:非堆内存使用量jvm_memory_committed_bytes{area="nonheap"}:非堆内存已提交量jvm_memory_max_bytes{area="nonheap"}:非堆内存最大值
内存池:
jvm_memory_pool_used_bytes:内存池使用量jvm_memory_pool_max_bytes:内存池最大值jvm_memory_pool_used_bytes{pool="G1 Eden Space"}:Eden 区使用量jvm_memory_pool_used_bytes{pool="G1 Old Gen"}:老年代使用量
7.2 GC 指标
GC 时间:
jvm_gc_pause_seconds_sum:GC 总时间jvm_gc_pause_seconds_count:GC 次数jvm_gc_pause_seconds_max:GC 最大时间rate(jvm_gc_pause_seconds_sum[5m]):GC 速率
GC 原因:
jvm_gc_pause_seconds{cause="G1 Evacuation Pause"}:G1 回收时间jvm_gc_pause_seconds{cause="G1 Humongous Allocation"}:大对象分配时间
GC 后内存:
jvm_gc_memory_allocated_bytes_total:GC 后分配的内存jvm_gc_memory_promoted_bytes_total:GC 后晋升到老年代的内存
7.3 线程指标
线程数量:
jvm_threads_live_threads:当前活跃线程数jvm_threads_peak_threads:峰值线程数jvm_threads_daemon_threads:守护线程数jvm_threads_states_threads:各状态线程数
线程状态:
jvm_threads_states_threads{state="RUNNABLE"}:运行状态线程数jvm_threads_states_threads{state="BLOCKED"}:阻塞状态线程数jvm_threads_states_threads{state="WAITING"}:等待状态线程数jvm_threads_states_threads{state="TIMED_WAITING"}:超时等待状态线程数
7.4 类加载指标
- 类加载:
jvm_classes_loaded_classes:当前加载的类数jvm_classes_unloaded_classes_total:卸载的类总数jvm_classes_loaded_classes_total:加载的类总数
7.5 CPU 指标
- 进程 CPU:
process_cpu_usage:进程 CPU 使用率system_cpu_usage:系统 CPU 使用率
7.6 文件描述符指标
- 文件描述符:
process_open_fds:打开的文件描述符数process_max_fds:最大文件描述符数
8. Grafana 仪表板
8.1 导入 JVM 仪表板
- 登录 Grafana
- 进入"Dashboards" -> "Import"
- 输入仪表板 ID:
4701(JVM (Micrometer)) - 点击"Load"
- 选择 Prometheus 数据源
- 点击"Import"
8.2 导入 Spring Boot 仪表板
- 登录 Grafana
- 进入"Dashboards" -> "Import"
- 输入仪表板 ID:
12900(Spring Boot Statistics) - 点击"Load"
- 选择 Prometheus 数据源
- 点击"Import"
8.3 自定义 Java 监控仪表板
创建自定义仪表板,监控以下指标:
JVM 内存:
- 堆内存使用量
- 堆内存使用率
- 非堆内存使用量
- 各内存池使用量
GC 监控:
- GC 次数
- GC 时间
- GC 速率
- GC 后内存
线程监控:
- 活跃线程数
- 各状态线程数
- 线程峰值
类加载监控:
- 加载的类数
- 卸载的类数
CPU 监控:
- 进程 CPU 使用率
- 系统 CPU 使用率
9. 告警配置
9.1 配置 Java 告警规则
创建 /data/prometheus/rules/java.yml:
yaml
groups:
- name: java_alerts
interval: 30s
rules:
# 高内存使用告警
- alert: HighMemoryUsage
expr: (jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.instance }} 堆内存使用率过高"
description: "服务 {{ $labels.instance }} 堆内存使用率超过 80%,当前值为 {{ $value }}%"
# 严重内存使用告警
- alert: CriticalMemoryUsage
expr: (jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100 > 90
for: 2m
labels:
severity: critical
annotations:
summary: "服务 {{ $labels.instance }} 堆内存使用率严重"
description: "服务 {{ $labels.instance }} 堆内存使用率超过 90%,当前值为 {{ $value }}%"
# GC 频繁告警
- alert: FrequentGC
expr: rate(jvm_gc_pause_seconds_count[5m]) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.instance }} GC 过于频繁"
description: "服务 {{ $labels.instance }} GC 频率超过 10 次/分钟,当前值为 {{ $value }} 次/分钟"
# GC 时间过长告警
- alert: LongGCTime
expr: rate(jvm_gc_pause_seconds_sum[5m]) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.instance }} GC 时间过长"
description: "服务 {{ $labels.instance }} GC 时间超过 1 秒/分钟,当前值为 {{ $value }} 秒/分钟"
# 线程数过多告警
- alert: HighThreadCount
expr: jvm_threads_live_threads > 500
for: 5m
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.instance }} 线程数过多"
description: "服务 {{ $labels.instance }} 线程数超过 500,当前值为 {{ $value }}"
# CPU 使用率过高告警
- alert: HighCpuUsage
expr: process_cpu_usage * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.instance }} CPU 使用率过高"
description: "服务 {{ $labels.instance }} CPU 使用率超过 80%,当前值为 {{ $value }}%"
# 文件描述符告警
- alert: HighFileDescriptorUsage
expr: (process_open_fds / process_max_fds) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.instance }} 文件描述符使用率过高"
description: "服务 {{ $labels.instance }} 文件描述符使用率超过 80%,当前值为 {{ $value }}%"10. Arthas 诊断工具
10.1 安装 Arthas
bash
# 下载 Arthas
wget https://arthas.aliyun.com/arthas-boot.jar
# 运行 Arthas
java -jar arthas-boot.jar10.2 Arthas 常用命令
查看线程:
bashthread thread -n 5 thread -b查看类加载:
bashsc -d com.fanyi.cloud.module.system.service.UserService sm -d com.fanyi.cloud.module.system.service.UserService getUserById查看方法调用:
bashwatch com.fanyi.cloud.module.system.service.UserService getUserById '{params, returnObj}'查看方法耗时:
bashtrace com.fanyi.cloud.module.system.service.UserService getUserById查看堆栈:
bashstack com.fanyi.cloud.module.system.service.UserService getUserById查看内存:
bashdashboard查看 GC:
bashvmtool --action getInstances --className java.lang.String --limit 10
11. 性能优化
11.1 JVM 参数优化
编辑启动脚本,添加 JVM 参数:
bash
java -jar app.jar \
# 堆内存大小
-Xms2g \
-Xmx2g \
# 新生代大小
-Xmn512m \
# 元空间大小
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
# GC 算法
-XX:+UseG1GC \
# GC 日志
-Xlog:gc*:file=/var/log/gc.log:time,tags:filecount=5,filesize=10m \
# OOM 时生成堆转储
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/heapdump.hprof \
# 禁用偏向锁
-XX:-UseBiasedLocking \
# 禁用类验证
-Xverify:none \
# 快速失败
-XX:+FailOverToOldVerifier \
# 启用压缩指针
-XX:+UseCompressedOops \
# 启用压缩类指针
-XX:+UseCompressedClassPointers11.2 GC 优化
根据应用特点选择合适的 GC 算法:
G1 GC(推荐):
bash-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16mCMS GC:
bash-XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelSurvivorRemarkEnabledZGC(Java 11+):
bash-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
11.3 线程池优化
合理配置线程池:
java
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, // 核心线程数
maximumPoolSize, // 最大线程数
keepAliveTime, // 线程空闲时间
TimeUnit.SECONDS, // 时间单位
workQueue, // 工作队列
rejectedHandler // 拒绝策略
);12. 常见问题
12.1 内存泄漏
问题:内存使用持续增长,最终 OOM
解决方案:
- 使用 VisualVM 分析堆转储
- 查找大对象和对象引用
- 检查静态集合和缓存
- 检查未关闭的资源
- 使用 Arthas 分析内存
12.2 CPU 飙升
问题:CPU 使用率突然飙升
解决方案:
- 使用 Arthas 查看线程状态
- 查找热点方法
- 检查死循环
- 检查正则表达式
- 检查序列化操作
12.3 GC 频繁
问题:GC 过于频繁,影响性能
解决方案:
- 增加堆内存大小
- 优化对象创建
- 使用对象池
- 调整 GC 参数
- 分析 GC 日志
12.4 线程阻塞
问题:线程长时间阻塞
解决方案:
- 使用 Arthas 查看线程堆栈
- 查找死锁
- 检查锁竞争
- 检查 I/O 操作
- 检查网络调用
13. 注意事项
- JVM 参数:根据实际情况调整 JVM 参数
- GC 监控:持续监控 GC 情况
- 内存监控:关注内存使用趋势
- 线程监控:关注线程数量和状态
- 告警配置:配置合理的告警规则
- 日志管理:定期清理 GC 日志
- 堆转储:OOM 时自动生成堆转储
- 性能优化:持续优化应用性能
