PostgreSQL码农集散地

这个项目治愈了PG的监控盲区

pg_datasentinel: 把 PostgreSQL 运维从“翻日志”推进到“库内可观测”

https://github.com/datasentinel/pg_datasentinel

很多 PostgreSQL 故障不是突然发生的,而是“早就有信号,只是没人及时看见”。

比如:

  • 某个 SQL 排序、Hash Join 打爆临时文件,但你只能事后翻 log_temp_files。
  • 某张大表 autovacuum 越跑越久,但 pg_stat_progress_vacuum 只看得到正在发生的现场。
  • 容器里 PostgreSQL 被 cgroup 限了 CPU、内存,但数据库内部并不知道自己真实的笼子有多大。
  • XID/MXID wraparound 风险临近,传统监控只告诉你“还剩多少”,但不能告诉你“按当前消耗速度还能撑多久”。
  • checkpoint 抖动导致延迟尖刺,但你需要从日志里拼出时间线和 I/O 压力。

pg_datasentinel 这个扩展想解决的,就是 PostgreSQL 可观测性里一个很现实的问题:

真正值钱的不是“多几个视图”,而是把原本散落在日志、/proc、cgroup、共享内存、瞬时进度视图里的信号,变成 DBA 可以直接 SQL 查询的现场证据。

一、背景:PostgreSQL 原生监控强,但有几个盲区

PostgreSQL 本身的观测能力并不弱。

我们有:

  • pg_stat_activity 看会话、SQL、等待事件。
  • pg_stat_database、pg_stat_bgwriter、pg_stat_all_tables 看全局和对象级统计。
  • pg_stat_progress_vacuum、pg_stat_progress_analyze 看正在执行的维护任务。
  • 日志参数如 log_temp_files、log_checkpoints、log_autovacuum_min_duration 记录关键事件。
  • pg_stat_slru、pg_stat_io 等新版本视图继续补齐内部 I/O 观察能力。

但生产环境里,问题往往出在“跨层信息割裂”。

数据库知道 SQL,操作系统知道进程内存,容器知道 cgroup 限额,日志知道历史事件,共享内存知道 checkpoint 统计。它们分别存在,不在一个 SQL 查询平面上。

这会带来一个典型问题:
DBA 不是没数据,而是数据分散、时效不一致、关联成本高。

二、痛点:传统 PostgreSQL 运维经常卡在“证据链断裂”

1. pg_stat_activity 看得到 SQL,看不到 backend 内存

pg_stat_activity 能告诉你哪个 PID 正在跑什么 SQL、状态是什么、等什么锁,但它不告诉你这个 backend 当前 RSS/PSS 内存占用。

排查“某个连接是不是吃了大量内存”时,传统方式通常是:

ps -o pid,rss,cmd -p <pid>  
cat /proc/<pid>/status  
cat /proc/<pid>/smaps_rollup  

然后再和 pg_stat_activity.pid 手工关联。

这对紧急现场不友好,也很难让普通监控账号安全访问。

2. 临时文件通常靠日志,实时关联弱

PostgreSQL 的 log_temp_files 很有用,但它输出在日志里。传统做法是采集日志到 ELK、Loki、Splunk,再按 PID、用户、库名聚合。

问题是:

  • 依赖外部日志系统。
  • SQL 现场和日志事件关联需要额外处理。
  • 只能看“已经写完并记录的临时文件”,不容易看当前 backend 正打开的临时文件规模。

3. autovacuum/analyze 的历史信息不够结构化

pg_stat_progress_vacuum 只看当前正在跑的 vacuum。跑完就没了。
autovacuum 的详细信息在日志里,但日志文本需要解析。

如果你想问:

  • 最近哪些表 vacuum 最慢?
  • 哪些 vacuum 是 aggressive vacuum?
  • 哪些 analyze 是自动触发,哪些是手工触发?
  • 哪些表维护成本最高?

传统方案往往是日志解析 + 外部存储 + 自己建 dashboard。

4. wraparound 风险只看距离,不看速度

XID wraparound 和 MXID wraparound 是 PostgreSQL 的硬风险。传统监控一般看:

SELECT datname, age(datfrozenxid)  
FROM pg_database  
ORDERBY age(datfrozenxid) DESC;  

这能看到“离危险还有多远”,但不能很好回答:

按现在事务消耗速度,还有多久进入 aggressive vacuum?还有多久到 wraparound 红线?

对 DBA 来说,“距离”不如“ETA”直接。
一个系统剩 5 亿 XID,如果 TPS 很低,可能不紧急;如果事务消耗速度极高,就完全是另一回事。

5. 容器化 PostgreSQL 的资源边界在数据库外面

在 Kubernetes、Docker、OpenShift 里,PostgreSQL 看到的是 Linux 系统,但真正生效的是 cgroup 限额。

传统监控可能会从 Node Exporter、cAdvisor、Kubernetes metrics 侧看 CPU/memory limit,但 PostgreSQL 内部查询不到:

  • 当前容器 CPU quota 是多少?
  • memory hard limit 是多少?
  • cgroup 当前内存使用多少?
  • CPU pressure 是否明显?

这会导致 DBA 看数据库指标,SRE 看容器指标,双方需要对表。

三、传统方案:不是不能做,而是链路长、成本高

传统 PostgreSQL 可观测方案一般由几块组成:

目标
传统方案
问题
看会话 SQL
pg_stat_activity
缺少 backend 内存、当前临时文件占用
看进程内存
ps
、/proc、Node Exporter
需要和 PID 手工关联
看临时文件
log_temp_files
 + 日志采集
事件在日志系统,不在数据库查询平面
看 vacuum 历史
日志解析
文本解析成本高,结构化弱
看 checkpoint
log_checkpoints
、pg_stat_bgwriter
细粒度事件需要日志或额外采集
看 wraparound
age()
 + 静态阈值
缺少基于消耗速率的 ETA
看容器资源
cAdvisor、K8S metrics、node exporter
与 SQL 现场割裂

这些方案不是错,而是偏“外部观测”。
外部观测适合长期存储、告警、统一 dashboard,但对 DBA 现场诊断来说,第一反应往往还是想进数据库执行 SQL。

pg_datasentinel 的价值就在这里:它把一部分关键证据拉回 PostgreSQL 内部。

四、pg_datasentinel 的方案:共享内存 Ring Buffer + SQL 视图

pg_datasentinel 是 PostgreSQL 15+ 的扩展,必须通过:

shared_preload_libraries = 'pg_datasentinel'  

预加载。

它的核心机制可以概括为四句话:

  1. 通过 hook 截获 PostgreSQL 关键日志事件。
  2. 把 vacuum、analyze、temp file、checkpoint、XID/MXID snapshot 写入共享内存 ring buffer。
  3. 通过 SQL 视图暴露结构化观测结果。
  4. 不启动后台 worker,主要依赖 PostgreSQL hook、共享内存、LWLock 和系统文件读取。

README 给出的架构如下:

shared_preload_libraries  
        |  
        v  
   _PG_init()  
        |  
        +-- GUC 参数  
        +-- shmem_request_hook  
        +-- shmem_startup_hook  
        +-- emit_log_hook  
        +-- ProcessUtility_hook  

它不是一个全量监控系统,也不是 Prometheus 的替代品。
更准确地说,它是 PostgreSQL 内部的“近场观测增强层”。

五、核心能力拆解

1. ds_stat_activity:给 pg_stat_activity 补上内存和临时文件

ds_stat_activity 扩展了 pg_stat_activity,额外提供:

  • rss_memory_bytes
  • pss_memory_bytes
  • temp_bytes
  • PostgreSQL 18+ 的 plan_id

其中:

  • RSS 来自 /proc/<pid>/statm。
  • PSS 来自 /proc/<pid>/smaps_rollup,需要开启 pg_datasentinel.enable_pss_memory = on。
  • 当前临时文件大小来自 /proc/<pid>/fd/。
  • plan_id 在 PostgreSQL 18+ 可配合 pg_store_plans fork 观察当前执行计划。

典型用法:

SELECT
    pid,  
    usename,  
    datname,  
    state,  
    wait_event_type,  
    wait_event,  
    pg_size_pretty(rss_memory_bytes) AS rss,  
    pg_size_pretty(pss_memory_bytes) AS pss,  
    pg_size_pretty(temp_bytes)       AS temp,  
left(query, 120)                 ASquery
FROM ds_stat_activity  
WHERE state = 'active'
ORDERBY rss_memory_bytes DESCNULLSLAST;  

这类能力非常适合现场排查:

  • 哪个 active backend 内存最高?
  • 哪个会话正在占用临时文件?
  • 某个 SQL 是否触发了大排序、大 Hash、大物化?

注意:README 明确说明该能力依赖 Linux 的 /proc。如果 /proc 不可访问,对应字段会是 NULL。

2. ds_container_resources:让数据库自己知道 cgroup 边界

容器环境里,ds_container_resources 返回一行,显示:

  • cpu_limit
  • cpu_pressure_pct_60s
  • mem_limit_bytes
  • mem_used_bytes
  • cgroup_version

查询示例:

SELECT
    cgroup_version,  
    cpu_limit,  
    cpu_pressure_pct_60s,  
    pg_size_pretty(mem_limit_bytes) AS memory_limit,  
    pg_size_pretty(mem_used_bytes)  AS memory_used  
FROM ds_container_resources;  

这对 Kubernetes 里的 PostgreSQL 很有价值。

举个场景:
业务说数据库慢,DBA 看 pg_stat_activity 发现 SQL 并不多,锁也不明显。传统上还要去看 Pod limit、node pressure、container memory。现在至少可以先在数据库里确认:

  • PostgreSQL 被限制成几核?
  • 当前内存使用是否接近 cgroup limit?
  • cgroup v2 下 CPU PSI 是否升高?

这能减少 DBA 和 SRE 之间来回对账的时间。

3. ds_wraparound_risk:从“剩余距离”变成“风险 ETA”

这是我认为 pg_datasentinel 最有价值的功能之一。

它维护一个 ds_xid_snapshots ring buffer,最多 504 个快照。按 README 描述,大约是 21 天历史,最多每小时采一次,通常在 checkpoint 时采样。

ds_wraparound_risk 会返回一行,把 XID 和 MXID 风险统一暴露出来:

  • 距离 aggressive vacuum 还有多少 XID/MXID。
  • 距离 wraparound 还有多少 XID/MXID。
  • 当前估算的 XID/MXID 消耗速率。
  • 到 aggressive vacuum 的 ETA。
  • 到 wraparound 的 ETA。
  • 哪个数据库最接近风险。

示例:

SELECT
    eta_aggressive_vacuum_fmt,  
    eta_wraparound_fmt,  
    datname,  
    snapshot_count,  
    snapshot_interval,  
    xids_to_aggressive_vacuum,  
    xids_to_wraparound,  
    mxids_to_aggressive_vacuum,  
    mxids_to_wraparound  
FROM ds_wraparound_risk;  

这个设计背后的判断是对的:
wraparound 风险不是静态阈值问题,而是“剩余距离 / 消耗速度”的动态问题。

如果没有速率,告警很容易两种极端:

  • 太早告警,大家疲劳。
  • 太晚告警,只剩救火。

不过也要注意边界:
README 说明如果少于 2 个 snapshot,ETA 为 NULL。所以这个能力不是安装后立刻就有完整判断,需要运行一段时间积累样本。

4. ds_vacuum_activity:把 vacuum 日志变成结构化事件

ds_vacuum_activity 捕获:

  • autovacuum LOG 消息。
  • manual VACUUM INFO 消息。

并解析出:

  • database/schema/table
  • heap pages
  • pages removed/remain/scanned
  • tuples removed/remain
  • user/sys CPU
  • elapsed
  • 是否 aggressive
  • 是否 automatic

查询慢 vacuum:

SELECT
    logged_at,  
    datname,  
    schemaname,  
    relname,  
    elapsed,  
    tuples_removed,  
    is_aggressive,  
    is_automatic  
FROM ds_vacuum_activity  
ORDERBY elapsed DESC
LIMIT20;  

这类视图的价值在于:
DBA 不再只看“现在谁在 vacuum”,而是可以看“最近一段时间哪些 vacuum 最重”。

适合回答:

  • 哪些表反复产生大量 dead tuples?
  • 哪些表 vacuum 时间最长?
  • 是否已经出现 aggressive vacuum?
  • 手工 vacuum 和 autovacuum 的效果差异如何?

5. ds_analyze_activity:观察统计信息维护

ds_analyze_activity 捕获:

  • autoanalyze LOG 消息。
  • manual ANALYZE INFO 消息。

可以查看:

SELECT
    logged_at,  
    datname,  
    schemaname,  
    relname,  
    elapsed,  
    sample_blks_total,  
    ext_stats_total,  
    child_tables_total,  
    is_automatic  
FROM ds_analyze_activity  
ORDERBY logged_at DESC
LIMIT20;  

在分区表、扩展统计、多租户场景里,analyze 成本有时也不低。
如果统计信息更新不及时,SQL 计划会漂;如果 analyze 太频繁,也会带来维护成本。这个视图能帮助 DBA 看到统计信息维护的实际行为。

6. ds_tempfile_activity:临时文件事件留在数据库里

临时文件通常是 SQL 执行过程中内存不足的信号,常见原因包括:

  • work_mem 不够。
  • 排序数据量太大。
  • Hash Join/Hash Aggregate 溢出。
  • CTE/materialize/临时中间结果过大。
  • 并发高,单个 SQL 看似可控,总体内存被放大。

ds_tempfile_activity 捕获 log_temp_files 日志事件:

SELECT
    logged_at,  
    username,  
    datname,  
    pid,  
    pg_size_pretty(bytes) ASsize,  
    message  
FROM ds_tempfile_activity  
ORDERBYbytesDESC
LIMIT20;  

它适合做两类分析:

  • 按用户/数据库找“临时文件大户”。
  • 结合 ds_stat_activity 找当前正在制造临时文件的 SQL。

例如:

SELECT
    t.logged_at,  
    t.username,  
    t.datname,  
    t.pid,  
    pg_size_pretty(t.bytes) AS tempfile_size,  
left(a.query, 120)      AS current_query  
FROM ds_tempfile_activity t  
LEFTJOIN ds_stat_activity a ON a.pid = t.pid  
ORDERBY t.bytes DESC
LIMIT20;  

注意:如果临时文件事件发生后 backend 已结束或 PID 被复用,关联结果需要谨慎解读。

7. ds_checkpoint_activity:checkpoint 事件结构化

ds_checkpoint_activity 捕获 checkpoint 和 restartpoint 完成事件,并且 README 明确说它直接从 PostgreSQL shared memory 的 CheckpointStats 读取指标,而不是解析日志文本。

可以看:

  • checkpoint 起止时间。
  • 写了多少 dirty buffers。
  • WAL segment added/removed/recycled。
  • write time。
  • sync time。
  • total time。
  • longest sync。
  • average sync。

查询慢 checkpoint:

SELECT
    logged_at,  
    total_time,  
    bufs_written,  
    write_time,  
    sync_time,  
    sync_rels,  
    longest_sync,  
    average_sync  
FROM ds_checkpoint_activity  
ORDERBY total_time DESC
LIMIT10;  

这对分析“周期性延迟尖刺”很有用。
如果 sync_time 或 longest_sync 特别高,可能要进一步检查存储延迟、checkpoint 参数、WAL 压力、后台写策略等。

8. ds_activity_summary:一眼看 ring buffer 是否有数据

这个视图返回一行,统计四类 ring buffer 的数量、最老时间、最新时间:

SELECT * FROM ds_activity_summary;  

适合做健康检查:

  • vacuum/analyze/tempfile/checkpoint 是否被捕获?
  • ring buffer 里是否有数据?
  • 最近一次事件是什么时候?
  • 日志参数是否生效?

六、效果对比:它改变的是排障路径,不是替代所有监控

下面这个对比更接近真实生产价值。

场景
传统路径
使用 pg_datasentinel 后
找高内存 backend
pg_stat_activity
 + ps/proc 手工关联
直接查 ds_stat_activity
找当前临时文件占用
查 /proc/<pid>/fd 或事后看日志
ds_stat_activity.temp_bytes
看历史 temp file
日志系统检索 log_temp_files
ds_tempfile_activity
 SQL 查询
看 vacuum 历史
解析 autovacuum 日志
ds_vacuum_activity
 结构化查询
看 analyze 历史
解析日志或猜测统计变化
ds_analyze_activity
看 checkpoint 抖动
查日志、外部采集
ds_checkpoint_activity
看 wraparound 风险
age()
 + 静态阈值
ds_wraparound_risk
 给出 ETA
看容器资源边界
跳到 K8S/cAdvisor/Node
ds_container_resources
 库内可查

一句话总结:

传统方案偏“多系统拼证据”,pg_datasentinel 偏“在数据库内先拿到第一手现场证据”。

它不会替代 Prometheus、Grafana、日志平台。
但它能显著缩短 DBA 在 PostgreSQL 内部完成第一轮定位的时间。

七、适合哪些场景

场景 1:容器化 PostgreSQL 运维

如果 PostgreSQL 跑在 Docker、Kubernetes、OpenShift 里,ds_container_resources 很实用。

推荐检查:

SELECT
    cgroup_version,  
    cpu_limit,  
    cpu_pressure_pct_60s,  
    pg_size_pretty(mem_limit_bytes) AS memory_limit,  
    pg_size_pretty(mem_used_bytes)  AS memory_used  
FROM ds_container_resources;  

如果 mem_used_bytes 接近 mem_limit_bytes,同时 backend RSS 偏高,需要进一步检查连接数、work_mem、并行查询、shared buffers、maintenance 操作。

场景 2:SQL 临时文件治理

先打开:

log_temp_files = 0  

然后查:

SELECT
    username,  
    datname,  
count(*)                         AS files,  
    pg_size_pretty(sum(bytes))        AS total_temp,  
    pg_size_pretty(max(bytes))        AS max_temp  
FROM ds_tempfile_activity  
GROUPBY username, datname  
ORDERBYsum(bytes) DESC;  

再查大文件明细:

SELECT
    logged_at,  
    username,  
    datname,  
    pid,  
    pg_size_pretty(bytes) ASsize,  
    message  
FROM ds_tempfile_activity  
ORDERBYbytesDESC
LIMIT20;  

治理方向通常是:

  • 优化 SQL,减少不必要排序、Hash、物化。
  • 给关键 SQL 建合适索引,避免大排序。
  • 谨慎调整 work_mem,不要只按单 SQL 算,要按并发和节点数放大。
  • 对批处理任务做资源隔离。

场景 3:autovacuum 治理

打开:

log_autovacuum_min_duration = 0  

查看慢 vacuum:

SELECT
    logged_at,  
    schemaname,  
    relname,  
    elapsed,  
    pages_scanned,  
    tuples_removed,  
    is_aggressive,  
    is_automatic  
FROM ds_vacuum_activity  
ORDERBY elapsed DESC
LIMIT20;  

查 aggressive vacuum:

SELECT
    logged_at,  
    datname,  
    schemaname,  
    relname,  
    elapsed,  
    tuples_removed,  
    message  
FROM ds_vacuum_activity  
WHERE is_aggressive  
ORDERBY logged_at DESC;  

如果出现 aggressive vacuum,不要只想着“加大 autovacuum”。要看:

  • 表是否长期没有被正常 vacuum。
  • 是否有长事务阻止 dead tuple 清理。
  • 是否有逻辑复制槽、prepared transaction、老快照拖住 xmin。
  • 表级 autovacuum 参数是否合理。
  • 是否存在高频 UPDATE/DELETE 热点表。

场景 4:wraparound 风险预警

查询:

SELECT
    eta_aggressive_vacuum_fmt,  
    eta_wraparound_fmt,  
    datname,  
    snapshot_count,  
    snapshot_interval,  
    xids_to_aggressive_vacuum,  
    xids_to_wraparound,  
    mxids_to_aggressive_vacuum,  
    mxids_to_wraparound  
FROM ds_wraparound_risk;  

可以设计告警逻辑:

SELECT *  
FROM ds_wraparound_risk  
WHERE eta_wraparound < interval'7 days'
OR eta_aggressive_vacuum < interval'1 day';  

实际阈值要按业务而定。
高 TPS 系统应该更保守,因为 XID 消耗速度变化可能很快。

场景 5:checkpoint 抖动分析

查询慢 checkpoint:

SELECT
    logged_at,  
    total_time,  
    bufs_written,  
    write_time,  
    sync_time,  
    longest_sync  
FROM ds_checkpoint_activity  
ORDERBY total_time DESC
LIMIT20;  

如果 write_time 高,关注写入压力。
如果 sync_time 或 longest_sync 高,关注 fsync、存储延迟、单 relation sync 抖动。
如果 checkpoint 过于频繁,检查 max_wal_size、checkpoint_timeout、WAL 生成速率。

八、实操:安装、配置、验证

1. 编译安装

要求:

  • PostgreSQL 15+
  • pg_config 在 PATH

安装:

make  
sudo make install  

2. 修改 postgresql.conf

最小配置:

shared_preload_libraries = 'pg_datasentinel'  

要捕获 autovacuum/autoanalyze:

log_autovacuum_min_duration = 0  

要捕获临时文件:

log_temp_files = 0  

checkpoint 日志默认开启,建议确认:

log_checkpoints = on  

推荐初始配置:

shared_preload_libraries = 'pg_datasentinel'  

log_autovacuum_min_duration = 0  
log_temp_files = 0  
log_checkpoints = on  

pg_datasentinel.enabled                   = on  
pg_datasentinel.max_entries               = 1000  
pg_datasentinel.maintenance_force_verbose = off  
pg_datasentinel.ignore_system_schemas     = on  
pg_datasentinel.enable_pss_memory         = off  

修改 shared_preload_libraries 后需要重启 PostgreSQL。

3. 创建扩展

重启后执行:

CREATE EXTENSION pg_datasentinel;  

4. 授权监控用户

扩展安装时会创建 ds_reader 角色,并把视图查询权限授给它。

GRANT ds_reader TO monitoring_user;  

这样普通监控账号可以查询这些观测视图,而不需要额外逐个授权。

5. 验证是否采集到数据

先看总览:

SELECT * FROM ds_activity_summary;  

检查活动会话增强信息:

SELECT
    pid,  
    usename,  
    state,  
    pg_size_pretty(rss_memory_bytes) AS rss,  
    pg_size_pretty(pss_memory_bytes) AS pss,  
    pg_size_pretty(temp_bytes)       AS temp  
FROM ds_stat_activity  
ORDERBY rss_memory_bytes DESCNULLSLAST
LIMIT20;  

检查 wraparound 风险:

SELECT
    eta_aggressive_vacuum_fmt,  
    eta_wraparound_fmt,  
    snapshot_count,  
    snapshot_interval  
FROM ds_wraparound_risk;  

如果 snapshot_count < 2,ETA 为空是正常的,需要等待快照积累。

6. 清理 ring buffer

清空全部:

SELECT ds_activity_reset_all();  

分别清理:

SELECT ds_vacuum_activity_reset();  
SELECT ds_analyze_activity_reset();  
SELECT ds_tempfile_activity_reset();  
SELECT ds_checkpoint_activity_reset();  
SELECT ds_xid_snapshots_reset();  

九、容量与开销:重点看 max_entries

pg_datasentinel 使用共享内存 ring buffer。
当 buffer 满了,最旧记录会被覆盖,保留最近 pg_datasentinel.max_entries 条事件。

README 给出的共享内存占用大致如下:

max_entries
总共享内存占用
100
~600 kB
1000
~5.6 MB
5000
~28 MB
10000
~56 MB

初始建议:

  • 普通生产库:1000 起步。
  • 高频 temp file 或 autovacuum 事件很多的库:可以提高到 5000。
  • 如果需要长期历史,不要指望 ring buffer,应该外接 Prometheus、定时采集表或日志平台。

注意:XID snapshot buffer 固定 504 条,不随 max_entries 增长,大约覆盖 21 天。

十、边界条件:不要把它当万能监控

这个扩展的设计很实用,但也有清晰边界。

1. 必须预加载

它依赖 shared_preload_libraries,所以启用需要重启。
这意味着它更适合纳入标准 PostgreSQL 部署模板,而不是临时救火时才装。

2. 部分能力 Linux only

ds_stat_activity 的 RSS/PSS/temp file 依赖 /proc,README 明确说明 Linux only。
非 Linux 或 /proc 不可访问时,字段可能为 NULL。

3. 日志解析依赖英文关键词

ds_vacuum_activity 和 ds_analyze_activity 解析日志文本,README 说明如果 PostgreSQL 使用翻译后的 message locale,解析会失效。

生产建议保持数据库日志语言为英文,尤其是需要机器解析时。

4. ring buffer 不是长期存储

满了会覆盖旧记录。
这对“最近现场”很好,对“审计级历史”不够。

如果你要长期趋势,应定期采集这些视图到外部时序库或审计库。

5. PSS 更准,但更贵

pg_datasentinel.enable_pss_memory = on 会读取每个 backend 的 /proc/<pid>/smaps_rollup。
PSS 比 RSS 更接近真实内存分摊,但 backend 很多时可能有额外开销。

建议:

  • 默认关闭。
  • 排查内存问题时短时间打开。
  • 高连接数实例谨慎长期打开。

十一、推荐落地方式

我建议把 pg_datasentinel 当成 PostgreSQL 运维的“库内黑匣子”。

基础版

适合大多数生产库:

shared_preload_libraries = 'pg_datasentinel'  
log_autovacuum_min_duration = 0  
log_temp_files = 0  
log_checkpoints = on  

pg_datasentinel.max_entries = 1000  
pg_datasentinel.ignore_system_schemas = on  
pg_datasentinel.enable_pss_memory = off  

日常看:

SELECT * FROM ds_activity_summary;  
SELECT * FROM ds_wraparound_risk;  

排障版

遇到内存或临时文件问题:

SELECT
    pid,  
    usename,  
    datname,  
    state,  
    pg_size_pretty(rss_memory_bytes) AS rss,  
    pg_size_pretty(temp_bytes)       AS temp,  
left(query, 200)                 ASquery
FROM ds_stat_activity  
ORDERBY rss_memory_bytes DESCNULLSLAST;  

遇到 vacuum 风险:

SELECT
    logged_at,  
    schemaname,  
    relname,  
    elapsed,  
    tuples_removed,  
    is_aggressive,  
    is_automatic  
FROM ds_vacuum_activity  
ORDERBY elapsed DESC
LIMIT50;  

遇到 checkpoint 抖动:

SELECT
    logged_at,  
    total_time,  
    bufs_written,  
    write_time,  
    sync_time,  
    longest_sync  
FROM ds_checkpoint_activity  
ORDERBY total_time DESC
LIMIT20;  

监控集成版

定时采集这些视图:

  • ds_wraparound_risk
  • ds_activity_summary
  • ds_container_resources
  • ds_tempfile_activity 增量
  • ds_checkpoint_activity 增量
  • ds_vacuum_activity 增量

注意 ring buffer 会覆盖,采集周期不要太长。

十二、结论

pg_datasentinel 的定位很清楚:
它不是一个大而全的监控平台,而是 PostgreSQL 内部可观测性的补强插件。

它解决的是 DBA 很熟悉但一直麻烦的问题:

  • backend 内存和 SQL 现场分离。
  • 临时文件在日志里,不在 SQL 查询里。
  • vacuum/analyze 历史缺少结构化视图。
  • checkpoint 抖动需要翻日志。
  • wraparound 风险缺少速率 ETA。
  • 容器资源限制在数据库外部。

它的工程取舍也很明确:

  • 用共享内存 ring buffer,换取低依赖、近实时、SQL 可查。
  • 用 hook 捕获事件,避免额外后台 worker。
  • 用 /proc 和 cgroup 补齐 PostgreSQL 原生视图看不到的系统层信息。
  • 不承诺长期历史,长期趋势交给外部监控系统。

如果你的 PostgreSQL 已经运行在容器里,或者经常排查 temp file、autovacuum、checkpoint、wraparound 这类问题,pg_datasentinel 值得放进测试环境验证。

最后一句话:

PostgreSQL 生产运维最怕的不是问题复杂,而是问题发生时证据不在一个地方。pg_datasentinel 的价值,就是把一部分关键证据提前放回数据库里,让 DBA 用 SQL 先把现场看清楚。