Prometheus + Grafana 监控
pgAdmin 只能看「此刻」,要看「过去一小时、昨天、上个月」,必须有指标的采集、存储与展示体系。云原生世界为这个问题准备了事实标准组合:Prometheus(采集与存储)+ Grafana(可视化)+ postgres_exporter(数据库侧探针)。它以「拉取(pull)」模型周期性抓取 PostgreSQL 的指标快照,存进时序数据库,再由 Grafana 绘成趋势曲线与告警看板——pgAdmin 上一闪而过的小流水线,在这里被放大成 7×24 的大流水线。
本页完整走一遍这套组合的搭建:postgres_exporter 的部署与账号准备、Prometheus 的抓取配置、自定义查询扩展、Grafana 面板接入,以及一套可以直接抄进生产实践的告警规则示例(连接数、复制延迟、WAL 堆积、缓存命中率、长事务)。学完本页,你的 PostgreSQL 将第一次拥有「历史可回溯、异常会说话」的持续监控能力。
对本节前几页的成果做一次盘点:慢查询日志与 auto_explain 的 JSON 产出可以接入 Grafana 的日志面板(通过 Loki/Elasticsearch 数据源),pg_stat_statements 的口径成为语句级面板的标准语义,pgAdmin 兜底即时确认——本页是这些散装能力的「总装车间」。请带着这个视角阅读后面的配置细节。
前置知识
建议先阅读:pgAdmin 管理与监控
基础概念
三件套的分工
┌──────────────┐ HTTP /metrics(拉取) ┌────────────┐ PromQL ┌──────────┐
│ PostgreSQL │◄── postgres_exporter ────│ Prometheus │──────────────►│ Grafana │
│ (数据库) │ 定期查询 pg_stat_* │ (采集+存储)│ 查询/告警 │ (可视化) │
└──────────────┘ └────────────┘ └──────────┘
▲ │
│ 连接(监控账号) │ Alertmanager(可选,告警分发)
└──────────────────────────────────────────┘| 组件 | 职责 | 关键词 |
|---|---|---|
| postgres_exporter | 驻留在数据库附近,把 SQL 查询结果翻译成 Prometheus 指标 | 探针 / 转换器 |
| Prometheus | 周期拉取各 exporter 的 /metrics 端点,存储时序数据,评估告警规则 | 拉取模型 / TSDB |
| Grafana | 连接 Prometheus 数据源,渲染面板、看板与告警视图 | 面板 / 看板 |
| Alertmanager(可选) | 接收 Prometheus 的告警,去重、分组、路由到邮件/IM/Webhook | 告警分发 |
术语先建立三个:指标(metric)是带名字与标签的时间序列点;标签(label)给指标附加维度(如 dbname="appdb");PromQL 是 Prometheus 的查询语言,负责聚合、计算速率与触发告警。
与 Zabbix / pgwatch 的定位差异
工具章节的四个方案各有生态位,先立好坐标系,后面两页的展开才不迷路:
| 方案 | 一句话定位 | 强项 | 成本 |
|---|---|---|---|
| Prometheus + Grafana(本页) | 云原生指标事实标准 | 生态最大、PromQL 灵活、社区看板海量 | 需自建与运维整套栈 |
| Zabbix(下一页) | 企业级传统监控 | 模板齐全、告警体系成熟、企业特性(用户/审批)重 | 部署重、PromQL 式灵活性弱 |
| pgwatch(17.4.4) | PostgreSQL 专用语句级监控 | 开箱即用的语句级面板、preset 体系 | 专注 PG、通用性弱 |
选型的现实决策树:已有 Zabbix 的企业 → PostgreSQL 接入 Zabbix 而不是另起炉灶;云原生/容器化环境 → Prometheus 体系;想快速获得语句级深度监控 → pgwatch 或商业 SaaS(17.4.5)。多方案并存也是常态:Zabbix 管告警、Prometheus 管看板,关键是不让两套系统的「同一个指标」出现两套口径。
拉取模型对数据库监控的意义
Prometheus 的 pull 模型意味着:监控服务器的故障不会压垮数据库,但数据库的监控盲区会被及时发现(拉不到 = 指标缺失 = 立刻可见)。对数据库监控还有两个具体推论:其一,exporter 与数据库之间保持一个轻量连接即可,监控自身的开销完全可控;其二,抓取间隔(scrape interval)就是你的时间分辨率——15s 间隔可以捕捉到秒级的连接尖峰,1m 间隔则适合容量趋势。间隔的选择是「分辨率 vs 存储」的权衡,没有标准答案。
postgres_exporter 是什么
postgres_exporter 是 Prometheus 官方社区(prometheus-community)维护的 PostgreSQL 指标导出器(前身由个人开发者维护后转入社区)。它内置了针对标准统计视图(pg_stat_database、pg_stat_activity、pg_stat_replication 等)的默认采集,同时支持通过自定义查询文件扩展任意指标——这是它最强大的能力:任何能写成 SQL 的监控问题,都能变成 Grafana 上的曲线。
版本与配置说明
postgres_exporter 经历过配置方式的重大演进:早期版本以 DATA_SOURCE_NAME 环境变量指定连接串;新版本转向配置文件(--config.file 指定 YAML,内含连接串与采集器设置)。两种方式的参数名、指标命名在不同版本间存在差异。本页示例以较新的配置文件方式为主,具体以你所部署版本的官方 README 为准。
语法与用法
准备监控账号
监控账号坚持最小权限,官方推荐授予 pg_monitor 内置角色:
-- 1. 创建监控账号
CREATE ROLE exporter WITH LOGIN PASSWORD '强口令';
-- 2. 授予观察权限(pg_monitor 聚合了多个只读统计角色)
GRANT pg_monitor TO exporter;
-- 3. 允许连接业务库(统计视图大部分在库级)
GRANT CONNECT ON DATABASE appdb TO exporter;
-- 4. 如果要采集 pg_stat_statements(语句级指标),执行其重置函数需要额外授权:
GRANT EXECUTE ON FUNCTION pg_stat_statements_reset() TO exporter;
-- 注意:把 reset 函数交给监控账号意味着"重置"可被误触发,
-- 更稳妥的做法是复用本站 pg_stat_statements 一页的增量快照法,不授权 reset。同时确认 pg_hba.conf 允许 exporter 主机以口令方式连接:
# pg_hba.conf —— 只放行监控网段,限定账号
host all exporter 10.0.8.0/24 scram-sha-256部署 postgres_exporter
# 方式一:二进制部署
wget https://github.com/prometheus-community/postgres_exporter/releases/latest/download/postgres_exporter-*.linux-amd64.tar.gz
tar xzf postgres_exporter-*.tar.gz
cd postgres_exporter-*/# queries.yaml —— 自定义查询文件(结构示意,字段以所用版本文档为准)
app_connections:
query: "SELECT count(*) AS total, count(*) FILTER (WHERE state = 'active') AS active FROM pg_stat_activity WHERE datname = 'appdb'"
master: true
metrics:
- total:
usage: "GAUGE"
description: "Total connections to appdb"
- active:
usage: "GAUGE"
description: "Active connections to appdb"# exporter 配置文件(新版本方式,示意)
data_source_name: "postgresql://exporter:强口令@10.0.1.12:5432/appdb?sslmode=disable"
# 旧版本方式(环境变量,仍在大量存量部署中使用):
# DATA_SOURCE_NAME=postgresql://exporter:强口令@10.0.1.12:5432/appdb?sslmode=require# 启动(含自定义查询文件)
./postgres_exporter --config.file=exporter-config.yml --extend.query-path=queries.yaml
# 验证指标端点
curl -s http://localhost:9187/metrics | head -20# 方式二:Docker 部署(更常见)
docker run -d --name postgres_exporter \
-p 9187:9187 \
-v $PWD/queries.yaml:/etc/postgres_exporter/queries.yaml \
prometheuscommunity/postgres_exporterpostgres_exporter 的默认端口是 9187,/metrics 端点输出 Prometheus 文本格式指标。部署纪律:exporter 应部署在「与数据库网络可达、与 Prometheus 可达」的位置——常见做法是每台数据库主机一个 exporter(sidecar 模式),或每实例一个。
配置 Prometheus 抓取
# prometheus.yml
global:
scrape_interval: 15s # 抓取间隔 = 时间分辨率
evaluation_interval: 15s # 告警规则评估间隔
scrape_configs:
- job_name: "postgresql"
static_configs:
- targets: ["10.0.1.12:9187"]
labels:
env: "production"
instance_role: "primary"
- targets: ["10.0.1.13:9187"]
labels:
env: "production"
instance_role: "replica"
# PgBouncer 池化时单独抓取其 exporter
- job_name: "pgbouncer"
static_configs:
- targets: ["10.0.1.12:9127"]# 加载配置并检查
promtool check config prometheus.yml
curl -s http://prometheus:9090/-/reload # 需 --web.enable-lifecycle 支持labels 是指标检索的灵魂:多实例环境务必在抓取配置里打上环境与角色标签,Grafana 面板的「按实例下钻」、告警规则的「只对生产主库生效」都靠标签实现。
接入 Grafana
1. Grafana → Connections → Data sources → Add Prometheus
URL: http://prometheus:9090
2. Dashboards → New → Import:
从 Grafana 官方看板市场搜索 "PostgreSQL"(选择适配 postgres_exporter
且标明 Prometheus 数据源的看板,按下载量与维护活跃度挑选,
具体看板编号以市场实际页面为准);
或手工创建面板(详见下节)。
3. 变量(Variables)建议:datasource、env、instance_role——
让同一份看板在不同环境间复用。导入社区看板省时,但理解每个面板背后的 PromQL 更重要——看板作者是别人,告警责任是你。下一节直接手写核心面板。
手工创建核心面板(PromQL 模板)
| 面板 | PromQL 示意 | 说明 |
|---|---|---|
| 连接数趋势 | sum by (datname) (pg_stat_activity_count{state="active"}) | 指标名以所用 exporter 版本为准 |
| 库大小 | pg_database_size_bytes | 直接量测 |
| 缓存命中率 | sum(rate(pg_stat_database_blks_hit{datname="appdb"}[5m])) / (sum(rate(pg_stat_database_blks_hit{datname="appdb"}[5m])) + sum(rate(pg_stat_database_blks_read{datname="appdb"}[5m]))) | 经典差分 |
| 事务吞吐 | rate(pg_stat_database_xact_commit{datname="appdb"}[5m]) | 每秒提交数 |
指标名的重要提醒
PostgreSQL 的 pg_stat_* 计数器在 exporter 中映射为以 pg_ 开头的指标,精确指标名(下划线、后缀如 _count/_total)随 exporter 版本与采集器开关而变化。写面板前先用 Grafana 的 Explore 浏览实际存在的指标名,或直接 curl exporter:9187/metrics | grep pg_ 查看——不要凭记忆硬编码。
详细说明
默认采集覆盖了什么
postgres_exporter 的内置采集器覆盖数据库运维的主干指标面:
实例级:pg_up、启动时长、版本信息
库级:连接数、提交/回滚速率、块命中/读、临时文件、死元组(pg_stat_database)
活动级:当前会话状态分布(pg_stat_activity)
复制级:延迟字节/延迟时长、备库回放状态(pg_stat_replication,主库视角)
后台级:检查点、缓冲区、锁统计(pg_stat_bgwriter/pg_stat_checkpointer 等,随版本调整)注意「随版本调整」:内核改动了统计视图(如 PG17 拆分 pg_stat_bgwriter),exporter 的内置采集也会跟进调整,跨版本升级 exporter 时要看发行说明。主干指标之外的一切(业务维度、语句级、队列深度),都走自定义查询——这是 exporter 设计哲学的核心:内置管通用,SQL 管一切特殊。
自定义查询:任意 SQL 都能变成曲线
queries.yaml 的能力边界就是 SQL 的能力边界。三个高价值自定义查询方向:
# 方向一:长事务监控(业务最有感知的问题)
long_transactions:
query: |
SELECT count(*) AS count,
coalesce(max(extract(epoch FROM now() - xact_start)), 0) AS max_age_seconds
FROM pg_stat_activity
WHERE state <> 'idle' AND xact_start < now() - interval '5 minutes'
master: true
metrics:
- count:
usage: "GAUGE"
description: "Transactions older than 5 minutes"
- max_age_seconds:
usage: "GAUGE"
description: "Age of oldest transaction in seconds"
# 方向二:锁等待数量(对应优化流程值班压缩版第 2 步)
lock_waits:
query: |
SELECT count(*) AS waiting
FROM pg_locks WHERE NOT granted
master: true
metrics:
- waiting:
usage: "GAUGE"
description: "Locks waiting to be granted"
# 方向三:按表名的语句扫描统计(对接 pg_stat_statements 自定义聚合)
# 语句级指标建议参考 exporter 仓库自带的 pg_stat_statements 示例查询文件,
# 按需裁剪字段后再上线——全量语句指标的基数(cardinality)控制是关键。自定义查询的性能红线:每条查询以抓取间隔持续执行,15s 一次的全表扫描也是「每 15 秒一次」。写自定义查询的规矩与写巡检 SQL 相同——只碰统计视图与索引、避免大结果集、必要时加 LIMIT。上线后先在 Grafana 看 exporter 自身耗时与数据库负载确认无副作用。
监控自身开销的评估
数据库人问监控方案的第一句话应该是「你在我库上跑了什么、多久跑一次」。开销账这样算:
exporter 的开销 = 抓取间隔内的 SQL 执行成本
默认采集:十来条轻量查询(全部打在统计视图上),单次 < 数十毫秒
自定义查询:取决于 SQL 质量(红线已述)
频率:15s 一次 → 默认采集约占数据库资源的千分之一量级(经验值,仅参考量级)
Prometheus 侧开销:与被监控库无关,在监控服务器上自行消化
时序存储开销:基数 × 采样频率 × 保留期,预算公式见注意事项两个必须养成的习惯:其一,把 exporter 的连接也纳入 pg_stat_activity 巡检视野——它是库里的常驻客人,行为要可审计;其二,exporter 自身暴露的 /metrics 里包含采集耗时与失败计数,把它们画进 Grafana 的「监控自身健康」面板——监控系统不监控自己,是最隐蔽的盲区。
exporter 的高可用与失效语义
exporter 进程挂了会发生什么?Prometheus 拉取失败,目标标记为 down,pg_up 变 0——上面的 PostgresExporterDown 告警兜的就是这个底。设计上要注意:
1. exporter 单实例即可(它只是转换器,无状态),但要被系统服务管理
(systemd / 容器编排),崩了自动拉起
2. exporter 挂 ≠ 数据库挂,两类告警的 severity 应该不同:
exporter down → warning(先修监控)
数据库不可达(exporter 活着但连不上库,或采集错误率飙升)→ critical
3. 网络分区时 pull 模型天然「缺数据」,Grafana 面板要正确显示 gap
(不要用 fill 插值把故障期画成平线——那是自欺欺人的经典面板事故)pg_stat_statements 集成:语句级监控上云
exporter 社区提供了 pg_stat_statements 的示例采集查询,把语句级统计搬进时序库。集成后的典型面板:
语句级 Top 面板(数据来自 pg_stat_statements 采集):
total_exec_time 增速 Top 10 → 谁在持续消耗资源
mean_exec_time 分布 → 尾部延迟画像
calls 增速 Top 10 → 调用风暴预警与上一节(慢查询分析)的口径一致,这里的关键是增量思维:PromQL 的 rate()/increase() 函数在两次抓取之间做差分,天然实现了「增量榜单」,无需 reset 与快照表——监控时序库本身就是那个「历史基线表」。语句指标的字段基数大(每模板一个序列),生产部署要控制采集的模板数量(SQL 里加 ORDER BY ... LIMIT),否则时序库会被撑爆。
复制延迟与 WAL 堆积的监控
主备架构下,这两个指标是数据安全的哨兵(完整复制专题见高可用章节):
复制延迟(主库视角,pg_stat_replication):
write_lag / flush_lag / replay_lag → 时长维度
pg_wal_lsn_diff(sent_lsn, replay_lsn) → 字节维度
WAL 堆积:
pg_wal 目录大小 / WAL 段数量
归档延迟(pg_stat_archiver:failed_count、归档速率)字节维度的延迟用自定义查询采集(把 pg_wal_lsn_diff 的结果变成 GAUGE),告警阈值按业务容忍度定:流复制场景常见「延迟 > 100MB 或 > 30s 告警」。WAL 堆积告警的优先级要设得很高——它是「备库离线 + 磁盘将满」的双重前兆,历史上很多数据丢失事故的第一信号就是 WAL 目录悄然膨胀。
告警规则示例
Prometheus 的告警规则文件(PromQL 表达,经 Alertmanager 分发)。以下模板覆盖任务点名的五类场景,阈值是示例值,务必按业务校准:
# postgres-alerts.yml
groups:
- name: postgresql
rules:
# ① 实例不可达(最高优先级)
- alert: PostgresExporterDown
expr: pg_up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "PostgreSQL 指标端点不可达 ({{ $labels.instance }})"
# ② 连接数逼近上限
- alert: PostgresTooManyConnections
expr: sum(pg_stat_activity_count) / pg_settings_max_connections > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "连接数已达 max_connections 的 80% ({{ $labels.instance }})"
# ③ 复制延迟(字节与时长双口径)
- alert: PostgresReplicationLag
expr: pg_replication_lag_seconds > 30
for: 2m
labels:
severity: warning
annotations:
summary: "复制延迟超过 30s ({{ $labels.instance }})"
# ④ WAL 堆积(自定义查询指标示意)
- alert: PostgresWalBacklog
expr: pg_wal_lsn_diff_bytes > 1073741824 # > 1GB
for: 5m
labels:
severity: critical
annotations:
summary: "WAL 堆积超过 1GB ({{ $labels.instance }})"
# ⑤ 缓存命中率骤降
- alert: PostgresCacheHitRatioLow
expr: |
sum(rate(pg_stat_database_blks_hit{datname!~"template.*"}[10m]))
/
(sum(rate(pg_stat_database_blks_hit{datname!~"template.*"}[10m]))
+ sum(rate(pg_stat_database_blks_read{datname!~"template.*"}[10m]))) < 0.9
for: 15m
labels:
severity: warning
annotations:
summary: "10 分钟窗口缓存命中率低于 90% ({{ $labels.instance }})"
# ⑥ 长事务(对接自定义查询 long_transactions)
- alert: PostgresLongTransaction
expr: pg_long_transactions_max_age_seconds > 3600 # > 1 小时
for: 2m
labels:
severity: critical
annotations:
summary: "存在超过 1 小时的长事务 ({{ $labels.instance }})"# 规则文件检查与加载
promtool check rules postgres-alerts.yml
# 在 prometheus.yml 中引用:
# rule_files: ["postgres-alerts.yml"]规则设计的通用原则:for 持续时长过滤抖动(瞬时尖峰不值得半夜打电话);severity 分级路由(critical 打电话、warning 进群);annotations 写清含义与处置入口(告警信息里附 runbook 链接,值班者不用猜)。告警疲劳是监控系统死亡的第一原因——宁可少而准,不可多而麻木。
Grafana 告警与 Prometheus 告警的两条路线
Grafana 自身也演化出了告警能力,两套路线并存时容易混乱:
路线 A:Prometheus 规则 → Alertmanager → 分发
优点:规则与指标同源(Git 管理)、Alertmanager 的分组/静默/抑制成熟
适合:已有 Prometheus 告警体系、规则较多的团队
路线 B:Grafana Unified Alerting → Grafana 内置分发
优点:面板即告警、支持多数据源混合查询、配置界面友好
适合:小团队快速起步、非 Prometheus 数据源也要告警选一条主路线并写进规范,避免「一半告警在 Alertmanager、一半在 Grafana、职责不清谁也说不准」。起步期用 B 快速验证,规模化了迁到 A 是常见路径;迁移的关键是把每条告警的「表达式 + for + severity + runbook」四要素原样平移,并做一轮并行运行(双路同时触发几天,比对一致性)再下线旧路。
pgbouncer_exporter:把连接池纳入视野
使用 PgBouncer 的架构里,连接池排队是「假慢查询」的头号来源(优化流程页的隐形根因)。独立的 pgbouncer_exporter 把池的统计(SHOW STATS、SHOW POOLS 暴露的容量与等待)转成指标:
# prometheus.yml 追加
scrape_configs:
- job_name: "pgbouncer"
static_configs:
- targets: ["10.0.1.12:9127"]监控关注点(指标名以 pgbouncer_exporter 文档为准):
各池的 client 连接数 vs server 连接数 → 池饱和度
cl_waiting(排队中的客户端) → 排队即业务延迟
每池事务/查询速率 → 与 DB 侧吞吐对账部署形态与 postgres_exporter 一致:一个池一个 exporter,Prometheus 单独 job 抓取。业务侧耗时高而数据库侧耗时低时,第一时间来这里看排队曲线——优化流程页教的「两端做差」在这里变成两条曲线的叠加图。
与日志、trace 的联动
指标体系有天然盲区:它知道「异常发生了」,不知道「异常现场长什么样」。成熟可观测性方案会让三根支柱互相跳转:
Grafana 面板(指标)→ 标注(Annotation)打在曲线上 → 关联日志查询(jsonlog 采集)
→ 关联 trace(应用侧 APM)实操起步:把 PostgreSQL 的变更事件(部署、参数修改、failover)通过 Grafana API 打成 Annotation——曲线上的每一次突变立刻有了「当时发生了什么」的注脚。指标与日志的衔接在日志章节已铺好(jsonlog 采集进 Loki/ES),本页只要求把「跳转入口」建在面板上。
看板设计的四层结构
手工建看板别一张画到底,按「总 → 分 → 深 → 实」分层:
第一层 总览(Overview):
多实例网格:pg_up、连接率、事务速率、复制延迟 —— 一屏判读全部健康度
第二层 单实例详情(Instance Detail):
连接数、TPS、缓存命中率、临时文件、死元组 —— 点击总览下钻进入
第三层 深度(Deep Dive):
语句级 Top、锁等待、表 IO、WAL 速率 —— 按需展开的高成本查询
第四层 运维(Ops):
变更标注、备份产物大小、exporter 自身健康 —— 平时少看,出事必看四层结构的另一个好处是分工明确:第一层给所有人看,第二层给值班看,第三四层给 DBA 看——看板的使用者不同,颗粒度就该不同。社区看板导入后也可以按这个结构重排,删掉「看起来炫但说不清口径」的面板。
实战示例
示例一:从零搭建最小可用监控
# 1. 数据库侧:建监控账号(见前文 SQL)
# 2. 数据库主机:启动 exporter
docker run -d --name pg_exporter -p 9187:9187 \
-v /opt/pgmon/queries.yaml:/etc/queries.yaml \
prometheuscommunity/postgres_exporter
# 连接配置按所用版本方式传入(配置文件或环境变量)
# 3. 监控主机:prometheus.yml 增加抓取(见前文配置),启动 Prometheus
./prometheus --config.file=prometheus.yml
# 4. 验证指标链路
curl -s http://10.0.1.12:9187/metrics | grep pg_up
# 期望输出包含:pg_up 1
# 5. Grafana 添加数据源,创建第一个面板:连接数曲线全链路 30 分钟。此后数据库的每一次异常波动都会留痕——这是从 pgAdmin 到监控平台的关键一跃。
示例二:连接数告警的完整演练
# 场景:max_connections=200,演练到 160(80%)时是否触发
- alert: PostgresTooManyConnections
expr: sum(pg_stat_activity_count) / pg_settings_max_connections > 0.8
for: 5m
annotations:
summary: "连接数 80%:{{ $value | humanizePercentage }} ({{ $labels.instance }})"
runbook_url: "https://wiki.internal/runbook/pg-connections"演练步骤:
1. 临时把阈值调低到 0.1,确认规则能触发、Alertmanager 能送达(邮件/IM)
2. 恢复阈值 0.8,用压测工具把连接推过 160,观察 5m 的 for 持续期
3. 释放连接,确认告警自动 resolve
4. 演练记录写进 runbook:谁触发、多久送达、误报率如何没有经过演练的告警规则等于不存在——真正需要它的深夜,它可能根本没配置对。
示例三:用 Grafana 面板回答「昨晚发生了什么」
复盘场景:昨夜 23:40 业务接口超时报警,今晨复盘。
1. Grafana 连接数面板:23:35 连接数从 40 跳到 190(逼近上限)
2. 会话状态分布面板:idle 占比暴涨 → 疑似应用连接泄漏
3. 切日志平台(jsonlog 采集),过滤 23:30-23:45:
大量 connection authorized 记录,无对应 finish
4. 结论:新版本发布引入连接泄漏 → 联动应用侧修复
5. 面板上打 Annotation「v2.4.1 连接泄漏事故」,形成完整证据链这个复盘演示了指标 + 日志 + 标注的标准三件套——「昨晚发生了什么」从玄学变成五分钟流程。
示例四:多实例环境的三层标签体系
# 大规模部署的抓取配置(文件发现示例)
scrape_configs:
- job_name: "postgresql"
file_sd_configs:
- files: ["/etc/prometheus/targets/pg/*.json"]// /etc/prometheus/targets/pg/production.json
[
{ "targets": ["10.0.1.12:9187"],
"labels": { "env": "production", "cluster": "shop", "role": "primary" } },
{ "targets": ["10.0.1.13:9187"],
"labels": { "env": "production", "cluster": "shop", "role": "replica" } },
{ "targets": ["10.0.2.21:9187"],
"labels": { "env": "staging", "cluster": "shop", "role": "primary" } }
]# 面板与规则按三层标签检索:
# {env="production"} → 只看生产
# {env="production", cluster="shop"} → 只看生产 shop 集群
# {role="replica"} → 所有备库实例超过两位数后,标签体系就是监控系统的骨架——事后补标签的成本远高于开局就定好。
注意事项
监控账号必须有界。 pg_monitor + 库连接权限是全集;pg_stat_statements_reset 等高危函数不建议授予(误触发会清空语句统计基线)。监控账号口令也要轮转,别因为「它只是只读的」就设成永不更换。
exporter 版本与内核版本要一起管理。 内核统计视图的演进(拆分、改名、新增字段)直接影响内置采集器;升级 PostgreSQL 大版本时,exporter 升级要列入同一变更单,升级后核对指标完整性。
自定义查询是双刃剑。 一条写着顺手的全表聚合,会以抓取间隔永续执行。所有自定义查询过三关:只碰统计视图、结果集有界、上线后观察数据库侧负载。exporter 的采集耗时(自监控指标)应纳入巡检。
指标名不要硬编码。 exporter 演进中指标命名有变化(历史上有过较大重构),面板与规则引用的指标名要用「Explore 实测」确认。团队内共享的面板 JSON 要注明适配的 exporter 版本。
抓取间隔决定告警灵敏度的上限。 15s 抓取 + 2m for 的告警,最快也要约 2 分半才触发——秒级故障(如连接风暴打满)可能「还没告警就结束了」。对超快的故障模式,缩短抓取与评估间隔,或改用数据库侧的本地守护(如日志触发)。
单点 Prometheus 不可靠。 监控挂了等于全盲,生产环境至少考虑 Prometheus 的双实例或远程存储(Thanos/VictoriaMetrics/Mimir 等方案选其一),Alertmanager 做集群化。监控自身的可用性是下一层级的运维议题,但不能长期裸奔。
时序库的基数治理。 高基数指标(每语句、每用户、每表一个序列)会在几周内吃掉存储与内存。采集 SQL 里的 LIMIT、Grafana 面板里的标签筛选、定期的基数审计,三件套缺一不可。
不要把 pg_stat_statements 的 mean 当实时指标。 语句统计是累计口径,rate 差分后才有「当前」含义;面板上直接画 mean 曲线会呈现「惯性平线」假象——这也是语句级监控比资源级监控难做的原因。
抓取失败的重试语义要理解。 Prometheus pull 失败不会自动重试本次抓取(下一次抓取按计划进行),指标在时序库里就是缺口。对带宽/抖动敏感的环境,scrape_timeout 要小于抓取间隔(官方默认 10s/15s 的组合即如此),让超时可控而不是悬空。
Secrets 管理别偷懒。 exporter 的连接串里带着数据库口令,无论环境变量还是配置文件方式,都要纳入密钥管理(K8s Secret、Vault、受限权限的配置目录),并禁止把带口令的启动命令写进 shell history 或启动脚本仓库。
最佳实践
- 监控账号一律
pg_monitor+ 最小补充,口令纳入轮转。 与应用账号严格分离,监控流量在pg_hba.conf限定网段。 - 每实例一个 exporter,抓取配置用文件发现 + 三层标签(env/cluster/role)。 标签体系从第一个实例就建好,规模化时零迁移成本。
- 抓取与评估间隔统一 15s 起步,容量敏感场景再放宽;对告警的「最快触达时间」要有量化预期并写进 SLA。
- 五类核心告警先落地:实例存活、连接数、复制延迟、WAL 堆积、长事务,再加缓存命中率与语句级异常。每条规则配 for 持续期与 runbook 链接,每条规则上线前演练。
- 自定义查询走「统计视图优先、结果有界、上线观察」三关。 把本站巡检章节的 SQL(长事务、锁等待、膨胀、空闲事务)依次迁入 queries.yaml,让巡检从「人跑」变「系统跑」。
- Grafana 看板自建为主、社区看板为辅。 导入市场看板要逐面板理解 PromQL 并本地化指标名;团队共享的面板 JSON 纳入版本管理。
- 语句级监控控制基数:采集 SQL 一律
ORDER BY ... LIMIT。 pg_stat_statements 的增量视角(rate/increase)替代「定期 reset」习惯,时序库做历史基线。 - 变更事件打 Annotation。 部署、参数修改、failover 全部上曲线注脚,复盘效率翻倍——这是指标体系成本最低、收益最高的增强。
- PgBouncer 架构必配 pgbouncer_exporter。 连接池排队是「假慢查询」主源,池的等待队列与数据库指标同图展示。
- 监控自身高可用:双 Prometheus 或远程存储,Alertmanager 集群。 全盲的监控系统是最危险的故障状态。
- 导出的 Grafana 看板与告警规则进 Git。 像代码一样评审与回滚,杜绝「面板只在某人浏览器里存在」。
- 把本页体系与本节前三页打通。 auto_explain 的 JSON 计划进日志管道、慢查询日志的 Top 统计进看板、pg_stat_statements 的口径作为语句面板标准——监控不是工具堆砌,是本节四页工具链的收口;继续深入模板化企业监控请读下一页 Zabbix。
下一节
继续学习:Zabbix 监控
参考链接
- postgres_exporter(prometheus-community)官方仓库
- Prometheus 官方文档:Configuration(scrape_configs)
- Prometheus 官方文档:Alerting Rules
- Prometheus 官方文档:EXPLAIN 式查询语言 PromQL
- Grafana 官方文档:PostgreSQL 数据源与看板
- Grafana 官方看板市场(PostgreSQL 搜索)
- pgbouncer_exporter 官方仓库
- Prometheus 官方文档:Alertmanager
- PostgreSQL 官方文档:Database Roles(pg_monitor)
- PostgreSQL 官方文档:pg_stat_statements