Spring Boot 监控实战:集成 Prometheus 与 Grafana,打造全方位监控体系
前言
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
八、注意事项
- 指标标签差异:不同 JMX Exporter 配置或 JVM 版本(如 HotSpot、OpenJ9)的指标标签(如
gc名称、pool名称)可能略有差异,需根据实际暴露的指标调整。 - 时间范围选择:使用
increase、rate函数时,时间范围需根据指标采集频率调整(如采集频率为 15s,时间范围建议设为 1m 或 5m)。 - 单位转换:Prometheus 指标默认以字节为单位,可通过
/ 1024 / 1024转换为 MB,/ 1024 / 1024 / 1024转换为 GB(如jvm_memory_used_bytes{area="heap"} / 1024 / 1024)。
通过以上查询表达式,可全面监控 JVM 应用的运行状态,及时发现内存泄漏、GC 频繁、线程死锁等问题。
更多推荐





所有评论(0)