Vector 的 postgresql_metrics 源:从 RFC 设计到生产实现的 PostgreSQL 指标采集指南
2026/9/13 20:25:09 网站建设 项目流程

Vector 的 postgresql_metrics 源:从 RFC 设计到生产实现的 PostgreSQL 指标采集指南

【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector

本文以 Vector 仓库中的 RFC 3603(2020-08-27 提交)为骨架,结合仓库中postgresql_metrics源的最终实现代码与其官方组件文档,完整讲解:Vector 如何原生采集 PostgreSQL 服务器指标、postgresql_metrics源暴露哪些配置项、每一类指标的名称与语义是什么,以及该设计在实现落地过程中的关键演进。读完本文,你将能够独立配置一个postgresql_metrics源,理解其指标命名规则与标签体系,并知道如何用集成测试验证采集结果。

一、RFC 背景:为什么 Vector 需要原生 PostgreSQL 指标源

RFC 3603 的动机非常直接:用户希望采集、转换并转发 PostgreSQL 数据库的性能指标,以更好地观察数据库的运行状态。在此之前,用户若想将 PostgreSQL 指标送入 Vector 管道,只能依赖 Telegraf 的postgresqlinput 或 Prometheus 的postgresql_exporter这类外部采集器,再让 Vector 通过prometheus源去抓取——链路长、组件多、维护成本高。

RFC 的 Scope 明确了两点边界:

  • 覆盖:新增一个用于采集 PostgreSQL 服务器指标的 source;
  • 不覆盖:其他数据库的指标采集。

之所以值得做,除了 PostgreSQL 本身是被广泛采用的现代数据库、用户普遍需要监控其状态与性能外,更关键的是 Vector 的产品愿景——"One Tool. All Data.",即一个工具完成日志、指标、追踪(当时即将支持)的摄取与投递。RFC 中引用了 Vector 官方文档的两条原则:

One Tool. All Data. —— 一个简单工具将你的日志、指标和追踪从 A 送到 B。

你应该使用 Vector 替代 Logstash、Fluent*、Telegraf、Beats 或类似的工具。

换句话说,把 PostgreSQL 指标采集内建到 Vector 中,是为了减少用户在摄取指标时对第三方采集器的依赖,让 Vector 真正成为可替代 Telegraf 的一体化数据管道。

二、整体设计:一个源、三个查询、一套命名规则

2.1 实现方案:Rust PostgreSQL 客户端直连

RFC 给出的内部方案是:构建一个名为postgresql_metrics(当时名称待确认)的单一 source,使用 Rust 的 PostgreSQL 客户端(tokio_postgres)按配置中给定的地址连接目标数据库服务器

这一方案在最终实现中完全落地。在 src/sources/postgresql_metrics.rs 中,源码直接依赖tokio_postgres(含ClientConfigNoTlsRow等类型),并通过postgres_openssl::MakeTlsConnector支持 TLS 连接。连接建立后,源码会执行SHOW server_version_num检查服务器版本,只有**主版本号大于等于 9.6(即 server_version_num >= 90600)**的服务器才会被接受,否则抛出InvalidVersion错误——这与 RFC 中"支持所有未 EOL 的 PostgreSQL 版本"的承诺一致。

2.2 三个核心查询

RFC 明确规定了 source 需要执行的三条查询:

SELECT * FROM pg_stat_database SELECT * FROM pg_stat_database_conflicts SELECT * FROM pg_stat_bgwriter

最终实现与 RFC 完全一致。在源码中,这三条查询被封装在DatnameFilterPostgresqlMetrics中:

  • pg_stat_databaseDatnameFilter::pg_stat_database):逐数据库返回连接数、事务提交/回滚、块读写命中、元组增删改查、临时文件、死锁等累计统计;
  • pg_stat_database_conflictsDatnameFilter::pg_stat_database_conflicts):在备库(standby)上返回因恢复冲突而被取消的查询次数,按冲突类型(表空间、锁、快照、buffer pin、死锁)拆分;
  • pg_stat_bgwriterDatnameFilter::pg_stat_bgwriter):后台写进程(background writer)的检查点与缓冲写统计,属于集群级(非数据库级)数据。

三者通过try_join_all并发执行(见collect_metrics),采集完成后统计字节数与事件数,并通过内部事件EndpointBytesReceivedEventsReceived上报。采集循环由tokio::time::interval驱动,每次迭代结束发送CollectionCompleted事件,度量单轮采集耗时。

2.3 指标命名规则

RFC 定义的命名规则非常清晰,这也是本文值得记住的核心约定:

table_name_column_name+ Prometheus 结尾(计数器加_total等)

即:表名 + 下划线 + 列名,再依据指标类型追加 Prometheus 风格的_total后缀。RFC 给出的示例:

  • pg_database_conflicts_confl_tablespace_total

其中pg_database_conflicts是表名,confl_tablespace是列名,_total是因为计数器在 Prometheus 命名约定中必须以total结尾。这套规则与 Prometheus 官方 exporter 的命名方式保持一致,方便用户在 Prometheus 生态中复用查询经验。

需要注意的是,RFC 中"表名"的示例写法是pg_database_conflicts,而最终实现落地时统一采用了pg_stat_database_conflicts_confl_*前缀,指标语义与命名规则本身没有变化,只是前缀与 PostgreSQL 视图名保持了一致。

三、指标清单:完整指标表与语义

RFC 在"Internal Proposal"一节列出了一份完整的指标清单,并标注了每个指标的标签(tag)集:数据库级指标带dbhostserveruser,集群级指标带hostserver。最终实现保留了这一分层思想,但标签体系简化为:所有指标带endpointhost,数据库级指标额外带dbserveruser未在最终实现中出现,endpoint则是 RFC 在"所有指标将额外带 endpoint(去除用户名/密码后)"一节中要求增加的)。

以下为最终实现实际输出的指标清单,结合 组件文档 中的官方描述整理:

3.1 可用性指标

指标名类型标签语义
upgaugeendpoint, hostPostgreSQL 服务器是否存活,成功采集为1,失败为0

up指标对应 RFC 中的pg_up设计("0 表示采集成功、1 表示采集失败"),实现时去掉了pg_前缀并反转语义(成功=1)。在源码collect()中,采集成功时输出gauge!(1.0),任一步骤出错则输出gauge!(0.0)并发出PostgresqlMetricsCollectError内部事件。

3.2 pg_stat_database 系列(数据库级,带 db 标签)

指标名类型语义
pg_stat_database_datidgauge数据库 OID,共享对象为 0
pg_stat_database_numbackendsgauge当前连接到该数据库的后端进程数(唯一反映当前状态的列)
pg_stat_database_xact_commit_totalcounter已提交事务数
pg_stat_database_xact_rollback_totalcounter已回滚事务数
pg_stat_database_blks_read_totalcounter磁盘块读取数
pg_stat_database_blks_hit_totalcounter命中 PostgreSQL 缓冲缓存(非 OS 文件缓存)的块数
pg_stat_database_tup_returned_totalcounter查询返回的行数
pg_stat_database_tup_fetched_totalcounter查询取回的行数
pg_stat_database_tup_inserted_totalcounter插入的行数
pg_stat_database_tup_updated_totalcounter更新的行数
pg_stat_database_tup_deleted_totalcounter删除的行数
pg_stat_database_conflicts_totalcounter因恢复冲突被取消的查询数(仅备库出现)
pg_stat_database_temp_files_totalcounter创建的临时文件数
pg_stat_database_temp_bytes_totalcounter写入临时文件的数据总量
pg_stat_database_deadlocks_totalcounter检测到的死锁数
pg_stat_database_blk_read_time_seconds_totalcounter后端读取数据文件块耗时(秒,需启用track_io_timing
pg_stat_database_blk_write_time_seconds_totalcounter后端写入数据文件块耗时(秒,需启用track_io_timing
pg_stat_database_stats_resetgauge上次重置统计的时间(Unix 时间戳)

3.3 pg_stat_database_conflicts 系列(备库冲突,带 db 标签)

指标名类型语义
pg_stat_database_conflicts_confl_tablespace_totalcounter因表空间被删除而取消的查询数
pg_stat_database_conflicts_confl_lock_totalcounter因锁超时而取消的查询数
pg_stat_database_conflicts_confl_snapshot_totalcounter因旧快照而取消的查询数
pg_stat_database_conflicts_confl_bufferpin_totalcounter因 buffer 被 pin 而取消的查询数
pg_stat_database_conflicts_confl_deadlock_totalcounter因死锁而取消的查询数

3.4 pg_stat_bgwriter 系列(集群级,无 db 标签)

指标名类型语义
pg_stat_bgwriter_checkpoints_timed_totalcounter已执行的定时检查点次数
pg_stat_bgwriter_checkpoints_req_totalcounter已执行的请求式检查点次数
pg_stat_bgwriter_checkpoint_write_time_seconds_totalcounter检查点处理中写入文件的总耗时(秒)
pg_stat_bgwriter_checkpoint_sync_time_seconds_totalcounter检查点处理中同步文件的总耗时(秒)
pg_stat_bgwriter_buffers_checkpoint_totalcounter检查点期间写入的缓冲数
pg_stat_bgwriter_buffers_clean_totalcounter后台写进程写入的缓冲数
pg_stat_bgwriter_maxwritten_clean_totalcounter后台写进程因写入过多缓冲而停止清理扫描的次数
pg_stat_bgwriter_buffers_backend_totalcounter后端直接写入的缓冲数
pg_stat_bgwriter_buffers_backend_fsync_totalcounter后端自行执行 fsync 的次数
pg_stat_bgwriter_buffers_alloc_totalcounter已分配的缓冲数
pg_stat_bgwriter_stats_resetgauge上次重置统计的时间(Unix 时间戳)

3.5 按版本条件输出的扩展指标(PostgreSQL 12+)

源码中有一处版本分支:当client_version >= 120000(即 PostgreSQL 12 及以上)时,额外采集两个校验和指标:

指标名类型语义
pg_stat_database_checksum_failures_totalcounter检测到的数据页校验和失败次数(未启用数据校验和时为 0)
pg_stat_database_checksum_last_failuregauge最后一次数据页校验和失败的时间(Unix 时间戳,未启用时为 0)

3.6 单位与数值归一化细节

实现层面有几个值得注意的数值处理:

  • 时间类指标统一转为秒blk_read_timeblk_write_timecheckpoint_write_timecheckpoint_sync_time在 PostgreSQL 中单位为毫秒,源码读取f64后统一除以1000f64再输出,且指标名带有_seconds_段,命名与单位自洽;
  • 时间戳类指标转为 Unix 时间戳stats_resetchecksum_last_failure这类timestamptz列通过chrono::DateTime<Utc>读取后取.timestamp()
  • 所有指标使用MetricKind::Absolute输出,并带namespace(默认postgresql)与当前 UTC 时间戳。

四、配置详解:从 RFC 草案到最终实现

4.1 RFC 中的配置草案

RFC 的 Doc-level Proposal 给出的配置示例如下:

[sources.my_source_id] type = "postgresql_metrics" # required endpoint = "postgres://postgres@localhost" # required - address of the PG server. included_databases = ["production", "testing"] # optional, list of databases to query. Defaults to all if not specified. excluded_databases = [ "development" ] # optional, excludes specific databases. If a DB is excluded explicitly but included in `included_databases` then it is excluded. scrape_interval_secs = 15 # optional, default, seconds namespace = "postgresql" # optional, default is "postgresql", namespace to attach to metrics.

RFC 同时提出"还将暴露 HTTP SSL 设置,并在 endpoint URL 中支持ssl参数",并计划补充一份"无需 root 权限运行"的指南。

4.2 最终实现的配置项

对照 生成配置文档 与 源码配置结构体,最终配置形态如下:

[sources.my_source_id] type = "postgresql_metrics" # required endpoints = ["postgresql://postgres:vector@localhost:5432/postgres"] # required include_databases = ["^postgres$", "^vector$"] # optional exclude_databases = ["^template.*"] # optional scrape_interval_secs = 15 # optional, default 15 (seconds) namespace = "postgresql" # optional, default "postgresql" [sources.my_source_id.tls] ca_file = "certs/ca.pem" # optional

各配置项说明(RFC 草案 → 最终实现的差异已标注):

配置项必填默认值说明
endpointsRFC 草案为单个endpoint,实现演进为endpoints字符串数组,可同时抓取多个 PostgreSQL 实例,每个元素须为 PostgreSQL 连接 URI 格式(如postgresql://postgres:vector@localhost:5432/postgres
include_databases全部数据库RFC 草案名为included_databases,实现定稿为include_databases;使用 POSIX 正则表达式匹配datname列,指定""表示包含datname为 NULL 的记录(如共享对象)
exclude_databases不排除RFC 草案名为excluded_databases,实现定稿为exclude_databases;同样使用 POSIX 正则。RFC 明确优先级语义:数据库若同时被 include 与 exclude,则被排除
scrape_interval_secs15两次抓取之间的间隔,单位秒
namespace"postgresql"附加到所有输出指标上的命名空间
tls.ca_file附加 CA 证书文件的绝对路径,证书须为 DER 或 PEM(X.509)格式

4.3 include/exclude 的正则过滤是如何实现的

最终实现没有在 SQL 层面硬编码数据库名,而是用DatnameFilter(源码实现)在构建查询时动态拼装 WHERE 子句

  • include 列表中的每个正则生成一个datname ~ $N谓词(POSIX 正则匹配),多个正则之间用OR连接,整体用括号包裹;
  • exclude 列表生成NOT (datname ~ $1 OR datname ~ $2 ...)谓词,并通过AND与 include 组合,从而天然实现"exclude 优先级更高";
  • ""被特殊处理为datname IS NULL/datname IS NOT NULL条件:include 含空串则保留 NULL 记录,exclude 含空串则剔除 NULL 记录;
  • 所有正则通过参数化查询(match_params)传入,避免 SQL 注入。

include_databasesexclude_databases均未配置,则查询保持最简形式SELECT * FROM pg_stat_database,等价于采集全部数据库。这一点与 RFC 中"未指定时默认采集所有数据库"的语义一致。

4.4 TLS 与连接安全

RFC 提出的 SSL 支持最终以两种方式落地:

  1. endpoint URL 内建 SSL 参数:连接 URI 中直接支持sslmode(如?sslmode=require),源码会解析并透传该参数;
  2. 独立tls配置块:提供tls.ca_file指定附加 CA 证书(DER/PEM 格式),通过 OpenSSL 构建MakeTlsConnector建立加密连接(见源码build_client中的SslConnector::builder(SslMethod::tls_client())set_ca_file)。

此外,连接成功后源码在 DEBUG 级别记录服务器版本(SELECT version()),并对endpoint标签做了脱敏处理:config_to_endpoint函数会将连接配置重新序列化为不含用户名/密码的规范化 URI(如postgresql:///postgres?host=localhost&port=5432),这正是 RFC 要求的"所有指标均带上去除用户名/密码后的 endpoint 标签"。从源码看,该函数还会保留sslmodeconnect_timeoutkeepalives_idletarget_session_attrschannel_binding等连接参数,剔除默认值。

4.5 输出标签体系

最终实现的标签体系如下:

  • 所有指标:endpoint(脱敏后的连接 URI)、host(取自连接配置的主机,TCP 主机名或 Unix socket 路径);
  • 数据库级指标(pg_stat_database 与 pg_stat_database_conflicts 系列):额外带db标签(取自datname列,NULL 时为"");
  • 集群级指标(pg_stat_bgwriter 系列):仅endpointhost

五、权限要求与运维注意

5.1 所需权限

组件文档 的 "Required Privileges" 一节明确指出:postgresql_metrics通过向配置的 PostgreSQL 服务器发起查询来采集指标,必须确保配置的用户对以下三个视图拥有 SELECT 权限

  • pg_stat_database
  • pg_stat_database_conflicts
  • pg_stat_bgwriter

RFC 也提到要补充"无需 root 权限运行"的指南——即使用具备上述视图查询权限的专用低权限账号,而不是超级用户。实际操作中应避免在 endpoint URI 中硬编码高权限账号口令,可通过 Vector 的密钥管理能力注入凭据。

5.2 采集行为与版本限制

  • 多实例并发endpoints中每个实例对应一个独立的PostgresqlMetrics采集器,抓取时通过join_all并发执行,互不阻塞;
  • 版本校验:连接时执行SHOW server_version_num,低于 9.6 的服务器连接会被拒绝并返回InvalidVersion错误;12.0 以上自动多采集两个校验和指标;
  • 失败语义:任何一轮采集中有实例失败,该实例输出up = 0,成功实例正常输出,管道不会中断;
  • 内部遥测:每轮抓取会产生collect_completed_totalcollect_duration_seconds等内部指标,可用于监控采集器自身健康状况。

六、集成测试验证:实现确实按 RFC 工作

postgresql_metrics的集成测试位于 src/sources/postgresql_metrics.rs 的integration_tests模块(需启用postgresql_metrics-integration-testsfeature),测试覆盖了 RFC 中的核心承诺:

  • test_host / test_local:分别验证 TCP 连接与 Unix socket 连接(postgresql:///postgres?host=<socket>&user=vector&password=vector);
  • test_host_ssl:验证?sslmode=require+tls.ca_file的加密连接;
  • test_host_include_databases:配置["^vec", "gres$"],断言所有指标的db标签只能是vectorpostgres
  • test_host_exclude_databases:配置排除["^vec", "gres$"],断言没有任何指标带vector/postgresdb标签;
  • test_host_exclude_databases_empty:验证排除""(即排除datname IS NULL的记录);
  • test_host_include_databases_and_exclude_databases:includetemplate\d+且 excludetemplate0时,断言只保留template1—— 直接验证了 RFC 中"被显式排除的数据库即使被 include 也会被排除"的优先级规则。

测试同时断言:事件数大于 1、up指标值为 1、所有指标 namespace 为postgresql、每条指标都带endpointhost标签,且pg_stat_database_datidpg_stat_database_conflicts_confl_tablespace_totalpg_stat_bgwriter_checkpoints_timed_total三类来源的指标都存在——三条查询全部生效。

七、设计决策回顾:Prior Art、替代方案与取舍

7.1 已有实现参考(Prior Art)

RFC 列出并参考了社区已有的 PostgreSQL 采集实现:wrouesnel 的postgres_exporter、Telegraf 的postgresqlinput 插件,以及 collectd 的 PostgreSQL 插件。这些项目验证了"通过查询统计视图采集指标"这一路线的可行性,Vector 的指标命名也向其靠拢。

7.2 替代方案:外部采集器 + prometheus 源

RFC 认真考虑过一个替代方案:不新增 source,而是让用户运行 Telegraf 的 postgresql input 或 Prometheus 的 postgresql_exporter,再由 Vector 的prometheus源抓取结果。该方案能复用既有项目,但 RFC 明确否决了它,理由是这与 Vector 的"One Tool. All Data."原则相悖——Vector 的目标是替代 Telegraf,而不是依赖它。不过 RFC 也承认:已经在运行 Telegraf 或 PostgreSQL Exporter 的用户,完全可以继续走这条老路prometheus源依然可用。

7.3 缺点与未来工作

RFC 坦承该方案的缺点主要是新增 source 带来的额外维护与集成测试负担(因此仓库中配套了完整的集成测试矩阵)。RFC 还留下两个待办:

  • Outstanding Questions:实现过程中应关注是否采集pg_settings
  • Future Work:后续可扩展采集更多数据库指标,包括复制(Replication)指标、锁(Locks)指标、pg_stat_user_tables

八、总结

从 RFC 3603 到落地,postgresql_metrics源完整兑现了设计承诺:以 Rust 客户端直连 PostgreSQL、执行三条核心统计视图查询、按"表名_列名 + Prometheus 后缀"命名指标、以endpoint/host/db标签描述指标归属。与 RFC 草案相比,实现的演进主要体现在:endpoint升级为多实例的endpoints数组、include/exclude 从字面匹配升级为 POSIX 正则、指标命名统一为pg_stat_*前缀、新增 PostgreSQL 12+ 校验和指标、以及 endpoint 标签的凭据脱敏处理。

如果你正在用 Vector 构建可观测性管道,只需在配置中加上一个postgresql_metrics源,就能以极低代价把 PostgreSQL 的事务、缓冲、检查点、冲突等关键性能信号汇入统一的日志/指标管道,再配合 Vector 的 transform 与 sink 能力完成富化与分发。相关参考材料:配置结构体见 src/sources/postgresql_metrics.rs、采集逻辑见同文件collect_pg_stat_database等函数、指标语义与权限要求见 组件文档。

【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询