Web18-Java Web监控:使用Prometheus与Grafana

Java Web监控:使用Prometheus与Grafana

在Java Web应用的全生命周期中,监控系统扮演着“健康管家”的角色。随着应用规模扩大和分布式架构普及,传统的日志打印和手动排查已无法满足需求——开发者需要实时掌握系统性能瓶颈、资源使用情况和业务指标波动。Prometheus与Grafana的组合已成为云原生时代监控的事实标准,能够实现指标采集、存储、可视化与告警的全流程管理。

本文将系统讲解如何基于Prometheus与Grafana构建Java Web应用的监控体系,从环境搭建、指标埋点、数据采集到可视化 dashboard 设计,覆盖从基础到进阶的实战技巧,附详细代码示例和配置说明,帮助开发者从零搭建企业级监控平台。

一、监控系统的核心价值与技术选型

监控是保障Java Web应用稳定运行的基石。一套完善的监控系统能在问题爆发前预警、在故障发生时快速定位根因、在优化时提供数据支撑。

1. Java Web监控的核心需求

Java Web应用的监控需覆盖“基础设施-应用性能-业务指标”三个维度,核心需求包括:

  • 实时性:关键指标(如CPU使用率、请求延迟)需秒级更新,确保问题及时发现;
  • 全面性:覆盖服务器资源(CPU/内存/磁盘)、JVM状态(GC/堆内存)、应用性能(接口响应时间/错误率)、业务指标(订单量/支付成功率);
  • 可追溯性:指标数据需长期存储,支持历史对比分析(如“今日峰值与上周同期对比”);
  • 可视化:通过图表直观展示指标趋势,替代枯燥的数字罗列;
  • 告警能力:当指标超过阈值(如错误率>5%)时,通过邮件、钉钉等渠道自动通知相关人员。

典型痛点:某电商平台在大促期间突然出现订单支付失败,因缺乏实时监控,运维人员花3小时才定位到“数据库连接池耗尽”的问题,导致直接损失超10万元。

2. 技术选型:Prometheus与Grafana的组合优势

在众多监控工具中,Prometheus与Grafana的组合脱颖而出,成为Java Web监控的首选方案。二者的核心优势如下:

工具角色核心优势
Prometheus指标采集与存储时序数据模型优化、强大的PromQL查询语言、分布式部署支持、原生告警功能
Grafana可视化与 dashboard丰富的图表类型(折线图/柱状图/热力图等)、拖拽式 dashboard 设计、多数据源支持、告警集成

技术栈优势:Prometheus负责从Java应用和服务器中采集指标并存储,通过PromQL实现灵活查询;Grafana连接Prometheus数据源,将指标转化为直观的可视化图表,二者协同形成“采集-存储-查询-可视化-告警”的完整闭环。

3. 监控体系的核心组件

一套完整的Java Web监控体系需包含以下组件:

  • 指标埋点工具:在Java应用中嵌入指标采集逻辑,如Micrometer(Java生态的指标门面);
  • 暴露器:将应用指标通过HTTP接口暴露,供Prometheus采集(如Prometheus Java Client);
  • Prometheus Server:负责定时采集、存储指标数据,提供PromQL查询接口;
  • Grafana:连接Prometheus,创建可视化 dashboard;
  • 告警管理器:Prometheus Alertmanager负责告警聚合、路由与分发;
  • ** exporters**:采集非应用指标(如服务器资源、数据库性能),如Node Exporter(服务器监控)、MySQL Exporter(数据库监控)。

工作流程

Java应用 → Micrometer埋点 → Prometheus Client暴露指标 → Prometheus Server采集存储 → Grafana可视化 → Alertmanager告警

二、环境搭建:Prometheus与Grafana基础部署

在进行Java应用集成前,需先完成Prometheus与Grafana的基础部署。推荐使用Docker快速搭建环境,降低配置复杂度。

1. 环境准备

  • 操作系统:Linux(推荐Ubuntu 20.04+或CentOS 7+)、Windows 10+(WSL2)或macOS;
  • 依赖软件:Docker 20.10+、Docker Compose 2.0+;
  • 硬件要求:至少2GB内存(Prometheus和Grafana本身消耗较低,主要取决于监控数据量)。

2. Docker Compose部署Prometheus与Grafana

使用Docker Compose可一键启动Prometheus、Grafana和Node Exporter(用于服务器监控),配置如下:

(1)创建目录结构
mkdir -p prometheus-grafana/{prometheus, grafana, data/prometheus, data/grafana}
cd prometheus-grafana
(2)编写Prometheus配置文件

创建prometheus/prometheus.yml

global:
  scrape_interval: 15s  # 全局采集间隔(默认15秒)
  evaluation_interval: 15s  # 告警规则评估间隔

# 告警规则文件配置
rule_files:
  - "alert_rules.yml"  # 后续会创建告警规则

# 采集目标配置
scrape_configs:
  # 监控Prometheus自身
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

  # 监控Grafana
  - job_name: "grafana"
    static_configs:
      - targets: ["grafana:3000"]

  # 监控服务器资源(Node Exporter)
  - job_name: "node"
    static_configs:
      - targets: ["node-exporter:9100"]

  # 监控Java应用(后续会添加应用地址)
  - job_name: "java-web-app"
    metrics_path: "/actuator/prometheus"  # Spring Boot应用的指标暴露路径
    static_configs:
      - targets: ["host.docker.internal:8080"]  # 本地Java应用地址(Windows/macOS)
        # 若为Linux,替换为实际IP:- targets: ["192.168.1.100:8080"]
(3)编写告警规则文件

创建prometheus/alert_rules.yml,定义基础告警规则:

groups:
  - name: java-web-app-alerts
    rules:
      # 应用不可用告警
      - alert: AppDown
        expr: up{job="java-web-app"} == 0
        for: 1m  # 持续1分钟符合条件才告警
        labels:
          severity: critical  # 告警级别
        annotations:
          summary: "Java应用不可用"
          description: "应用{{ $labels.instance }}已下线超过1分钟"

      # 高错误率告警
      - alert: HighErrorRate
        expr: sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_count[5m])) > 0.05
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "应用错误率过高"
          description: "过去5分钟错误率{{ $value | humanizePercentage }},超过5%阈值"

      # JVM堆内存使用率过高
      - alert: HighJvmHeapUsage
        expr: jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} > 0.8
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "JVM堆内存使用率过高"
          description: "堆内存使用率{{ $value | humanizePercentage }},超过80%阈值"
(4)编写Docker Compose配置

创建docker-compose.yml

version: '3.8'

services:
  # Prometheus服务
  prometheus:
    image: prom/prometheus:v2.45.0
    container_name: java-monitor-prometheus
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - ./prometheus/alert_rules.yml:/etc/prometheus/alert_rules.yml
      - ./data/prometheus:/prometheus  # 数据持久化
    ports:
      - "9090:9090"
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--web.enable-lifecycle'  # 支持热加载配置
    restart: always
    networks:
      - monitor-network

  # Grafana服务
  grafana:
    image: grafana/grafana:9.5.2
    container_name: java-monitor-grafana
    volumes:
      - ./data/grafana:/var/lib/grafana  # 数据持久化
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin  # 初始密码
      - GF_USERS_ALLOW_SIGN_UP=false  # 禁用注册
    restart: always
    depends_on:
      - prometheus
    networks:
      - monitor-network

  # Node Exporter:采集服务器资源指标
  node-exporter:
    image: prom/node-exporter:v1.6.1
    container_name: java-monitor-node-exporter
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - "9100:9100"
    restart: always
    networks:
      - monitor-network

  # Alertmanager:处理告警
  alertmanager:
    image: prom/alertmanager:v0.25.0
    container_name: java-monitor-alertmanager
    volumes:
      - ./prometheus/alertmanager.yml:/etc/alertmanager/alertmanager.yml
      - ./data/alertmanager:/data
    ports:
      - "9093:9093"
    command:
      - '--config.file=/etc/alertmanager/alertmanager.yml'
      - '--storage.path=/data'
    restart: always
    depends_on:
      - prometheus
    networks:
      - monitor-network

networks:
  monitor-network:
    driver: bridge
(5)编写Alertmanager配置

创建prometheus/alertmanager.yml,配置告警接收方式(以邮件为例):

global:
  resolve_timeout: 5m  # 告警解决后等待5分钟确认

route:
  group_by: ['alertname', 'job']  # 按告警名称和job分组
  group_wait: 10s  # 组内第一个告警等待10秒,可能合并同类告警
  group_interval: 10s  # 组内告警间隔10秒发送
  repeat_interval: 1h  # 重复告警间隔1小时
  receiver: 'email-notifications'  # 默认接收者

receivers:
- name: 'email-notifications'
  email_configs:
  - to: 'admin@example.com'  # 接收告警的邮箱
    from: 'prometheus@example.com'
    smarthost: 'smtp.example.com:587'  # SMTP服务器地址和端口
    auth_username: 'prometheus@example.com'
    auth_password: 'your-email-password'  # 邮箱密码或授权码
    auth_identity: 'prometheus@example.com'
    send_resolved: true  # 告警解决后发送恢复通知

inhibit_rules:  # 抑制规则(高优先级告警触发时,抑制低优先级告警)
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'job', 'instance']
(6)启动服务
# 启动所有服务
docker-compose up -d

# 查看启动状态
docker-compose ps

服务启动后,可通过以下地址访问:

  • Prometheus:http://localhost:9090(Web UI)
  • Grafana:http://localhost:3000(默认账号密码:admin/admin)
  • Node Exporter:http://localhost:9100/metrics(服务器指标)
  • Alertmanager:http://localhost:9093(告警管理)

3. 验证基础监控是否正常

(1)验证Prometheus采集状态

访问Prometheus Web UI(http://localhost:9090),进入“Status → Targets”页面,确认所有job的“State”均为“UP”:

  • prometheus:Prometheus自身监控
  • grafana:Grafana监控
  • node:Node Exporter监控(服务器资源)
(2)验证指标查询功能

在Prometheus的“Graph”页面,输入以下PromQL查询指标,验证是否有数据返回:

  • 服务器CPU使用率:100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
  • Prometheus自身内存使用:prometheus_tsdb_head_series(当前存储的时间序列数)
(3)验证Grafana基础功能

访问Grafana(http://localhost:3000),首次登录需修改密码(建议改为grafana123方便测试)。进入“Home”页面,确认界面正常加载。

三、Java Web应用集成Prometheus:指标埋点与暴露

Java Web应用需通过埋点暴露关键指标(如接口响应时间、JVM状态),供Prometheus采集。Spring Boot应用可通过Micrometer快速集成,非Spring应用可使用Prometheus Java Client。

1. Spring Boot应用集成(推荐)

Spring Boot 2.x+默认集成Micrometer作为指标门面,可通过spring-boot-starter-actuator快速暴露指标。

(1)添加依赖

pom.xml中添加以下依赖:

<!-- Spring Boot Actuator:提供监控端点 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- Micrometer Prometheus注册表:将指标转换为Prometheus格式 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- Spring Boot Web:确保应用是Web类型 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
(2)配置application.yml

src/main/resources/application.yml中配置Actuator与Prometheus:

spring:
  application:
    name: java-web-app  # 应用名称,将作为指标标签

# Actuator配置
management:
  endpoints:
    web:
      exposure:
        include: health,prometheus,info  # 暴露的端点,必须包含prometheus
      base-path: /actuator  # 端点基础路径(默认/actuator)
  metrics:
    export:
      prometheus:
        enabled: true  # 启用Prometheus导出
    tags:
      application: ${spring.application.name}  # 所有指标添加application标签
  endpoint:
    health:
      show-details: always  # 健康检查显示详细信息
    metrics:
      enabled: true
    prometheus:
      enabled: true
(3)启动Spring Boot应用

创建简单的Spring Boot启动类和控制器:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class JavaWebAppApplication {

    public static void main(String[] args) {
        SpringApplication.run(JavaWebAppApplication.class, args);
    }

    // 测试接口:模拟用户查询
    @GetMapping("/user/{id}")
    public String getUser(@PathVariable Long id) {
        // 模拟处理时间(随机延迟0-200ms)
        try {
            Thread.sleep((long) (Math.random() * 200));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return "User: " + id;
    }

    // 测试接口:模拟订单创建
    @GetMapping("/order")
    public String createOrder() {
        // 模拟偶尔失败(10%概率)
        if (Math.random() < 0.1) {
            throw new RuntimeException("创建订单失败");
        }
        return "Order created";
    }
}

启动应用后,访问http://localhost:8080/actuator/prometheus,应能看到暴露的Prometheus格式指标,例如:

# HELP http_server_requests_seconds Duration of HTTP server requests
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{application="java-web-app",exception="None",method="GET",outcome="SUCCESS",status="200",uri="/user/{id}",} 10.0
http_server_requests_seconds_sum{application="java-web-app",exception="None",method="GET",outcome="SUCCESS",status="200",uri="/user/{id}",} 1.234
# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{application="java-web-app",area="heap",} 1.23456789E8
(4)验证Prometheus采集Java应用指标

回到Prometheus Web UI(http://localhost:9090),进入“Status → Targets”,确认java-web-app的State为“UP”。在“Graph”页面查询Java应用指标:

  • 接口请求数:http_server_requests_seconds_count{application="java-web-app"}
  • JVM堆内存使用:jvm_memory_used_bytes{application="java-web-app", area="heap"}

2. 自定义指标埋点:业务与性能指标

除了Actuator自动暴露的指标,还需针对业务场景和关键流程自定义指标,如订单量、支付成功率、自定义耗时等。

(1)Micrometer核心指标类型

Micrometer支持多种指标类型,覆盖不同监控场景:

指标类型作用适用场景
Counter单调递增的计数器接口请求数、订单创建数、错误数
Gauge可增可减的仪表盘在线用户数、队列长度、缓存命中率
Timer记录耗时与频率接口响应时间、方法执行时间
Summary记录分布统计(均值、分位数)延迟分布、数据大小分布
Histogram记录直方图分布(需配合Prometheus的histogram_quantile)精确分位数计算(如P95延迟)
(2)自定义指标实战示例

创建一个指标服务类,封装常用自定义指标:

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.binder.MeterBinder;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class CustomMetrics implements MeterBinder {

    // 订单相关指标
    private Counter orderCreateCounter;  // 订单创建计数器
    private Counter orderPayCounter;     // 订单支付计数器
    private Timer orderProcessTimer;     // 订单处理计时器

    // 在线用户数指标
    private final AtomicInteger onlineUserCount = new AtomicInteger(0);

    // 商品库存指标(模拟)
    private final Map<String, AtomicInteger> productStock = new HashMap<>();

    @PostConstruct
    public void init() {
        // 初始化商品库存(模拟数据)
        productStock.put("product-1", new AtomicInteger(100));
        productStock.put("product-2", new AtomicInteger(50));
    }

    // 绑定指标到注册中心
    @Override
    public void bindTo(io.micrometer.core.instrument.MeterRegistry registry) {
        // 1. 订单创建计数器
        orderCreateCounter = Counter.builder("business.order.create.count")
                .description("订单创建总数")
                .tag("app", "java-web-app")
                .register(registry);

        // 2. 订单支付计数器
        orderPayCounter = Counter.builder("business.order.pay.count")
                .description("订单支付总数")
                .tag("app", "java-web-app")
                .register(registry);

        // 3. 订单处理计时器
        orderProcessTimer = Timer.builder("business.order.process.time")
                .description("订单处理耗时")
                .tag("app", "java-web-app")
                .register(registry);

        // 4. 在线用户数Gauge
        Gauge.builder("business.user.online.count", onlineUserCount, AtomicInteger::get)
                .description("当前在线用户数")
                .tag("app", "java-web-app")
                .register(registry);

        // 5. 商品库存Gauge(动态标签)
        for (Map.Entry<String, AtomicInteger> entry : productStock.entrySet()) {
            String productId = entry.getKey();
            AtomicInteger stock = entry.getValue();
            Gauge.builder("business.product.stock.count", stock, AtomicInteger::get)
                    .description("商品库存数量")
                    .tag("app", "java-web-app")
                    .tag("product_id", productId)
                    .register(registry);
        }
    }

    // 订单创建计数
    public void incrementOrderCreate() {
        orderCreateCounter.increment();
    }

    // 订单支付计数
    public void incrementOrderPay() {
        orderPayCounter.increment();
    }

    // 记录订单处理时间(函数式用法)
    public <T> T recordOrderProcessTime(Supplier<T> task) {
        return orderProcessTimer.record(task);
    }

    // 在线用户数+1
    public void incrementOnlineUser() {
        onlineUserCount.incrementAndGet();
    }

    // 在线用户数-1
    public void decrementOnlineUser() {
        onlineUserCount.decrementAndGet();
    }

    // 减少商品库存
    public void decreaseStock(String productId, int amount) {
        AtomicInteger stock = productStock.get(productId);
        if (stock != null) {
            stock.addAndGet(-amount);
        }
    }
}
(3)在业务代码中使用自定义指标

修改控制器,集成自定义指标:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class BusinessController {

    @Autowired
    private CustomMetrics customMetrics;

    // 订单创建接口
    @PostMapping("/order")
    public String createOrder(@RequestParam String productId) {
        // 记录订单创建
        customMetrics.incrementOrderCreate();

        // 记录订单处理时间
        return customMetrics.recordOrderProcessTime(() -> {
            // 模拟订单处理(50-300ms)
            try {
                Thread.sleep(50 + (long) (Math.random() * 250));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            // 减少库存
            customMetrics.decreaseStock(productId, 1);
            return "Order created for product: " + productId;
        });
    }

    // 订单支付接口
    @PostMapping("/order/{id}/pay")
    public String payOrder(@PathVariable Long id) {
        // 模拟支付处理
        try {
            Thread.sleep((long) (Math.random() * 100));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        // 记录支付成功
        customMetrics.incrementOrderPay();
        return "Order " + id + " paid";
    }

    // 用户登录接口(更新在线人数)
    @PostMapping("/user/login")
    public String login() {
        customMetrics.incrementOnlineUser();
        return "Login success";
    }

    // 用户登出接口(更新在线人数)
    @PostMapping("/user/logout")
    public String logout() {
        customMetrics.decrementOnlineUser();
        return "Logout success";
    }
}

启动应用后,调用几次接口(如POST /order?productId=product-1POST /user/login),再访问http://localhost:8080/actuator/prometheus,应能看到自定义指标:

# HELP business_order_create_count 订单创建总数
# TYPE business_order_create_count counter
business_order_create_count{app="java-web-app",} 5.0
# HELP business_user_online_count 当前在线用户数
# TYPE business_user_online_count gauge
business_user_online_count{app="java-web-app",} 3.0
# HELP business_product_stock_count 商品库存数量
# TYPE business_product_stock_count gauge
business_product_stock_count{app="java-web-app",product_id="product-1",} 95.0

3. 非Spring Boot应用集成(原生Java)

非Spring Boot应用(如传统Servlet应用)可通过Prometheus Java Client直接暴露指标。

(1)添加依赖
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient</artifactId>
    <version>0.16.0</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient_servlet</artifactId>
    <version>0.16.0</version>
</dependency>
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient_hotspot</artifactId>  <!-- JVM指标 -->
    <version>0.16.0</version>
</dependency>
(2)初始化指标与Servlet

创建指标注册类:

import io.prometheus.client.Counter;
import io.prometheus.client.Gauge;
import io.prometheus.client.Histogram;
import io.prometheus.client.exporter.MetricsServlet;
import io.prometheus.client.hotspot.DefaultExports;

import javax.servlet.annotation.WebServlet;

// 注册Prometheus指标Servlet
@WebServlet("/metrics")
public class PrometheusMetricsServlet extends MetricsServlet {
    static {
        // 注册JVM指标
        DefaultExports.initialize();
    }

    // 接口请求计数器
    public static final Counter requestCounter = Counter.build()
            .name("http_requests_total")
            .help("Total HTTP requests")
            .labelNames("method", "path", "status")
            .register();

    // 接口响应时间直方图
    public static final Histogram requestDuration = Histogram.build()
            .name("http_request_duration_seconds")
            .help("HTTP request duration in seconds")
            .labelNames("method", "path")
            .register();

    // 在线用户数
    public static final Gauge onlineUsers = Gauge.build()
            .name("online_users_total")
            .help("Current online users")
            .register();
}
(3)在Servlet中使用指标
import io.prometheus.client.Histogram.Timer;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/user")
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String path = "/user";
        String method = "GET";
        Timer timer = PrometheusMetricsServlet.requestDuration.labels(method, path).startTimer();

        try {
            // 模拟处理逻辑
            Thread.sleep((long) (Math.random() * 200));
            resp.getWriter().println("User info");
            PrometheusMetricsServlet.requestCounter.labels(method, path, "200").inc();
        } catch (Exception e) {
            resp.sendError(500, "Error");
            PrometheusMetricsServlet.requestCounter.labels(method, path, "500").inc();
        } finally {
            timer.observeDuration(); // 记录耗时
        }
    }
}

部署应用后,访问http://localhost:8080/metrics即可获取指标,Prometheus配置类似Spring Boot应用。

四、Prometheus核心配置与PromQL查询

Prometheus的强大之处在于灵活的配置和强大的查询语言PromQL。掌握这些技能是实现精准监控的基础。

1. Prometheus核心配置详解

Prometheus的配置文件(prometheus.yml)包含全局配置、告警规则和采集目标,以下是关键参数详解:

(1)全局配置(global)
global:
  scrape_interval: 15s  # 所有采集目标的默认采集间隔
  evaluation_interval: 15s  # 告警规则的评估间隔
  scrape_timeout: 10s  # 单个采集请求的超时时间
  external_labels:  # 附加到所有时序数据的标签(用于联邦部署)
    monitor: "java-web-monitor"
(2)采集配置(scrape_configs)

每个job_name定义一组采集目标:

scrape_configs:
  - job_name: "java-web-app"  # 任务名称(会作为标签添加到指标)
    scrape_interval: 5s  # 覆盖全局采集间隔(高频指标可设为5s)
    metrics_path: "/actuator/prometheus"  # 指标路径
    scheme: "http"  # 协议(http/https)
    basic_auth:  # 若应用有认证,配置账号密码
      username: "admin"
      password: "secret"
    static_configs:  # 静态配置采集目标
      - targets: ["192.168.1.100:8080", "192.168.1.101:8080"]  # 多个实例
        labels:  # 附加标签(如环境、机房)
          env: "prod"
         机房: "北京"
    relabel_configs:  # 标签重写规则(高级功能)
      - source_labels: [__address__]  # 源标签(__address__是内置标签)
        regex: "(.*):8080"  # 正则匹配
        target_label: instance  # 目标标签
        replacement: "${1}"  # 替换为IP(去除端口)
(3)服务发现配置(动态目标)

分布式环境中,静态配置难以维护,可使用服务发现(如Kubernetes、Consul):

# Kubernetes服务发现示例
- job_name: "k8s-java-app"
  kubernetes_sd_configs:
    - role: pod  # 发现Pod
  relabel_configs:
    # 仅采集带有"app=java-web-app"标签的Pod
    - source_labels: [__meta_kubernetes_pod_label_app]
      action: keep
      regex: java-web-app
    # 从Pod注解中获取指标路径
    - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)

2. PromQL核心语法与常用查询

PromQL(Prometheus Query Language)是用于查询指标数据的函数式语言,支持聚合、过滤和数学运算。

(1)基础查询
  • 直接查询指标:http_server_requests_seconds_count(返回该指标的所有时间序列)
  • 按标签过滤:http_server_requests_seconds_count{status="200", uri="/user/{id}"}(只返回状态200且路径为/user/{id}的序列)
  • 范围查询:http_server_requests_seconds_count{uri="/order"}[5m](返回过去5分钟的所有样本)
(2)常用函数
函数作用示例
rate()计算每秒增长率(适合计数器)rate(http_requests_total[5m])(5分钟窗口内的每秒请求数)
irate()计算瞬时增长率(更灵敏,适合高频变化指标)irate(node_cpu_seconds_total{mode!="idle"}[5m])
sum()按标签聚合求和sum(rate(http_requests_total[5m])) by (status)(按状态聚合请求率)
avg()计算平均值avg(rate(http_requests_seconds_sum[5m]) / rate(http_requests_seconds_count[5m])) by (uri)(按路径计算平均响应时间)
topk()取前N个值topk(3, sum(rate(http_requests_total[5m])) by (uri))(请求量前三的接口)
histogram_quantile()计算分位数histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, uri))(各接口的P95延迟)
(3)Java Web常用指标查询
监控目标PromQL查询含义
接口QPSsum(rate(http_server_requests_seconds_count[5m])) by (uri)各接口5分钟内的每秒请求数
接口错误率sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) by (uri) / sum(rate(http_server_requests_seconds_count[5m])) by (uri)各接口的5xx错误率
平均响应时间sum(rate(http_server_requests_seconds_sum[5m])) by (uri) / sum(rate(http_server_requests_seconds_count[5m])) by (uri)各接口的平均响应时间(秒)
P95响应时间histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le, uri))95%的请求响应时间不超过该值
JVM堆内存使用率jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} * 100堆内存使用率(百分比)
GC次数sum(rate(jvm_gc_pause_seconds_count[5m])) by (gc)各GC类型的每秒发生次数
在线用户数business_user_online_count{app="java-web-app"}当前在线用户数
订单创建速率rate(business_order_create_count[5m])每秒订单创建数

3. 告警规则配置进阶

Prometheus的告警规则定义在alert_rules.yml中,除基础阈值告警外,还支持复杂逻辑告警。

(1)多条件组合告警
# 接口响应时间与错误率联合告警
- alert: CriticalApiIssue
  expr: |
    (sum(rate(http_server_requests_seconds_sum[5m]) by (uri) / rate(http_server_requests_seconds_count[5m]) by (uri)) > 0.5)
    and
    (sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m]) by (uri)) > 1)
  for: 2m
  labels:
    severity: critical
  annotations:
    summary: "接口{{ $labels.uri }}异常"
    description: "接口{{ $labels.uri }}响应时间>500ms且错误率>1次/秒,持续2分钟"
(2)环比异常告警
# 订单量突降告警(与上周同期相比下降50%以上)
- alert: OrderVolumeDrop
  expr: |
    rate(business_order_create_count[30m]) < 
    (rate(business_order_create_count[30m] offset 1w) * 0.5)
  for: 1h
  labels:
    severity: warning
  annotations:
    summary: "订单量异常下降"
    description: "当前订单量{{ $value | humanize }}/秒,较上周同期下降超过50%"
(3)告警抑制与分组

通过Alertmanager的配置实现告警聚合,避免告警风暴:

  • 分组(group_by):将同类型告警合并发送(如同一应用的多个接口错误);
  • 抑制(inhibit_rules):高优先级告警触发时,抑制低优先级告警(如应用宕机时,不再发送接口错误告警);
  • 路由(route):按标签将告警发送到不同接收者(如生产环境告警给运维,测试环境告警给开发)。

五、Grafana可视化:从数据源到Dashboard

Grafana是监控数据的“可视化引擎”,能将Prometheus的时序数据转化为直观的图表和dashboard。以下是从零构建Java Web监控dashboard的详细步骤。

1. 添加Prometheus数据源

首次使用Grafana需先配置数据源:

  1. 登录Grafana(http://localhost:3000),进入左侧菜单 Configuration → Data Sources
  2. 点击“Add data source”,选择“Prometheus”;
  3. 在配置页面:
    • Name:输入“Prometheus-Java-Monitor”;
    • URL:输入Prometheus地址(http://prometheus:9090,Docker内部通信);
    • 其他配置保持默认,点击“Save & test”,显示“Data source is working”即配置成功。

2. 创建基础监控Dashboard

Dashboard由多个面板(Panel)组成,每个面板对应一个或多个指标的可视化图表。

(1)创建JVM监控面板
  1. 进入 Dashboards → New dashboard → Add visualization

  2. 选择数据源“Prometheus-Java-Monitor”;

  3. 配置面板:

    • Panel title:输入“JVM堆内存使用率”;
    • Query:输入PromQL jvm_memory_used_bytes{application="java-web-app", area="heap"} / jvm_memory_max_bytes{application="java-web-app", area="heap"} * 100
    • Legend:设置为{{ instance }}(按实例显示图例);
    • Visualization:选择“Gauge”(仪表盘),设置阈值(如80%为警告,90%为错误);
    • 点击右上角“Apply”保存面板。
  4. 新增JVM非堆内存面板,类似配置,指标改为area="nonheap"

(2)创建接口性能面板
  1. 点击Dashboard右上角“Add” → “Visualization”;

  2. 配置“接口QPS”面板:

    • Querysum(rate(http_server_requests_seconds_count{application="java-web-app"}[5m])) by (uri)
    • Visualization:选择“Graph”(折线图);
    • X-Axis:设置为“Time”;
    • Y-Axis:标题“QPS”;
    • Legend{{ uri }}
  3. 配置“接口平均响应时间”面板:

    • Querysum(rate(http_server_requests_seconds_sum{application="java-web-app"}[5m])) by (uri) / sum(rate(http_server_requests_seconds_count{application="java-web-app"}[5m])) by (uri)
    • Y-Axis:标题“平均响应时间(秒)”;
    • Unit:选择“seconds”。
  4. 配置“接口错误率”面板:

    • Querysum(rate(http_server_requests_seconds_count{application="java-web-app", status=~"5.."}[5m])) by (uri) / sum(rate(http_server_requests_seconds_count{application="java-web-app"}[5m])) by (uri) * 100
    • Y-Axis:标题“错误率(%)”;
    • Unit:选择“percent (0-100)”;
    • 设置阈值线(如5%红线)。
(3)创建业务指标面板
  1. 新增“订单创建速率”面板:

    • Queryrate(business_order_create_count{app="java-web-app"}[5m])
    • Visualization:选择“Graph”,Y轴标题“订单/秒”。
  2. 新增“在线用户数”面板:

    • Querybusiness_user_online_count{app="java-web-app"}
    • Visualization:选择“Stat”(大数字),突出显示当前值。
  3. 新增“商品库存”面板:

    • Querybusiness_product_stock_count{app="java-web-app"}
    • Visualization:选择“Table”(表格),显示product_id和库存值。

3. 导入社区Dashboard模板

Grafana社区提供大量现成的Java监控模板,可直接导入使用,节省配置时间。

(1)导入JVM监控模板
  1. 进入 Dashboards → New dashboard → Import
  2. 在“Import via grafana.com”输入模板ID:4701(Spring Boot应用监控模板);
  3. 点击“Load”,选择数据源为“Prometheus-Java-Monitor”;
  4. 点击“Import”完成导入,该模板包含JVM内存、GC、线程等全面监控图表。
(2)导入服务器监控模板
  1. 同样方法导入模板ID:1860(Node Exporter服务器监控);
  2. 选择数据源为“Prometheus-Java-Monitor”,完成导入,可监控CPU、内存、磁盘、网络等服务器指标。

4. Dashboard优化与最佳实践

(1)布局与分组
  • 按监控维度分组面板(如“JVM监控”“接口性能”“业务指标”“服务器资源”);
  • 重要指标(如错误率、内存使用率)放在顶部或左侧,优先展示;
  • 调整面板大小,避免过大或过小(关键指标可设为“Stat”大面板)。
(2)时间范围与刷新频率
  • 根据监控目标设置时间范围:实时监控用“Last 1h”,趋势分析用“Last 7d”;
  • 刷新频率:高频指标(如QPS)设为“5s”,低频指标(如内存)设为“30s”;
  • 在Dashboard设置中配置默认时间范围和刷新频率。
(3)变量与模板化

通过变量实现Dashboard动态切换(如多环境、多实例):

  1. 进入Dashboard设置 → “Variables” → “Add variable”;
  2. 配置“instance”变量:
    • Nameinstance
    • TypeQuery
    • Data source:选择Prometheus;
    • Querylabel_values(http_server_requests_seconds_count{application="java-web-app"}, instance)
    • SortAlphabetical (asc)
  3. 在面板Query中使用变量:http_server_requests_seconds_count{instance=~"$instance"},实现通过下拉框切换实例。

六、进阶监控:分布式追踪与日志关联

在分布式Java Web应用中,单一指标监控难以定位跨服务问题,需结合分布式追踪和日志关联,构建“指标-追踪-日志”三位一体的监控体系。

1. 集成分布式追踪(Spring Cloud Sleuth + Zipkin)

Spring Cloud Sleuth可生成TraceID追踪跨服务请求,与Prometheus指标结合实现全链路监控。

(1)添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
(2)配置application.yml
spring:
  sleuth:
    sampler:
      probability: 1.0  # 开发环境采样率100%,生产环境可设0.1
  zipkin:
    base-url: http://localhost:9411  # Zipkin服务器地址
(3)启动Zipkin
docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin
(4)追踪指标关联

通过MDC将TraceID添加到日志,再通过Prometheus的traceId标签关联指标与追踪:

import brave.Tracer;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class TraceIdFilter extends OncePerRequestFilter {

    @Autowired
    private Tracer tracer;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        // 将Sleuth的TraceID添加到MDC
        String traceId = tracer.currentSpan().context().traceIdString();
        MDC.put("traceId", traceId);
        try {
            filterChain.doFilter(request, response);
        } finally {
            MDC.remove("traceId");
        }
    }
}

在Grafana中添加TraceID查询链接,实现从指标到追踪的跳转。

2. 日志与指标关联

通过Logback将指标标签(如traceIduri)写入日志,再通过ELK或Grafana Loki实现日志与指标的联动查询。

(1)Logback配置添加指标标签
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [traceId=%X{traceId}] - %msg%n</pattern>
    </encoder>
</appender>
(2)集成Grafana Loki收集日志
  1. 启动Loki和Promtail(日志收集):
# docker-compose.yml中添加
services:
  loki:
    image: grafana/loki:2.8.0
    ports:
      - "3100:3100"
    volumes:
      - ./data/loki:/loki
    command: -config.file=/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:2.8.0
    volumes:
      - ./data/promtail:/var/log
      - ./promtail/config.yml:/etc/promtail/config.yml
    command: -config.file=/etc/promtail/config.yml
  1. 在Grafana中添加Loki数据源,实现日志与指标在同一dashboard展示。

七、实战案例:Java Web应用性能问题排查

结合前文知识,通过一个实际案例展示如何用Prometheus与Grafana定位Java Web应用性能问题。

1. 问题场景

某Java Web应用上线后,用户反馈“部分接口响应缓慢”,开发团队需快速定位根因。

2. 排查步骤

(1)查看关键指标dashboard
  1. 访问Grafana dashboard,发现/order接口的平均响应时间从正常的100ms突增至800ms;
  2. 错误率无明显变化(状态码200),但QPS正常(约50 req/s);
  3. JVM监控面板显示:堆内存使用率达90%,GC次数频繁(每秒Young GC 5次)。
(2)深入分析JVM指标
  1. 在Prometheus中查询GC指标:

    • Young GC次数:sum(rate(jvm_gc_pause_seconds_count{gc="YoungGC"}[5m])) by (instance) → 确认每秒5次;
    • Young GC耗时:sum(rate(jvm_gc_pause_seconds_sum{gc="YoungGC"}[5m])) by (instance) → 每次GC耗时约50ms;
    • 结论:频繁GC导致CPU资源消耗,接口响应延迟。
  2. 分析内存泄漏嫌疑:

    • 老年代内存增长:jvm_memory_used_bytes{area="heap", generation="old"} → 持续增长,无下降趋势;
    • 线程数:jvm_threads_live_threads → 正常(约50);
    • 怀疑存在内存泄漏对象。
(3)结合分布式追踪定位问题接口
  1. 在Zipkin中查询/order接口的慢请求TraceID;
  2. 发现慢请求均涉及OrderService.calculateDiscount()方法,耗时约700ms;
  3. 查看该方法代码,发现存在大对象创建未释放的问题:
// 问题代码:每次调用创建大集合,未及时回收
public double calculateDiscount(Order order) {
    List<OrderItem> items = new ArrayList<>();
    // 循环添加大量元素(10万+)
    for (int i = 0; i < order.getItemsCount(); i++) {
        items.add(new OrderItem(...)); 
    }
    // 业务逻辑处理...
    return discount; // 未清空集合,导致内存泄漏
}
(4)验证优化效果
  1. 修改代码:使用后清空集合或改用局部变量池;
  2. 上线后观察dashboard:
    • /order接口响应时间恢复至120ms;
    • Young GC次数降至每秒0.5次;
    • 堆内存使用率稳定在60%;
    • 问题解决。

八、常见问题与最佳实践

1. 常见问题排查

(1)指标不显示或采集失败?
  • 检查应用是否正常暴露指标:访问http://<host>:<port>/actuator/prometheus确认有数据;
  • 检查Prometheus Targets状态:http://localhost:9090/targets,查看是否有“DOWN”状态及错误原因(如网络不通、认证失败);
  • 检查指标名称是否正确:PromQL区分大小写,确保标签匹配(如application="java-web-app"是否正确);
  • 检查采集间隔:若指标变化频率低,需等待scrape_interval时间后才会显示。
(2)Grafana图表无数据?
  • 检查数据源配置:确认Prometheus地址正确,测试连接是否成功;
  • 检查时间范围:默认时间范围可能未包含数据,尝试选择“Last 7 days”;
  • 检查PromQL语法:在Grafana的Query编辑器中点击“Test query”,查看是否有语法错误;
  • 检查指标是否存在:在Prometheus Web UI中先验证Query是否有数据。
(3)告警不触发或未收到通知?
  • 检查Prometheus告警规则:http://localhost:9090/alerts,查看告警是否处于“FIRING”状态;
  • 检查Alertmanager配置:http://localhost:9093,确认告警是否被正确路由;
  • 检查通知渠道:如邮件告警,查看Alertmanager日志是否有发送失败(docker logs java-monitor-alertmanager);
  • 检查for参数:告警规则的for设置过长可能导致延迟触发(如for: 5m需等待5分钟)。

2. 监控最佳实践

(1)指标设计原则
  • 核心指标优先:聚焦“4个黄金信号”——延迟(Latency)、流量(Traffic)、错误率(Errors)、饱和度(Saturation);
  • 标签设计合理:关键标签(如applicationinstanceuri)保持一致,避免过多标签导致 cardinality爆炸;
  • 避免过度采集:非关键指标可降低采集频率(如30s),减少Prometheus存储压力;
  • 业务指标与技术指标结合:技术指标(JVM/CPU)反映系统健康,业务指标(订单量/支付率)反映业务健康。
(2)性能优化建议
  • Prometheus存储优化:设置--storage.tsdb.retention.time=15d(保留15天数据),避免磁盘空间不足;对高频指标使用rate()而非原始计数器;
  • 指标采样策略:生产环境分布式追踪采样率设为0.1(10%),避免性能损耗;
  • JVM指标采集优化:使用micrometer-registry-prometheuscacheMetrics功能,减少重复计算;
  • 水平扩展:当监控目标超过100个,考虑Prometheus联邦部署(Federation)或使用Thanos扩展存储。
(3)告警策略设计
  • 告警分级:按严重程度分为critical(核心业务中断)、warning(性能下降)、info(非关键提示);
  • 告警聚合:通过Alertmanager的group_by合并同类告警,避免“告警风暴”;
  • 告警抑制:高优先级告警触发时,抑制低优先级告警(如应用宕机时不告警接口错误);
  • 告警自愈:结合自动化工具(如Ansible、Kubernetes HPA),实现简单告警的自动恢复(如扩容实例、重启服务)。

九、总结

Java Web监控是保障应用稳定运行的核心手段,Prometheus与Grafana的组合提供了从指标采集到可视化的完整解决方案。通过本文的实战指南,开发者可从零搭建包含JVM监控、接口性能、业务指标和服务器资源的全方位监控体系。

核心要点包括:

  • 利用Micrometer在Java应用中埋点,通过Actuator暴露指标;
  • 配置Prometheus采集指标,使用PromQL实现灵活查询;
  • 在Grafana中创建直观的dashboard,实现指标可视化;
  • 设计合理的告警规则,通过Alertmanager及时通知异常;
  • 结合分布式追踪和日志,构建“指标-追踪-日志”联动的排查体系。

随着Java Web应用向分布式、云原生演进,监控系统的重要性将愈发凸显。掌握Prometheus与Grafana的使用技巧,不仅能提升问题排查效率,更能通过数据驱动优化应用性能,为用户提供更稳定的服务体验。建议在实际项目中持续迭代监控策略,让监控系统真正成为开发和运维的“千里眼”与“顺风耳”。

### 使用 PrometheusGrafana 实现 Java 应用程序性能监控 为了实现对 Java 应用程序的性能监控,可以采用 PrometheusGrafana 组合的方式。以下是具体的实现方法: #### 1. **引入 Spring Boot Actuator** Spring Boot Actuator 提供了许多内置端点来帮助开发者了解应用程序的状态和运行情况。通过启用 Actuator 并将其 Prometheus 整合,能够轻松获取 JVM 性能指标以及自定义业务指标。 要集成 Actuator,请在项目的 `pom.xml` 文件中添加依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> ``` 随后,在 `application.properties` 或 `application.yml` 中配置 Prometheus 支持: ```properties management.endpoints.web.exposure.include=* management.endpoint.prometheus.enabled=true management.metrics.export.prometheus.enabled=true ``` 这一步会暴露 `/actuator/prometheus` 端点以便 Prometheus 抓取数据[^3]。 --- #### 2. **设置 JMX Exporter** 对于更深入的 JVM 监控(如 GC、线程池等),可以通过 jmx_exporter 将 JVM 数据导出给 Prometheus。下载适合版本的 jmx_prometheus_javaagent.jar 后,在启动命令中加入以下参数: ```bash -javaagent:/path/to/jmx_prometheus_javaagent.jar=7070:/path/to/config.yaml ``` 其中,`config.yaml` 是一个 YAML 配置文件,用于指定哪些 MBeans 被抓取并转换成 Prometheus 格式的指标[^2]。 --- #### 3. **安装和配置 Prometheus** Prometheus 可以作为独立的服务部署或者通过 Docker Compose 方便地管理。创建一个简单的 `docker-compose.yml` 来快速搭建环境: ```yaml version: '3' services: prometheus: image: prom/prometheus:v2.38.0 ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml ``` 编辑 `prometheus.yml` 添加目标 Job 定义: ```yaml scrape_configs: - job_name: 'java-app' static_configs: - targets: ['your-java-application-host:port'] labels: instance: java-service ``` 这里的目标地址应指向之前提到的应用程序 `/actuator/prometheus` 接口所在位置[^1]。 --- #### 4. **安装和配置 Grafana** 同样利用容器化技术简化操作流程: ```yaml grafana: image: grafana/grafana:latest ports: - "3000:3000" depends_on: - prometheus ``` 登录到本地访问的 Grafana Web UI (`http://localhost:3000`) ,默认用户名密码均为 admin/admin 。完成初始化后连接已有的 Prometheus 数据源,并导入适用于 Java/Spring Boot 的预设 Dashboard ID (例如:10015)。 --- #### 5. **验证效果** 一旦上述步骤全部执行完毕,则可以在 Grafana 上直观看到 CPU 利用率、内存分配状况、垃圾回收频率等一系列重要统计图表;同时也能针对异常阈值设定告警机制从而及时发现潜在风险。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值