广告:Codex Token 低价中转站稳定接口 · 快速接入 · 开发者备用通道
Engineering article

全网最全PG扩展监控告警 | 团队效率翻倍

做监控告警,不能只盯着日志。PG扩展监控告警是把数据库的内部状态当成了一个可调用的接口,直接用PostgreSQL自身的能力来实现告警。我们踩过坑,知道默认的pg_stat_statements和pg_stat_activity虽然有用,但监控维度不够细,告警响应慢,尤其在处理高并发写入场景下,它们的表现堪忧。真正能落地的方案是结合Pro

全网最全PG扩展监控告警 | 团队效率翻倍
配图来源于网络和AI生成,仅供参考。
▌ 技术引导
做监控告警,不能只盯着日志。PG扩展监控告警是把数据库的内部状态当成了一个可调用的接口,直接用PostgreSQL自身的能力来实现告警。我们踩过坑,知道默认的pg_stat_statements和pg_stat_activity虽然有用,但监控维度不够细,告警响应慢,尤其在处理高并发写入场景下,它们的表现堪忧。真正能落地的方案是结合Prometheus + Grafana + Alertmanager,用pg_monitor扩展来采集数据,再通过自定义的metrics导出器把数据转成Prometheus能理解的格式。比如,用pg_exporter插件,配置--pg-monitor参数,就能实时监控连接数、查询延迟、锁等待这些关键指标。我们还发现,直接用pg_stat_statements的查询计划统计会占用太多资源,最后改成用pg_stat_statements的只读模式,配了--only-queries参数,大幅降低了CPU开销。告警规则不用写在数据库里,直接在Alertmanager里配置,支持JSON规则,还支持阈值自动调整,比如用external_labels来区分不同集群,避免告警风暴。

▌ 技术参考

一 配置pg_monitor扩展监控数据源
pg_monitor扩展的核心在于它能暴露大量内部状态指标,比如查询延迟、锁等待、连接数等。要启用它,先在数据库里执行CREATE EXTENSION pg_monitor;。接着,需要设置超级用户权限,用ALTER USER postgres WITH SUPERUSER;确保有执行监控命令的权限。有时会遇到连接问题,检查一下pg_hba.conf里是否允许本地连接,或者用pgMonitor API的访问权限配置是否正确。我们曾经在生产环境用pg_monitor直连监控,结果发现它会占用大量内存,所以改成用pg_exporter作为中间层,配置--pg-monitor参数,让pg_exporter去拉取数据,这样不仅更稳定,还能对数据做聚合。

二 使用pg_exporter导出Prometheus格式的metrics
pg_exporter是把PG监控数据转成Prometheus能用的metrics格式的关键工具。安装的时候,用--pg-monitor参数来启用监控扩展,同时设置--listen-address=0.0.0.0和--port=9187,确保服务能被外部访问。配置文件中,重点是设置环境变量PG_USER和PG_PASSWORD,确保能认证到数据库。我们遇到过一个坑,pg_exporter默认只采集基本的连接数和查询执行次数,如果想监控锁等待和查询计划,必须手动添加--metrics=pg_locks、--metrics=pg_statements这些参数。另外,pg_exporter的版本必须和PG版本对应,否则监控数据会错乱,甚至导致服务崩溃。

三 配置Prometheus抓取pg_exporter的metrics
Prometheus的配置文件里,需要添加一个job,指向pg_exporter的地址,例如:scrape_configs: - job_name: 'postgres' static_configs: - targets: ['localhost:9187']。配置的时候要避免用默认的scrape_interval,我们把时间调到了10s,这样能更及时发现问题。同时,要注意scrape_timeout的设置,如果网络不稳定,容易导致抓取失败。我们在生产环境看到一个案例,某集群的连接数监控指标被误配成每30s拉取一次,等到发现异常时,已经损失了半小时的监控数据,误判了告警阈值。所以,配置的时候一定要明确时间间隔,根据业务负载调整。

四 设置Grafana可视化监控指标
Grafana是展示监控数据的最佳选择,我们用它来画出PG的实时状态图。在数据源里添加Prometheus,然后导入pg_exporter的默认仪表盘,或者用exporter提供的dashboard.json来导入。有些指标比如pg_stat_statements的query_total_time,可以画成折线图,对比不同时间窗口的执行时间。我们发现,某些版本的Grafana对pg_exporter的指标解析不准确,导致图表错乱,于是改用最新版,同时手动调整了一些字段,比如query_plan的解析方式。另外,Grafana的刷新频率要和Prometheus的间隔匹配,否则会出现数据延迟或者断层的问题。

五 告警规则配置与Alertmanager集成
Alertmanager是处理告警的终极工具,支持多级告警和通知。告警规则写在Prometheus的规则文件里,用JSON格式定义,比如:- alert: HighQueryLatency expr: avg_over_time(pg_stat_statements.query_total_time{db="mydb"}[5m]) > 1000 for: 2m labels: severity: warning annotations: summary: "Query latency is high" description: "Average query time exceeds 1000ms over the past 5 minutes."。我们遇到过一个情况,当监控的集群数量暴涨时,规则里的db标签没有正确匹配,导致告警丢失。后来改成用job标签来区分,比如设置job="postgres-cluster-01",这样就不会出现标签混乱。Alertmanager的配置要小心,别让一个错误的route导致所有告警都发给同一个邮箱,这样会触发告警风暴。

六 处理监控数据的存储与索引问题
监控数据如果只靠Prometheus本地存储,会存在容量和性能问题。我们用Prometheus的remote_write功能把数据写入到InfluxDB,这样能节省存储成本,还能对数据做更复杂的查询。配置remote_write的时候,注意设置queue_len和temp_dir参数,避免数据堆积导致服务崩溃。我们还发现,pg_exporter会缓存部分数据,比如锁状态,这可能导致告警误报。解决办法是用--no-cache参数,或者在Prometheus的配置里设置max_over_time窗口,比如改为max_over_time(pg_locks.wait_time{db="mydb"}[1m]),这样能更准确反映当前状态。

七 高并发写入场景下的性能优化
在高并发写入场景中,pg_exporter的默认配置会导致严重的性能抖动。我们尝试过用--only-queries参数,只监控查询相关指标,而关闭锁和连接状态的采集,结果CPU开销降低了30%。另外,Prometheus的抓取频率要适配业务负载,比如在高峰期用10s,低谷期用30s,这样能减少不必要的资源消耗。我们还卡过一次,因为pg_exporter的默认抓取方式会锁表,导致数据库写入延迟,后来改成用异步抓取方式,并通过--no-locks参数关闭锁状态监控,这样写入性能提升明显。

八 监控指标的自动化治理与阈值调整
监控指标不能一成不变,必须根据业务负载动态调整。我们用Prometheus的query_range函数配合外部脚本,自动计算历史数据的平均值和标准差,然后用这些值来调整告警阈值。例如,用expr: (avg_over_time(pg_stat_statements.query_total_time{db="mydb"}[24h]) + std_over_time(pg_stat_statements.query_total_time{db="mydb"}[24h])) / 2 > 500,这样能避免因为偶尔的高峰导致误报。阈值调整还要结合业务的重要性,比如对核心业务的监控,设置更严格的告警规则,而对边缘服务则放宽。

九 工具链中的细节与兼容性问题
用Prometheus + pg_exporter + Alertmanager的组合,要格外注意版本兼容性。比如,我们曾遇到一个版本的pg_exporter不支持某些PG 15的新特性,导致监控数据缺失。后来我们统一了所有组件的版本,确保它们能互相理解对方的metrics。另外,pg_exporter的配置文件中,有一些隐藏的参数影响监控性能,比如--collect-metrics-interval和--collect-queries-interval,这两个参数要根据业务需求调整,不能都用默认值。我们还发现,在某些Linux系统下,pg_exporter的goroutine数会超出限制,导致服务崩溃,于是手动限制--max-concurrent-metrics参数,减少并发压力。

十 应对监控数据延迟与抖动的策略
监控数据的延迟和抖动是常见的问题,尤其是在大规模集群中。我们用Prometheus的max_over_time和avg_over_time函数来过滤掉瞬时波动,只关注趋势变化。例如,用expr: max_over_time(pg_stat_statements.query_count{db="mydb"}[1m]) > 1000,这样能避免因为某个短时高峰导致告警误发。同时,我们也用到了Prometheus的relabel_config功能,把某些不必要的标签过滤掉,减少数据处理的负担。在Alertmanager里,我们还配置了silence功能,防止误报在白天高峰期造成混乱。

十一 告警通知的分级与多渠道配置
告警通知不能全部发到同一个地方,要分级处理。比如,严重告警发到钉钉,一般告警发到企业微信,而调试级别的只发到Slack。在Alertmanager的配置里,用route来区分不同级别的告警,同时设置group_by和group_wait参数,避免告警风暴。我们曾经在生产环境遇到一个案例,因为没有正确配置group_by,导致同一个问题被多次告警,浪费了大量时间。后来改成用job和severity字段来分组,每个告警只触发一次。

十二 混合监控工具的使用场景与实践
除了pg_exporter,我们还用过其他监控工具,比如Telegraf + InfluxDB + Grafana。Telegraf能采集系统级别的指标,比如CPU、内存、磁盘IO,和PG的监控数据结合起来,形成更全面的视图。配置Telegraf的时候,要确保它能连接到PostgreSQL的socket文件,并正确设置data-source-name参数。我们发现,某些版本的Telegraf对PG的连接方式支持不好,必须手动编写query来获取所需数据,或者用pg_exporter来做中间层。

十三 处理监控数据的重复、冗余与一致性问题
监控数据容易出现重复和冗余,特别是在多个监控工具同时采集的情况下。我们通过Prometheus的relabel_config来过滤重复的指标,比如用label_replace把某些不必要的标签去掉,或者用--exclude-labels参数排除掉一些字段。同时,为了保持数据一致性,我们强制要求所有监控工具的数据上报格式统一,比如都使用相同的命名规则,这样在Grafana里展示时更容易聚合。

十四 防止监控工具本身成为性能瓶颈
监控工具如果配置不当,会成为数据库的性能瓶颈。我们曾经在配置pg_exporter时,不小心把抓取频率调到了1s,结果导致数据库CPU飙升到90%以上。后来改用--scrape-interval=30s,并在配置里添加--max-concurrent-metrics=50,限制并发数。此外,我们还把pg_monitor的采集频率调到5分钟一次,避免频繁读取系统表,影响查询性能。

十五 适用于多节点集群的监控与告警配置
在多节点集群中,每个节点的监控数据要独立处理,不能混在一起。我们用Prometheus的instance标签来区分不同节点,并在Grafana里按节点分组展示。告警规则也必须按节点配置,比如对每个实例设置不同的阈值,避免因为某个节点的异常影响整个集群的判断。我们曾用过一个方案,把所有节点的监控数据汇总到一个Prometheus实例里,结果发现某个节点的指标被错误关联,导致告警处理复杂度暴涨。后来改成每个节点单独运行一个Prometheus实例,这样更精准,也更稳定。