数据库出了问题才想起来看监控,往往是来不及的。想要提前发现PostgreSQL的异常,一套完整的指标采集体系必不可少。postgres_exporter就是目前最主流的方案之一,它连接到PostgreSQL实例,把数据库内部的状态信息转换成Prometheus能够抓取的时间序列数据。这篇文章把安装部署、配置参数、自定义指标这些环节都展开讲清楚,照着做基本能跑通一套可用的监控链路。

postgres_exporter的几种部署方式
部署postgres_exporter主要有三种途径:直接下载二进制、使用Docker容器、以及在Kubernetes中部署。三种方式各有适用场景,下面分别说明。
二进制方式最直接。到项目的releases页面下载对应平台的压缩包,解压后得到一个可执行文件,配置好数据库连接串就能启动。这种方式适合传统的虚拟机部署,配合systemd管理进程,稳定性好排查问题也方便。一个典型的systemd服务单元可以这样写:
[Unit]
Description=postgres_exporter
After=network.target
[Service]
User=prometheus
Environment=DATA_SOURCE_NAME="postgresql://exporter:密码@127.0.0.1:5432/postgres?sslmode=disable"
ExecStart=/usr/local/bin/postgres_exporter \
--web.listen-address=:9187 \
--collector.stat_statements
Restart=on-failure
[Install]
WantedBy=multi-user.target
Docker方式则更适合容器化环境。官方镜像在docker hub上可以直接拉取,连接信息通过环境变量注入:
docker run -d \ --name postgres-exporter \ -p 9187:9187 \ -e DATA_SOURCE_NAME="postgresql://exporter:密码@192.168.1.100:5432/postgres?sslmode=disable" \ quay.io/prometheuscommunity/postgres-exporter
需要注意一点,DATA_SOURCE_NAME这个环境变量在新版本里已经支持用多个独立变量替代,比如PGHOST、PGPORT、PGUSER、PGPASSWORD、PGDATABASE,分开写的好处是密码不会出现在进程命令行里,安全性更好一些。
数据库账号权限与采集配置详解
exporter连接数据库不建议直接用超级用户,正确做法是创建一个专用监控账号,只授予必要的视图权限。下面这段SQL是官方推荐的初始化脚本,创建监控用户并授予系统视图的查询权限:
-- 创建监控专用用户 CREATE USER exporter WITH PASSWORD '强密码'; -- 授予系统视图权限 GRANT CONNECT ON DATABASE postgres TO exporter; GRANT USAGE ON SCHEMA public TO exporter; -- pg_stat_activity等视图需要超级用户创建的包装函数 CREATE OR REPLACE FUNCTION pg_stat_activity_view() RETURNS SETOF pg_stat_activity AS $$ SELECT * FROM pg_stat_activity $$ LANGUAGE sql VOLATILE SECURITY DEFINER; GRANT EXECUTE ON FUNCTION pg_stat_activity_view() TO exporter;
exporter默认采集的指标包括连接数、事务数、锁等待、缓存命中率、表膨胀相关的统计信息等,基本覆盖了日常运维关注的重点。但有些采集器默认是关闭的,比如针对pg_stat_statements的采集,需要在启动参数里显式开启--collector.stat_statements,同时数据库侧也要预先创建这个扩展:
-- postgresql.conf 中追加 shared_preload_libraries = 'pg_stat_statements' -- 重启后执行 CREATE EXTENSION pg_stat_statements;
开启之后就能拿到每条SQL语句的调用次数、总耗时、返回行数等指标,对定位慢查询非常有用。另外还有--collector.long_running_transactions等开关,可以根据实际需要逐个启用,建议不要一股脑全开,采集器越多对数据库的查询压力越大。
自定义查询:扩展属于你自己的指标
默认指标不够用时,postgres_exporter支持通过自定义查询文件扩展。原理很简单,你写一段SQL,指定返回列如何映射成指标名、类型和标签,exporter会周期性执行这段SQL并把结果暴露出来。查询文件通过--extend.query-path参数指定:
# custom_queries.yaml
pg_replication_lag_seconds:
query: "SELECT EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp()) AS lag"
master: true
metrics:
- lag:
usage: "GAUGE"
description: "复制延迟时间,单位秒"
pg_table_bloat_ratio:
query: |
SELECT relname AS table_name,
n_dead_tup * 100.0 / GREATEST(n_live_tup, 1) AS bloat_ratio
FROM pg_stat_user_tables
WHERE n_live_tup > 1000
metrics:
- table_name:
usage: "LABEL"
description: "表名"
- bloat_ratio:
usage: "GAUGE"
description: "死元组占比"
这里有两个细节容易踩坑。第一,SQL返回的列如果声明为LABEL,会作为指标标签;声明为GAUGE、COUNTER之类的才会成为指标值。第二,多行结果的查询每一行都会生成一个带不同标签的时间序列,比如上面的死元组统计,每张表一条序列,在Grafana里可以按表名分组展示趋势。
自定义查询给了很大的灵活性,但要控制执行频率和查询本身的代价。一个需要全表扫描才能算出来的指标,每15秒跑一次,对大库来说就是灾难。建议把重查询放到单独的exporter实例上,用较长的抓取间隔,轻量指标和重量指标分开管理。
多实例采集与Prometheus对接配置
一个exporter只能连一个数据库实例,如果环境里有多个PostgreSQL实例,通常有两种做法。一是每个实例旁边部署一个exporter,优点是采集压力分散、故障隔离;二是在Prometheus里用抓取配置做多目标,配合exporter的多数据库模式。对于容器化环境,推荐基于服务发现的自动发现方案:
scrape_configs:
- job_name: 'postgres'
static_configs:
- targets: ['192.168.1.10:9187']
labels:
instance: 'pg-master'
- targets: ['192.168.1.11:9187']
labels:
instance: 'pg-slave'
scrape_interval: 15s
scrape_timeout: 10s
如果用的是新版exporter支持的多数据库配置,可以通过--config.file指定一个yaml,里面声明多个数据源,exporter会在/probe路径下按目标参数动态采集,Prometheus侧改用relabel配置传入目标地址。这种方案减少了部署的进程数量,但单点问题需要考虑,生产环境里建议至少跑两个副本。
配置完成后,访问http://部署机器IP:9187/metrics,能看到大量以pg_开头的指标输出就说明链路通了。再用Prometheus自带的target状态页面确认抓取正常,最后在Grafana导入社区提供 dashboard 模板,常用的ID是9630或者12233,面板里连接趋势、缓存命中、慢查询排行一目了然。到这里,一套完整的PostgreSQL监控采集体系就算搭建完成了。
postgres_exporterPrometheus监控PostgreSQL指标采集修改时间:2026-09-10 12:14:36