Skip to content

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,2s

3.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: true

5. JMX 监控

5.1 启用 JMX

编辑 application.yaml

yaml
spring:
  jmx:
    # 启用 JMX
    enabled: true
    # 唯一名称
    unique-names: true

5.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 连接

  1. 打开 JConsole(JDK 自带)
  2. 输入连接信息:
    • 远程进程:192.168.1.10:48080
    • 用户名密码(如果配置了认证)
  3. 连接成功后,可以查看和管理 MBean

5.4 使用 VisualVM 连接

  1. 打开 VisualVM
  2. 添加远程主机:192.168.1.10
  3. 添加 JMX 连接:192.168.1.10:48080
  4. 连接成功后,可以查看:
    • 概览
    • 监控(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 仪表板

  1. 登录 Grafana
  2. 进入"Dashboards" -> "Import"
  3. 输入仪表板 ID:4701(JVM (Micrometer))
  4. 点击"Load"
  5. 选择 Prometheus 数据源
  6. 点击"Import"

8.2 导入 Spring Boot 仪表板

  1. 登录 Grafana
  2. 进入"Dashboards" -> "Import"
  3. 输入仪表板 ID:12900(Spring Boot Statistics)
  4. 点击"Load"
  5. 选择 Prometheus 数据源
  6. 点击"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.jar

10.2 Arthas 常用命令

  • 查看线程

    bash
    thread
    thread -n 5
    thread -b
  • 查看类加载

    bash
    sc -d com.fanyi.cloud.module.system.service.UserService
    sm -d com.fanyi.cloud.module.system.service.UserService getUserById
  • 查看方法调用

    bash
    watch com.fanyi.cloud.module.system.service.UserService getUserById '{params, returnObj}'
  • 查看方法耗时

    bash
    trace com.fanyi.cloud.module.system.service.UserService getUserById
  • 查看堆栈

    bash
    stack com.fanyi.cloud.module.system.service.UserService getUserById
  • 查看内存

    bash
    dashboard
  • 查看 GC

    bash
    vmtool --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:+UseCompressedClassPointers

11.2 GC 优化

根据应用特点选择合适的 GC 算法:

  • G1 GC(推荐):

    bash
    -XX:+UseG1GC
    -XX:MaxGCPauseMillis=200
    -XX:G1HeapRegionSize=16m
  • CMS GC

    bash
    -XX:+UseConcMarkSweepGC
    -XX:+CMSParallelRemarkEnabled
    -XX:+CMSParallelSurvivorRemarkEnabled
  • ZGC(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

解决方案

  1. 使用 VisualVM 分析堆转储
  2. 查找大对象和对象引用
  3. 检查静态集合和缓存
  4. 检查未关闭的资源
  5. 使用 Arthas 分析内存

12.2 CPU 飙升

问题:CPU 使用率突然飙升

解决方案

  1. 使用 Arthas 查看线程状态
  2. 查找热点方法
  3. 检查死循环
  4. 检查正则表达式
  5. 检查序列化操作

12.3 GC 频繁

问题:GC 过于频繁,影响性能

解决方案

  1. 增加堆内存大小
  2. 优化对象创建
  3. 使用对象池
  4. 调整 GC 参数
  5. 分析 GC 日志

12.4 线程阻塞

问题:线程长时间阻塞

解决方案

  1. 使用 Arthas 查看线程堆栈
  2. 查找死锁
  3. 检查锁竞争
  4. 检查 I/O 操作
  5. 检查网络调用

13. 注意事项

  1. JVM 参数:根据实际情况调整 JVM 参数
  2. GC 监控:持续监控 GC 情况
  3. 内存监控:关注内存使用趋势
  4. 线程监控:关注线程数量和状态
  5. 告警配置:配置合理的告警规则
  6. 日志管理:定期清理 GC 日志
  7. 堆转储:OOM 时自动生成堆转储
  8. 性能优化:持续优化应用性能

14. 相关文档