在现代的云原生和微服务架构中,系统监控是确保服务高可用和性能稳定的基石。PrometheusGrafana 是这一领域中最受欢迎且功能强大的组合。Prometheus 负责数据的收集和存储,而 Grafana 则专注于数据的可视化和警报。两者协同工作,为开发者和运维人员提供了全面的可观测性和洞察力。

核心思想:
Prometheus 是一个开源的系统监控和警报工具包,以其基于 Pull 模型的指标采集方式和强大的多维数据模型而闻名。Grafana 是一个开源的数据可视化和仪表盘工具,支持多种数据源,提供高度定制化的图表和警报功能。它们共同构成了高效、灵活的监控解决方案。


一、Prometheus 详解

1.1 Prometheus 简介与核心概念

Prometheus 是一个开源的监控系统,最初由 SoundCloud 开发并于 2016 年加入云原生计算基金会(CNCF),成为第二个毕业项目(第一个是 Kubernetes)。它以其强大的多维数据模型、灵活的查询语言(PromQL)和出色的可扩展性而备受青睐。

核心概念:

  • 拉取模型 (Pull Model):Prometheus 默认采用拉取(pull)模型。它会主动向配置的目标(如应用程序实例、服务器等)上的 HTTP 接口(通常是 /metrics)发起请求,采集(scrape)监控指标数据。
  • 时序数据库 (Time-Series Database, TSDB):Prometheus 内置一个高效的时序数据库,用于存储所有采集到的监控数据。数据以时间序列的形式存储,即每个指标都包含一个时间戳和一个值。
  • 多维数据模型:所有指标数据都以指标名称(metric name)和一组键值对(labels)唯一标识。标签允许您通过这些维度对数据进行过滤、聚合和分组,极大地增强了查询和分析的灵活性。

1.2 Prometheus 架构

Prometheus 的生态系统包含多个组件,它们协同工作以提供完整的监控解决方案:

主要组件:

  1. Prometheus Server:Prometheus 的核心,负责:
    • 指标采集 (Scraping):定期从目标拉取指标。
    • 存储 (Storage):将采集到的数据存储在其本地时序数据库中。
    • 查询 (Querying):通过 PromQL 查询数据。
    • 规则处理 (Rule Processing):处理记录规则(recording rules)和报警规则(alerting rules)。
  2. Exporters (指标暴露器):独立的应用程序,用于暴露第三方系统(如主机操作系统、数据库、消息队列等)的指标。每个 Exporter 都会将特定系统的指标转换为 Prometheus 兼容的格式,并通过 HTTP 接口暴露。
    • Node Exporter:用于采集服务器(Linux/Unix)的 CPU、内存、磁盘 I/O、网络等系统级指标。
    • cAdvisor:用于容器的资源使用情况监控。
    • 数据库 Exporters:如 MySQL Exporter, PostgreSQL Exporter。
    • 应用程序 Exporters:如 JVM Exporter, Redis Exporter。
  3. Pushgateway (推送网关):Prometheus 默认采用拉取模型,但对于一些生命周期短暂、指标无法被 Prometheus 主动拉取的批处理作业(short-lived jobs),Pushgateway 允许这些作业将指标“推送”给它,然后 Prometheus 再从 Pushgateway 拉取这些指标。
  4. Alertmanager (警报管理器):处理 Prometheus 服务器发送的告警。它负责对告警进行分组、去重、静默、抑制,并通过各种通知方式(如邮件、Slack、PagerDuty 等)发送给相关人员。
  5. Service Discovery (服务发现):Prometheus 可以通过集成各种服务发现机制(如 Kubernetes, Consul, EC2 等)自动发现需要监控的目标,而无需手动维护目标列表。

1.3 Prometheus 数据模型

Prometheus 将所有数据存储为时间序列 (Time Series)。每个时间序列由以下几部分组成:

  • 指标名称 (Metric Name):描述被测量特征的通用名称,如 http_requests_total(HTTP 请求的总数)。
  • 标签 (Labels):一组键值对,用于标识时间序列中的特定维度。例如,{method="POST", handler="/api/users"}。同一个指标名称但标签不同的序列,被视为不同的时间序列。

示例:
http_requests_total{method="POST", handler="/api/users", status="200"}
http_requests_total{method="GET", handler="/api/articles", status="404"}

  • 样本 (Sample):时间序列在特定时间点的值。每个样本包含一个 float64 类型的值和一个精确到毫秒的时间戳。

数据类型:
Prometheus 主要有四种核心指标类型:

  • Counter (计数器):表示一个单调递增的计数器,只能增加或在重置时归零(如系统重启)。适用于统计累计值,如请求总数、错误总数。
  • Gauge (仪表盘):表示一个可以任意升降的瞬时值。适用于测量当前状态,如内存使用量、CPU 温度。
  • Histogram (直方图):对一系列观测值进行采样,并将其分布到可配置的桶中。提供 _bucket(累积计数)、_sum(观测值总和)和 _count(观测值总数)三个系列,用于计算分位数等。
  • Summary (摘要):与 Histogram 类似,但它在客户端计算分位数,并提供 _sum_count。Summaries 对于精确分位数估计可能更合适,但占用更多资源。

1.4 PromQL (Prometheus Query Language)

PromQL 是 Prometheus 自己的查询语言,功能强大且灵活,可以用于实时查询和聚合时序数据。

基本查询:
直接查询指标名称和标签来获取最新的样本数据。

1
http_requests_total{job="my_app", method="GET"}

范围查询:
通过在查询后加上 [duration] 来获取一段时间内的数据。

1
http_requests_total{job="my_app"}[5m] // 获取过去 5 分钟内的数据

聚合操作符:
sum, avg, min, max, count, stddev, stdvar, topk, bottomk 等。

1
sum(http_requests_total) by (job) // 按 job 聚合所有 HTTP 请求总数

速率和增长函数:

  • rate(v range vector):计算在一个时间窗口内,v 中时间序列的每秒平均增长率。常用于 Counter 类型指标来计算 RPS (Requests Per Second)。
  • irate(v range vector):计算在一个时间窗口内,v 中时间序列的瞬时每秒增长率。它用于检测快速变化的 Counter。
  • increase(v range vector):计算在一个时间窗口内,v 中时间序列的增量。
1
rate(http_requests_total[5m]) // 过去 5 分钟内 HTTP 请求的平均每秒速率

过滤和数学运算:
PromQL 支持各种数学运算符 (+, -, *, /, %, ^) 和比较运算符 (==, !=, <, >, <=, >=),以及布尔运算符 (and, or, unless)。

1
sum(rate(http_requests_total{status="500"}[5m])) / sum(rate(http_requests_total[5m])) * 100 // 计算过去 5 分钟内 5xx 错误率

示例:Go 应用程序暴露 Prometheus 指标

一个简单的 Go 应用程序使用 github.com/prometheus/client_golang/prometheus 库暴露 HTTP 请求总数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package main

import (
"fmt"
"log"
"net/http"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
// 定义一个 Counter 类型的指标:HTTP 请求总数
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests.",
},
[]string{"path", "method"}, // 标签:请求路径和请求方法
)

// 定义一个 Gauge 类型的指标:当前活跃的 Goroutine 数量
activeGoroutines = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "active_goroutines",
Help: "Current number of active goroutines.",
},
)
)

func init() {
// 注册指标
prometheus.MustRegister(httpRequestsTotal)
prometheus.MustRegister(activeGoroutines)
}

func handler(w http.ResponseWriter, r *http.Request) {
// 每次请求增加计数器
httpRequestsTotal.WithLabelValues(r.URL.Path, r.Method).Inc()

// 模拟处理请求
fmt.Fprintf(w, "Hello, Prometheus!\n")
}

func main() {
// 路由到 /metrics 暴露 Prometheus HTTP handler
http.Handle("/metrics", promhttp.Handler())

// 普通业务逻辑路由
http.HandleFunc("/", handler)
http.HandleFunc("/greet", func(w http.ResponseWriter, r *http.Request) {
httpRequestsTotal.WithLabelValues(r.URL.Path, r.Method).Inc()
fmt.Fprintf(w, "Greetings!\n")
})

log.Println("Server started on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

1.5 Prometheus 配置 (prometheus.yml)

Prometheus 的核心配置是一个 YAML 文件,主要定义了全局设置抓取配置 (scrape_configs)规则文件 (rule_files)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
global:
scrape_interval: 15s # 默认的抓取间隔
evaluation_interval: 15s # 默认的规则评估间隔

alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093'] # Alertmanager 地址

rule_files:
- "alert.rules" # 加载报警规则文件

scrape_configs:
# Prometheus 自身的监控
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090'] # Prometheus 自身暴露指标的地址

# 监控上述 Go 应用
- job_name: 'my_go_app'
static_configs:
- targets: ['localhost:8080'] # Go 应用暴露指标的地址
labels: # 可以为 job 添加额外标签
application: 'golang_demo'

# 监控 Node Exporter
- job_name: 'node_exporter'
static_configs:
- targets: ['localhost:9100'] # Node Exporter 默认端口

1.6 Prometheus 的优缺点

优点:

  • 强大的多维数据模型:通过标签可以对数据进行灵活的查询和聚合。
  • 功能丰富的 PromQL:允许进行复杂的查询、过滤、聚合和计算。
  • 高效的内置 TSDB:经过优化,可以高效存储和查询时序数据。
  • 云原生友好:与 Kubernetes 紧密集成,支持服务发现、自动伸缩等。
  • 丰富的 Exporter 生态系统:可以监控各种主流应用和基础设施。
  • Pull 模型:简化目标管理,减少被监控系统的开销,方便防火墙设置。

缺点:

  • 不适合长期存储:本地存储在单机上,扩展性有限。通常需要与其他长期存储方案(如 Thanos, Mimir, VictoriaMetrics)结合。
  • Pull 模型不适用于所有场景:对于生命周期极短的任务,需要 Pushgateway。对于隔离网络中的目标,可能需要一些代理方案。
  • 不易处理日志和事件:主要面向指标监控,不直接处理日志或复杂事件数据。
  • 高可用性复杂度:本身不提供内置高可用,需要借助外部方案(如 Thanos, Cortex)实现。

二、Grafana 详解

2.1 Grafana 简介与核心功能

Grafana 是一个开源的度量分析和可视化套件、仪表盘构建器和监控警报工具。它支持将来自各种数据源的数据(包括 Prometheus)整合成美观、交互式的仪表盘,并提供警报功能。

核心功能:

  • 多数据源支持:可以连接并查询多种数据源,如 Prometheus, Graphite, InfluxDB, Elasticsearch, Loki, MySQL, PostgreSQL 等。
  • 强大的可视化能力:提供多种面板类型(图表、表格、Stat、Gauge、Heatmap 等),支持高度定制化,以直观的方式展示数据。
  • 灵活的仪表盘 (Dashboards):用户可以创建、保存、共享和导入导出仪表盘。Dashboard 是由多个面板组成的集合。
  • 警报 (Alerting):在满足特定条件时,基于查询结果触发警报,并通过各种通知方式(邮件、Slack、Webhook 等)发送。
  • 权限管理:提供用户管理、团队、组织和仪表盘级别的权限控制。

2.2 Grafana 与 Prometheus 的集成

Grafana 是 Prometheus 最常用的可视化前端。它们的集成非常紧密且简单:

  1. 添加 Prometheus 数据源:在 Grafana 中,首先需要配置 Prometheus 作为数据源,指定 Prometheus Server 的地址和端口。
  2. 创建仪表盘和面板:在仪表盘中添加新的面板,选择 Prometheus 数据源。
  3. 编写 PromQL 查询:在面板的查询编辑器中,直接输入 PromQL 表达式来获取所需数据。Grafana 会将这些查询发送给 Prometheus Server 并接收结果进行渲染。

2.3 Grafana 仪表盘与可视化

Grafana 的可视化基于仪表盘 (Dashboard)面板 (Panel)

  • Dashboard (仪表盘):一个或多个面板的集合,用于展示相关数据。可以组织多个 Tab 页,每个 Tab 页包含不同用途的面板。
  • Panel (面板):仪表盘中的单个可视化组件,如时间序列图、Stat 图、Table 表、Gauge 仪表等。每个面板都包含一个或多个对数据源的查询,并以选定的可视化类型展示结果。

创建面板的通用步骤:

  1. 选择数据源:选择已配置的 Prometheus 数据源。
  2. 编写查询 (PromQL):输入 PromQL 查询语句。Grafana 通常提供自动补全功能。
  3. 选择可视化类型:选择合适的面板类型(Graph, Stat, Table, Gauge, Bar Gauge, Heatmap 等)。
  4. 配置可视化选项:根据需要调整图例、轴、颜色、阈值、单位、数据点样式等。

示例:在 Grafana 中展示 Go 应用的 HTTP 请求速率

假设 Prometheus 已经采集了 http_requests_total 指标。

  1. 在 Grafana 中添加一个数据源,命名为 Prometheus_Local,URL 设置为 http://localhost:9090
  2. 创建一个新的仪表盘,添加一个 Graph 面板。
  3. 在面板的 Query 标签页,选择 Prometheus_Local 数据源。
  4. 在 A 区域的查询框中输入 PromQL:
    1
    sum by (path, method) (rate(http_requests_total{job="my_go_app"}[5m]))
    这个查询将计算 my_go_app 所有 HTTP 请求在过去 5 分钟内的平均每秒速率(RPS),并通过 pathmethod 标签进行聚合。
  5. Legend 字段输入 {{path}} - {{method}},以便在图例中显示清晰的标签。
  6. Visualization 标签页,可以自定义图表的展现形式,例如 Y 轴单位设置为 ops/s

2.4 Grafana 的警报 (Alerting)

Grafana 的警报功能允许您在监控数据达到特定阈值时接收通知。您可以直接在面板中配置警报规则。

警报配置步骤:

  1. 在任何图表面板中,点击 Alert 标签页。
  2. 点击 Create Alert
  3. 命名警报:为警报设置一个有意义的名称。
  4. 配置查询 (Eval // 通常是查询表达式 ):Grafana 会使用当前面板的查询作为警报的基础。您还可以添加或修改查询。
  5. 设置条件 (Conditions // 阈值 ):定义警报触发的条件。例如,A (query result) > 10 表示当查询 A 的结果大于 10 时触发。
  6. 设置评估模式 (Evaluation Behavior)
    • Evaluate every:多久评估一次规则。
    • For:条件持续多久才真正触发警报。
  7. 配置通知渠道 (Notification Channels):选择一个或多个已配置的通知渠道(邮件、Slack、Webhook 等)。
  8. 添加标签和注解 (Labels & Annotations):帮助分类和理解警报。

2.5 Grafana 的优缺点

优点:

  • 美观且高度可定制的仪表盘:提供丰富的可视化选项和灵活的布局。
  • 多数据源支持:可以集成来自不同源的数据,在一个仪表盘中展示。
  • 支持模板变量:通过变量实现动态仪表盘,提高复用性。
  • 企业级警报功能:内置警报管理,支持多种通知方式。
  • 活跃的社区:拥有庞大的用户和开发者社区,提供大量预设仪表盘和插件。
  • 易于部署和使用:提供多种安装方式,界面友好。

缺点:

  • 不负责数据采集和存储:它只是一个可视化层,需要依赖其他监控系统作为数据源。
  • 警报管理能力不如 Alertmanager:Grafana 的警报相对简单,对于更复杂的警报分组、去重、抑制等高级功能,Alertmanager 更为强大和专业。通常推荐将 PromQL Alerting Rules 配置在 Prometheus Server,由 Alertmanager 进行告警管理,Grafana 仅用于可视化和展示告警状态。

三、Prometheus 与 Grafana 的协同工作

Prometheus 和 Grafana 的结合是现代监控的黄金搭档:

  • 角色分工明确:Prometheus 专注于数据的可靠采集和高效存储,并提供强大的查询能力初步的警报规则定义。Grafana 则专注于数据的可视化展示,将枯燥的指标数据转化为直观易懂的图表,并提供交互式的仪表盘灵活的警报通知
  • 优势互补:Prometheus 的多维数据模型和 PromQL 为 Grafana 的复杂查询和切片分析提供了坚实基础。Grafana 的用户界面弥补了 Prometheus Web UI 在数据可视化方面的不足。
  • 提高可观测性:通过将性能指标、错误率、资源利用率等数据通过 Grafana 仪表盘统一展示,运维人员和开发人员可以快速发现问题、定位故障,并全面了解系统运行状况。

四、部署考虑

基本部署流程:

  1. 安装 Prometheus Server:下载并配置 prometheus.yml 文件。
  2. 部署 Exporters:在需要监控的主机、应用旁部署相应的 Exporter,以便 Prometheus 可以抓取指标。
  3. 安装 Alertmanager (可选但推荐):配置告警路由和接收器。
  4. 安装 Grafana:配置 Prometheus 作为数据源。
  5. 创建 Dashboards:在 Grafana 中创建自定义仪表盘,或导入社区提供的现成仪表盘。
  6. 配置警报:在 Prometheus 中定义 alerting rules (推荐),由 Prometheus 发送给 Alertmanager 处理。

示例:Go应用的Prometheus和Grafana配置

假设您有一个 Go 应用在 localhost:8080 运行,暴露 Prometheus 指标。

  1. Go 应用:确保 Go 应用包含了 Prometheus 客户端库并暴露了 /metrics 接口。
  2. Prometheus 配置 (prometheus.yml)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # ... (其他配置)

    scrape_configs:
    # ... (其他 job)
    - job_name: 'my_go_app'
    static_configs:
    - targets: ['localhost:8080']
    labels:
    environment: 'development'
    service: 'golang-http-server'
  3. Grafana 配置
    • 在 Grafana 中添加一个新的 Prometheus 数据源,URL 为 http://localhost:9090
    • 创建一个新的仪表盘,添加一个 Time Series 面板。
    • 在查询框中输入 PromQL:
      1
      sum by (path, method) (rate(http_requests_total{job="my_go_app"}[1m]))
      这将展示 Go 应用每个路径和方法的每分钟请求速率。
    • 可以添加另一个 Stat 面板,显示当前活跃的 Goroutine 数量:
      1
      active_goroutines{job="my_go_app"}

五、总结

Prometheus 和 Grafana 的组合提供了一个强大、灵活且高度可扩展的监控解决方案。Prometheus 作为强大的时序数据收集和查询引擎,结合 Grafana 卓越的可视化和仪表盘能力,使得系统状态一目了然,并能够及时发现和响应潜在问题。掌握这两者的使用,对于构建健壮的云原生系统和保障服务质量至关重要。