前言

1. Grafana 是什么

开始前首先要问一个问题,Grafana 到底是什么。

Grafana 是一个监控仪表系统,它是由 Grafana Labs 公司开源的的一个系统监测 (System Monitoring) 工具。它可以大大帮助你简化监控的复杂度,你只需要提供你需要监控的数据,它就可以帮你生成各种可视化仪表。同时它还有报警功能,可以在系统出现问题时通知你。

Grafana 不对数据源作假设,它支持以下各种数据,也就是说如果你的数据源是以下任意一种,它都可以帮助生成仪表。同时在市面上,如果 Grafana 称第二,那么应该没有敢称第一的仪表可视化工具了。因此,如果你搞定了 Grafana,它几乎是一个会陪伴你到各个公司的一件称心应手的兵器。

2.Prometheus是什么

Prometheus 是一个时间序列数据库。但是,它不仅仅是一个时间序列数据库。它涵盖了可以绑定的整个生态系统工具集及其功能,非常适合Kubernetes集群的监控。Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态,任意组件只要提供对应的HTTP接口就可以接入监控。不需要任何SDK或者其他的集成过程。这样做非常适合做虚拟化环境监控系统,比如VM、Docker、Kubernetes等。输出被监控组件信息的HTTP接口被叫做exporter 。目前互联网公司常用的组件大部分都有exporter可以直接使用,比如Varnish、Haproxy、Nginx、MySQL、Linux系统信息(包括磁盘、内存、CPU、网络等等)。Promethus有以下特点:

  • 支持多维数据模型:由度量名和键值对组成的时间序列数据
  • 内置时间序列数据库TSDB
  • 支持PromQL查询语言,可以完成非常复杂的查询和分析,对图表展示和告警非常有意义
  • 支持HTTP的Pull方式采集时间序列数据
  • 支持PushGateway采集瞬时任务的数据
  • 支持服务发现和静态配置两种方式发现目标
  • 支持接入Grafana

3.Grafana与Prometheus之间的关系

把 车辆 类比为 计算机系统 或者一个 软件系统:Grafana就是仪表盘,它和车辆的速度表、水温表是一类的,通过这些表盘你可以实时了解系统运行情况。而Prometheus作为一个时序数据库,其实它和大家熟知的Mysql是一类的东西,都是存储数据,提供查询的,它存储了计算机系统在各个时间点上的监控数据。而Grafana仪表盘上的数据,就是通过查询Prometheus获取的。

可观察性已经成为现代软件开发的一个重要组成部分。在今天这个快节奏的世界里,能够快速识别和解决应用程序中的问题至关重要。可观察性是监控和分析你的应用程序内部状态的做法,以获得对其行为、性能和可靠性的洞察力。通过采用可观察性实践,你可以更容易地识别和解决问题,确保你的应用程序以最佳状态运行。

在这篇文章中,我们将探讨为什么可观察性很重要,以及如何使用Prometheus和Grafana来监控Spring Boot应用程序。

为什么可观察性很重要?

可观察性之所以重要,有几个原因。

  • 首先,它可以让你主动监测应用程序的性能,并在问题变得严重之前发现任何问题。这在当今的云原生世界中尤为重要,因为在这个世界中,应用程序被部署在高度动态和分布式的基础设施上。
  • 其次,可观察性使你能够在问题发生时快速识别和诊断。有了正确的工具,你可以迅速找出任何问题的根本原因,节省时间和资源。
  • 最后,可观察性可以帮助你优化你的应用程序的性能。通过监控关键指标和分析性能数据,你可以确定需要改进的地方,并优化你的应用程序,使其更有效地运行。

首先,让我们了解一下所涉及的各个组成部分。下面的图表说明了监控过程是如何运作的。

Spring Boot应用程序包括一个Actuator模块,用于促进应用程序的监控和管理。

它与第三方监控工具无缝集成,包括Prometheus。Micrometer负责从应用中收集指标,并将其暴露给外部系统。在这种情况下,它将收集到的指标转发给Prometheus。Grafana是一个可视化工具,在仪表盘上显示从数据源(如Prometheus)获得的指标。

使用Prometheus和Grafana监控Spring Boot应用

现在我们明白了为什么可观察性很重要,让我们来探讨一下如何使用Prometheus和Grafana来监控Spring Boot应用。Prometheus是一个强大的监控工具,可以从你的应用程序中收集和存储指标。Grafana是一个可视化工具,可以对Prometheus收集的数据提供实时的洞察力。

第一步:将Prometheus添加到你的Spring Boot项目中

第一步是将Prometheus的依赖性添加到你的Spring Boot项目。你可以通过在你的pom.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>

第2步:配置Prometheus

接下来,你需要配置Prometheus和Micrometer。这涉及到在你的application.properties文件中添加以下属性:

management:
  # 配置 Spring Boot 的管理端点(如健康检查、指标等)
  endpoints:
    # 配置管理端点的 web 相关暴露设置
    web:
      # 设置暴露的端点,'include: *' 表示暴露所有管理端点
      exposure:
        include: '*'
    
    # 配置 Spring Boot 的指标收集和导出设置
    metrics:
      # 配置 Prometheus 导出设置
      export:
        prometheus:
          # 启用 Prometheus 数据导出功能,允许 Prometheus 从 Spring Boot 应用中抓取指标
          enabled: true
          
      # 设置 Spring Boot 应用的标签信息
      tags:
        # 为导出的 Prometheus 数据添加标签,这里使用应用程序的名称作为标签值
        application: '${spring.application.name}'

第3步:启动你的Spring Boot应用程序并验证指标是否被收集

一旦你添加了Prometheus的依赖关系并配置了Prometheus,你就可以启动Spring Boot应用程序并验证指标是否被收集。你可以通过访问下面的URL来做这件事:http://localhost:8080/actuator/prometheus

第4步:安装和配置prometheus

创建配置文件目录

在宿主机上创建 Prometheus 和 Grafana 的配置文件目录并配置权限:

mkdir -p /data/docker/{grafana,prometheus}
chmod -R 777 /data/docker/grafana
chmod -R 777 /data/docker/prometheus

这些目录将用于存放 Prometheus 和 Grafana 的配置文件和数据。

准备 Prometheus 配置文件

创建 prometheus.yml 文件并放置在 /data/docker/prometheus 目录下:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'spring-boot-application'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['<Spring Boot 应用的 IP>:<端口>']

注意:在 targets 中填写你的 Spring Boot 应用的 IP 地址和端口,以便 Prometheus 能够正确采集监控指标。

启动 Prometheus 容器

运行 Prometheus 容器并挂载配置文件和数据目录:

docker run -d \
  --name=prometheus \
  -p 9090:9090 \
  -v /data/docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \
  -v /data/docker/prometheus:/prometheus \
  prom/prometheus

启动后,你可以通过访问 http://localhost:9090 来查看 Prometheus 的 Web 界面。

第5步:安装和配置Grafana

最后一步是安装和配置Grafana。你可以通过以下步骤来完成:

在你的机器上下载并安装Grafana。登录到Grafana网络界面,并导航到数据源部分。添加一个新的数据源,选择Prometheus作为数据源类型。

启动 Grafana 容器

运行 Grafana 容器并挂载数据目录:

docker run -d \
  --name=grafana \
  -p 3000:3000 \
  -v /data/docker/grafana:/var/lib/grafana \
  grafana/grafana

访问 Grafana 的 Web 界面(默认地址为 http://localhost:3000,用户名和密码为 admin/admin),添加 Prometheus 作为数据源:

在最新版中,左侧菜单栏有一个 Connections ,在这里添加即可:

添加数据源:

点击 "Save & Test" 按钮,如果配置正确,将显示 "Data source is working" 的提示

2.创建仪表板

在 Grafana 中创建新的仪表板,并添加面板来展示关心的监控指标。可以通过 Prometheus 查询语言(PromQL)选择希望可视化的指标。例如,你可以添加一个面板来展示 Spring Boot 应用的请求延迟:

job:http_request_duration_seconds:mean5m{job="spring-boot-application"}

通过这种方式,你可以创建多个面板,展示不同的监控指标,如请求量、错误率等。

导航到Grafana仪表盘部分。点击 "New Dashboard "按钮,选择 "Add new panel"。

报警配置(可选)

1.配置 Alertmanager

创建 alertmanager.yml 文件并放置在 /data/docker/prometheus 目录下:

yaml复制代码

global:
  resolve_timeout: 5m

route:
  group_by: ['alertname']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 12h
  receiver: 'webhook'

receivers:
  - name: 'webhook'
    webhook_configs:
      - url: 'https://your-webhook-url'

在 url 中填写你的 Webhook 接收地址,用于接收报警通知

2.配置 Prometheus 告警规则

创建 prometheus.rules.yml 文件并放置在 /data/docker/prometheus 目录下:

groups:
  - name: example
    rules:
      - alert: HighRequestLatency
        expr: job:http_request_duration_seconds:mean5m{job="spring-boot-application"} > 0.5
        for: 10m
        labels:
          severity: page
        annotations:
          summary: "High request latency on {{ $labels.instance }}"
          description: "{{ $labels.instance }} has a mean request latency above 0.5s (current value: {{ $value }}s)"

在 expr 中定义了告警规则,当请求延迟超过 0.5 秒时触发告警

3.启动 Alertmanager 容器

运行 Alertmanager 容器并挂载配置文件:

docker run -d \
  --name=alertmanager \
  -p 9093:9093 \
  -v /data/docker/prometheus/alertmanager.yml:/etc/alertmanager/config.yml \
  prom/alertmanager

4.配置 Prometheus 使用 Alertmanager

在 prometheus.yml 文件中添加 Alertmanager 配置:

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']

通过以上配置,Prometheus 将能够将告警信息发送到 Alertmanager,进而触发报警通知

一个参考的prometheus配置文件

/prometheus/prometheus.yml

# 全局配置
global:
  # 设置抓取目标的默认时间间隔,表示 Prometheus 每 15 秒抓取一次目标数据
  scrape_interval: 15s
  # 设置评估规则的默认时间间隔,表示 Prometheus 每 15 秒评估一次告警规则
  evaluation_interval: 15s
  # 默认抓取超时设置为10秒
  # scrape_timeout is set to the global default (10s).

# 告警配置
alerting:
  # 配置告警管理器,指定告警接收的目标地址
  alertmanagers:
    - static_configs:
        # 告警接收地址,Prometheus 会将告警信息发送到此地址
        - targets: ['127.0.0.1:9093']

# 加载规则文件,并根据全局“评估间隔”定期评估规则
rule_files:
  # 指定规则文件的位置
  - "/etc/prometheus/rules.yml"

# 控制 Prometheus 监控哪些资源
# 默认配置中,Prometheus 会配置一个名为 'prometheus' 的作业,该作业用于抓取 Prometheus 服务器本身公开的时间序列数据
scrape_configs:
  # 作业名称会作为标签“job=<job_name>`添加到此配置中获取的任何数据
  - job_name: 'prometheus'
    # 静态配置,指定 Prometheus 要抓取的目标地址
    static_configs:
      # 目标地址,Prometheus 会从此地址抓取数据(通常是 Prometheus 自己暴露的指标)
      - targets: ['localhost:9090']

  - job_name: 'node'
    # 静态配置,指定 Prometheus 要抓取的目标地址
    static_configs:
      # 目标地址,Prometheus 会从此地址抓取数据(通常是 Node Exporter)
      - targets: ['localhost:9100']
        # 为此目标添加标签,用于标识环境和角色
        labels:
          env: dev
          role: docker

  - job_name: 'prometheusapp'
    # 设置自定义的 metrics 路径,告诉 Prometheus 从哪里抓取应用程序的指标数据
    metrics_path: '/actuator/prometheus'
    static_configs:
      # 目标地址,Prometheus 会从该地址抓取 Prometheus 应用程序的指标数据
      - targets: ['host.docker.internal:8080']

编辑告警规则文件

/prometheus/rules.yml

groups:
- name: example
  rules:
 # Alert for any instance that is unreachable for >5 minutes.
  - alert: InstanceDown
    expr: up == 0
    for: 1m
    labels:
      serverity: page
    annotations:
      summary: "Instance {{ $labels.instance }} down"
      description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."

编辑告警配置文件

/alertmanager/alertmanager.yml

global:
  resolve_timeout: 5m
  smtp_smarthost: 'xxx@xxx:587'
  smtp_from: 'zhaoysz@xxx'
  smtp_auth_username: 'xxx@xxx'
  smtp_auth_password: 'xxxx'
  smtp_require_tls: true
route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'test-mails'
receivers:
- name: 'test-mails'
  email_configs:
  - to: 'xxxxxx@qq.com'

一键启动 docker-compose的 docker-compose.yml

version: '3.8'

services:
  prometheus:
    image: prom/prometheus
    ports:
      - 9090:9090
    volumes:
      - /prometheus/:/etc/prometheus/
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.external-url=http://prometheus:9090/'
      - '--web.enable-lifecycle'
    networks:
      - monitor_net
    restart: always

  alertmanager:
    image: prom/alertmanager
    volumes:
      - /alertmanager/:/etc/alertmanager/
      - alertmanager_data:/alertmanager
    ports:
      - 9093:9093
    command:
      - '--config.file=/etc/alertmanager/alertmanager.yml'
      - '--storage.path=/alertmanager'
    networks:
      - monitor_net
    restart: always

  grafana:
    image: grafana/grafana
    ports:
      - 3000:3000
    volumes:
      - /grafana/:/etc/grafana/provisioning/
      - grafana_data:/var/lib/grafana
    environment:
      - GF_INSTALL_PLUGINS=camptocamp-prometheus-alertmanager-datasource
    depends_on:
      - prometheus
      - alertmanager
    networks:
      - monitor_net
    restart: always

volumes:
  prometheus_data: {}
  grafana_data: {}
  alertmanager_data: {}

networks:
  monitor_net:
    driver: bridge

启动composer

docker-compose -f docker-compose.yml up -d

一些Prometheus好用的表达式:

Prometheus 针对 JVM 应用的查询表达式主要依赖JMX Exporter(或 Spring Boot Actuator 集成的 Prometheus 端点)暴露的 JVM 监控指标。以下是 JVM 核心维度的常用查询表达式,涵盖内存、GC、线程、类加载、CPU 等关键指标,同时附带指标含义和使用场景说明。

一、JVM 内存指标查询

JVM 内存分为堆内存、非堆内存,以及堆内的 Eden、Survivor、老年代等区域,是监控的核心维度。

1. 堆内存使用情况
表达式 含义 场景
jvm_memory_used_bytes{area="heap"} 堆内存已使用字节数 实时查看堆内存使用量
jvm_memory_max_bytes{area="heap"} 堆内存最大可用字节数 堆内存总容量
jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} * 100 堆内存使用率(百分比) 监控堆内存使用率是否超过阈值(如 80%)
jvm_memory_used_bytes{area="heap", pool="Eden Space"} Eden 区已使用字节数 分析新生代内存分配速度
jvm_memory_used_bytes{area="heap", pool="Old Gen"} 老年代已使用字节数 监控老年代内存是否持续上涨(可能内存泄漏)
jvm_memory_used_bytes{area="heap", pool="Survivor Space"} Survivor 区已使用字节数 分析新生代垃圾回收效率
2. 非堆内存使用情况

非堆内存主要包括方法区(Metaspace)、直接内存等:

表达式 含义 场景
jvm_memory_used_bytes{area="nonheap"} 非堆内存已使用字节数 实时查看非堆内存使用量
jvm_memory_used_bytes{area="nonheap", pool="Metaspace"} 元空间已使用字节数 监控类元数据内存占用(避免元空间溢出)
jvm_memory_used_bytes{area="nonheap", pool="Code Cache"} 代码缓存已使用字节数 分析 JIT 编译代码的内存占用
jvm_memory_used_bytes{area="nonheap", pool="Direct Memory"} 直接内存已使用字节数 监控 NIO 直接内存使用(避免直接内存溢出)

二、GC(垃圾回收)指标查询

GC 指标反映垃圾回收的频率、耗时,是判断 JVM 性能的关键。

1. GC 次数统计
表达式 含义 场景
increase(jvm_gc_collection_count{gc="Young Generation"}[5m]) 5 分钟内新生代 GC(YGC)次数 监控 YGC 频率是否过高(如每秒多次)
increase(jvm_gc_collection_count{gc="Old Generation"}[5m]) 5 分钟内老年代 GC(FGC)次数 FGC 次数应尽可能少,频繁 FGC 需排查内存泄漏
jvm_gc_collection_count 累计 GC 次数(按代划分) 查看 GC 总次数趋势
2. GC 耗时统计
表达式 含义 场景
increase(jvm_gc_collection_seconds_sum{gc="Young Generation"}[5m]) 5 分钟内 YGC 总耗时(秒) 计算 YGC 平均耗时
increase(jvm_gc_collection_seconds_sum{gc="Old Generation"}[5m]) 5 分钟内 FGC 总耗时(秒) FGC 耗时过长会导致应用停顿(STW),需优化
increase(jvm_gc_collection_seconds_sum{gc="Young Generation"}[5m]) / increase(jvm_gc_collection_count{gc="Young Generation"}[5m]) YGC 平均耗时(秒 / 次) 评估新生代 GC 效率
increase(jvm_gc_collection_seconds_sum{gc="Old Generation"}[5m]) / increase(jvm_gc_collection_count{gc="Old Generation"}[5m]) FGC 平均耗时(秒 / 次) FGC 平均耗时超过 1 秒需警惕

三、JVM 线程指标查询

线程数反映应用的并发能力,线程死锁、阻塞会导致性能问题。

表达式 含义 场景
jvm_threads_current 当前活跃线程数 监控线程数是否超过阈值
jvm_threads_daemon 守护线程数 辅助分析线程模型
jvm_threads_peak 线程数峰值 对比当前线程数,判断是否有线程泄露
jvm_threads_blocked_count 线程阻塞次数 监控线程阻塞频率,排查锁竞争
increase(jvm_threads_blocked_count[5m]) 5 分钟内线程阻塞次数 分析锁竞争是否严重
jvm_threads_deadlocked 死锁线程数 检测是否存在线程死锁(大于 0 则告警)
jvm_threads_deadlocked_monitor 持有监视器的死锁线程数 更细粒度的死锁检测

四、类加载指标查询

类加载数反映应用的类加载情况,频繁类加载可能导致性能问题。

表达式 含义 场景
jvm_classes_loaded 当前已加载的类数量 监控类加载总数
jvm_classes_loaded_total 累计加载的类数量 分析类加载趋势
jvm_classes_unloaded_total 累计卸载的类数量 类卸载频繁可能是热部署或类加载器泄漏

五、CPU 与系统指标查询

JVM 进程的 CPU 使用率、文件描述符等指标反映应用对系统资源的占用。

表达式 含义 场景
process_cpu_usage * 100 JVM 进程 CPU 使用率(百分比) 监控 CPU 占用是否过高
process_cpu_seconds_total JVM 进程累计 CPU 耗时(秒) 分析 CPU 耗时趋势
rate(process_cpu_seconds_total[5m]) * 100 5 分钟内 JVM 进程平均 CPU 使用率 更平滑的 CPU 使用率监控
process_open_fds 进程打开的文件描述符数量 监控是否超过系统限制(process_max_fds
process_open_fds / process_max_fds * 100 文件描述符使用率 避免文件描述符耗尽
process_start_time_seconds JVM 进程启动时间(时间戳) 计算进程运行时长:time() - process_start_time_seconds

六、JVM 堆外内存(直接内存)查询

直接内存由 NIO 使用,不属于堆内存,需单独监控:

# 直接内存已使用字节数
jvm_memory_used_bytes{pool="Direct Memory"}

# 直接内存使用率
jvm_memory_used_bytes{pool="Direct Memory"} / jvm_memory_max_bytes{pool="Direct Memory"} * 100

七、进阶查询与告警规则示例

1. 堆内存使用率告警(超过 85% 告警)
jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} * 100 > 85
2. 5 分钟内 FGC 次数超过 3 次告警
increase(jvm_gc_collection_count{gc="Old Generation"}[5m]) > 3
3. 线程死锁告警
jvm_threads_deadlocked > 0 or jvm_threads_deadlocked_monitor > 0
4. YGC 平均耗时超过 50ms 告警
(increase(jvm_gc_collection_seconds_sum{gc="Young Generation"}[5m]) / increase(jvm_gc_collection_count{gc="Young Generation"}[5m])) * 1000 > 50

八、注意事项

  1. 指标标签差异:不同 JMX Exporter 配置或 JVM 版本(如 HotSpot、OpenJ9)的指标标签(如 gc 名称、pool 名称)可能略有差异,需根据实际暴露的指标调整。
  2. 时间范围选择:使用 increaserate 函数时,时间范围需根据指标采集频率调整(如采集频率为 15s,时间范围建议设为 1m 或 5m)。
  3. 单位转换:Prometheus 指标默认以字节为单位,可通过 / 1024 / 1024 转换为 MB,/ 1024 / 1024 / 1024 转换为 GB(如 jvm_memory_used_bytes{area="heap"} / 1024 / 1024)。

通过以上查询表达式,可全面监控 JVM 应用的运行状态,及时发现内存泄漏、GC 频繁、线程死锁等问题。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐