跳至内容

25.5 Pigsty 可观测体系

Pigsty 提供的是一套 PostgreSQL 可观测参考实现,而不是另一套数据库语义。

PostgreSQL system views
  -> pg_exporter metrics
      -> VictoriaMetrics time series
          -> recording/alert rules
              -> Grafana dashboard
                  -> Alertmanager route

PostgreSQL / PgBouncer / Patroni / pgBackRest / host logs
  -> Vector
      -> VictoriaLogs
          -> Grafana exploration

application traces, when instrumented
  -> VictoriaTraces
      -> Grafana exploration

每一层都可能:

-正常工作; -延迟; -丢数据; -标签漂移; -权限不足; -版本升级; -将一个原生值重新聚合; -把缺失误写成零。

所以“Pigsty 面板显示”仍要回到 PostgreSQL 和应用合同复核。

当前官方入口:

25.5.1 采集、存储、规则、面板与通知链

metrics 采集

Pigsty PostgreSQL 监控主要汇集:

PostgreSQL   pg_exporter, usually 9630
PgBouncer    exporter, usually 9631
Patroni      REST/metrics, usually 8008 or HTTPS target
Node         node_exporter, usually 9100
HAProxy      exporter/stats
other infra  etcd, Vector, Grafana, Alertmanager, storage self metrics

实际端口、TLS 和访问控制以 inventory/rendered config 为准,不能把教学默认值 当网络策略。

沙箱 pg-test-1 的只读探测:

pg_exporter PostgreSQL   9630
pg_exporter PgBouncer    9631
Patroni API              8008
node_exporter            9100

探测 endpoint 可证明 process/HTTP 返回,不能证明:

-所有 SQL collector 成功; -所有 database 被发现; -权限足够; -series 新鲜; -rule 查询正确; -用户服务健康。

target registration

Pigsty 文档中的 PostgreSQL target 文件沿用:

/etc/prometheus/targets/pgsql/

命名不意味着当前存储一定是旧版 Prometheus;Pigsty v4 的当前栈使用 VictoriaMetrics。target 记录:

labels:
  cls: pg-test
  ins: pg-test-1
  ip: 10.10.10.11
targets:
  - 10.10.10.11:9630
  - 10.10.10.11:9631
  - 10.10.10.11:8008

这个 external identity 会与 raw exporter metric-specific labels 合并。

raw exporter 与存储后的 label 不同

直接访问 :9630/metrics

pg_activity_count{datname="test",state="idle"} 1

写入 VictoriaMetrics 后还会带:

cls="pg-test"
ins="pg-test-1"
ip="10.10.10.11"
instance="10.10.10.11:9630"
job="pgsql"

因此调试 label 漂移要分别看:

  1. exporter raw output;
  2. target/relabel config;
  3. storage series;
  4. recording result。

只看一层可能误判 producer。

pg_exporter 是 SQL 到 metric 的编译层

它的配置定义:

query
minimum PostgreSQL version
timeout
cache
tag columns
metric columns
type
description
scale

同一个 view 可以变成多条 metric。升级 PostgreSQL/pg_exporter/Pigsty 后:

-列可能增加; -metric 名可能变化; -tag 可能变化; -旧 dashboard/rule 可能失配; -权限 schema 可能变化。

生产需要 versioned config 和 compatibility test。

exporter 内建最小信号

pg_exporter 即使不加载大量自定义 collector,也有基本自描述/连通信号,例如:

pg_up
pg_version
pg_in_recovery
pg_exporter_build_info

它们适合判断:

  • exporter process/target;
  • database connectivity;
  • server version;
  • recovery role。

pg_up=1 不证明所有高成本 collector、扩展 view 或 application database 可读。

management endpoint 要保护

pg_exporter 的管理/配置能力不应无条件暴露给业务网络。即使 /metrics 可被 监控系统读取,也要区分:

scrape read
health read
configuration reload
profiling/debug

使用:

-网络 ACL; -reverse proxy auth/TLS; -bind address; -least-privilege service; -管理面关闭或隔离; -access log/audit。

不要把“exporter 没有业务写权限”等同于“管理 endpoint 无风险”。

metrics storage

Pigsty v4 使用 VictoriaMetrics 保存时序。它负责:

  • ingest; -time-series index; -MetricsQL/PromQL-compatible query; -retention; -recording result; -rule state相关读写; -API。

本章快照:

VictoriaMetrics version          1.148.0
total series                     44,842
total label-value pairs          387,724
distinct metric names            3,078

这些不是“监控容量还剩多少”的答案。还要看:

  • ingest rate; -data size; -retention; -series churn; -query latency; -cache; -disk; -backup; -self errors; -cardinality trend。

logs storage

Vector 收集:

/pg/log/postgres
/pg/log/pgbouncer
/pg/log/patroni
/pg/log/pgbackrest
host/service logs

发送到 VictoriaLogs。沙箱 health/version 证明:

VictoriaLogs v1.52.0 endpoint healthy

本章没有读取任何日志 body,因此没有证明:

-所有 source 被采集; -parser 正确; -redaction 正确; -retention 正确; -query role 正确; -incident window 有完整日志。

endpoint health 只是第一层。

traces storage

沙箱有:

VictoriaTraces v0.9.4 endpoint healthy

但没有声称 pg36_shop 发出 application span。三件事要分开:

trace backend exists
collector receives data
specific service has complete/useful instrumentation

没有第三项,不能在架构图上把 trace 当成已覆盖。

rule evaluation

VMAlert:

-读取规则; -向 datasource 查询; -执行 recording/alert; -remote-write recording/state; -把 alert 发给 Alertmanager; -暴露自监控 API/metric。

快照:

VMAlert version         1.148.0
groups                  17
alert rules             50
recording rules         698
group/rule errors       0
current firing alerts   0

这些是 Pigsty 已有规则。第 25 章的:

18 recording + 13 alert

只经过隔离工具测试,未放进在线 VMAlert。

dashboard

Grafana 将三类 data source 组织为:

PGSQL   PostgreSQL metrics
PGCAT   PostgreSQL catalog/direct datasource
PGLOG   PostgreSQL-related logs

当前 Pigsty 文档列出约 26 个 PostgreSQL dashboard,按 overview、cluster、 instance、database 等层级组织。

dashboard 的优势:

-导航与变量; -版本化 panel; -多层关联; -time range; -release annotation; -top-N; -drill-down。

它的边界:

-panel query 可能与告警不同; -变量默认值可能聚合错 scope; -time range/step 改变结果; -downsampling 隐藏 spike; -颜色阈值不等于 SLO; -Grafana cache/query error; -直接 PG datasource 可能与 metric snapshot 不同。

Alertmanager

Alertmanager 负责:

-group; -dedup; -route; -inhibition; -silence; -receiver integration; -repeat。

它不负责决定 expression 是否有业务意义。VMAlert 能成功发送给 Alertmanager, 也不等于外部 receiver 已收到。

快照:

Alertmanager 0.33.1
current alerts 0
notification failure counters nonzero series 0

没有 receipt canary,真实 delivery 仍是盲区。

端到端链路的健康层

证据
producerPostgreSQL view/metric raw output
scrapetarget up、scrape duration/error
ingestnewest sample time、storage health
queryexact expression result、error
ruleevaluation state/error/duration
notifierVMAlert notifier success/error
routeAlertmanager matched receiver
integrationexternal API accepted
receipthuman/system acknowledgment

“面板有数据”通常证明到 query;“Alertmanager 无失败”最多证明部分 notifier/ integration 路径;receipt 需要独立 canary。

Pigsty 三种监控模式

当前文档:

模式场景可见能力
RDS / Basic只有可连接 PGURLPG metrics,缺 host/pool/LB/log
Managed现有数据库且可 SSH/sudoPG + node,其他可选
Full / StandardPigsty 创建并管理PG/pool/LB/node/log 完整参考栈

这直接影响诊断:

RDS mode has no node metrics
  -> cannot conclude host normal from absent panel

RDS mode has no local PG logs
  -> PGLOG absence is expected capability gap

Managed optional pool
  -> check inventory before diagnosing queue

dashboard 应根据 capability 隐藏/标记 unavailable,而不是显示绿色零。

平台版本是合同的一部分

本章快照:

Pigsty           v4.4.0
PostgreSQL       18.4
pg_exporter      v1.4.0
VictoriaMetrics  v1.148.0
VictoriaLogs     v1.52.0
VictoriaTraces   v0.9.4
Alertmanager     0.33.1

旧教程若仍写 Prometheus、Loki 等历史组件,不能直接套用 v4。规则语法具有兼容 目标,但 storage、API、自监控 metric 和运行特性必须按实际版本核对。

25.5.2 以指标语义定位集群、实例、数据库和查询

三个稳定基础身份

Pigsty 使用:

cls   cluster
ins   instance/member
ip    node address

同一个:

cls=pg-test
ins=pg-test-1
ip=10.10.10.11

可关联 PostgreSQL、PgBouncer、Patroni、node、HAProxy 与 logs。

它们解决的是平台身份,不自动解决业务身份:

service
environment
operation_class
objective_id

需要应用层单独提供。

为什么同时保留 clsinsip

label用途变化风险
cls服务集群聚合cluster rename/migration
ins稳定成员角色rebuild/replacement
ipnode/网络关联IP 重用/迁移

IP 不是唯一永久身份;instance 也可能重建。诊断包同时保存 topology event 和 captured_at。

instance 与 exporter endpoint

storage series 还有:

instance="10.10.10.11:9630"
job="pgsql"

这个 instance 是 scrape target endpoint,不一定等于 Pigsty ins。写 query 时明确:

sum by (cls, ins, ip) (...)

不要误用 Prometheus convention 的 instance 代替 Pigsty member identity。

cluster 级

常见问题:

-集群是否有 primary; -多少 member exporter 可达; -transaction/WAL 总 workload; -aggregate capacity; -replication topology; -entrypoint health。

查询示意:

min by (cls) (pg_up)
sum by (cls) (rate(pg_db_xact_total[5m]))
max by (cls) (pg_lag)

第一条 min(pg_up) 只是“是否每个目标 up”,不是 service availability。

instance 级

常见:

role
activity/wait
checkpointer
I/O
WAL/archive
replication sender/receiver
autovacuum
host resource

本章现场:

pg_in_recovery{cls="pg-test"}

可区分:

pg-test-1 0 primary
pg-test-2 1 replica
pg-test-3 1 replica

但角色应与 Patroni、direct SQL 和 topology event 交叉,特别是在切换窗口。

database 级

raw exporter:

pg_activity_count{datname="test",state="idle"}
pg_db_deadlocks{datname="test"}
pg_db_temp_bytes{datname="test"}

storage 加平台身份后,可以:

sum by (cls, datname, state) (
  pg_activity_count
)

database label 是 logical database 名;多个 cluster 可能都有 postgrestest,不能丢 cls

query 级

现场 pg_query_calls

pg_query_calls{
  datname="postgres",
  query="-1567903771303523871"
} 214

这里 query 的值是 numeric queryid 字符串,不是 SQL text。语义:

metric label name  query
metric label value queryid
cardinality bound  pg_stat_statements.max per tracking dimensions

查询时:

topk(
  20,
  sum by (cls, datname, query) (
    rate(pg_query_exec_time[5m])
  )
)

具体 metric 名与单位由当前 pg_exporter.yml 定义,使用前查看 HELP 和 dashboard query;不要凭记忆假设 _exec_time 是 counter 还是 seconds。

query label 仍有 cardinality 成本

即使不是 raw text:

-pg_stat_statements.max=10000; -多个 database/user/toplevel; -多个 instance; -旧 series retention; -query churn;

仍可产生大量 series。current snapshot 的 top label cardinality 中 recording 有 698 个值,也说明 rule identity 自身会形成规模。

需要:

-只保留需要的 query metric; -记录 dealloc; -控制 dynamic SQL shape; -top-N dashboard; -retention; -不要把 queryid 复制到 page grouping。

exact metric names 来自当前 exporter

沙箱 pg_exporter v1.4.0 实际暴露:

pg_activity_count
pg_activity_max_conn_duration
pg_activity_max_duration
pg_activity_max_tx_duration

pg_archiver_failed_count / failed_time
pg_archiver_finish_count / finish_time

pg_checkpointer_timed / req / done
pg_checkpointer_write_time / sync_time / buffers_written

pg_db_numbackends / deadlocks / temp_bytes / xact_*

pg_io_read_bytes / write_bytes / extend_bytes
pg_io_read_time / write_time / fsyncs ...

pg_lag
pg_repl_*
pg_query_calls / exec_time / io_time / rows / blocks / wal_bytes
pg_table_age / n_dead_tup / size / bloat estimates

这是版本化现场证据,不是永久 API。升级时用:

curl --fail --silent http://TARGET:9630/metrics

仅在受控网络检查 # HELP# TYPE 与 label,不要把 endpoint 公网暴露。

pg_lagpg_repl_replay_diff

现场:

pg_lag                   all observed 0
pg_repl_replay_diff      two downstream series 0

前者可能是 time-like convenience metric,后者是 replay distance;具体实现要 查 exporter SQL。两者都不能代替 commit-correlated SLI。

archiver metric 命名的实现差异

native view:

archived_count
last_archived_time
failed_count
last_failed_time

exporter 观察名:

finish_count / finish_time
failed_count / failed_time

规则作者要确认:

-finish_time 是 Unix seconds; -counter type; -primary/replica exposure; -reset; -last success after failure; -missing on replica。

不能把 native column 名直接猜成 metric 名。

label join 的显式性

组合两个指标:

A
and on (service, operation_class, environment)
B

必须显式声明 join key。默认所有共同 label 会参与匹配;一侧多一个 insjob,结果可能空。

调试步骤:

  1. 分别查询 A/B;
  2. 列 label sets; 3.确定语义上应该一对一、多对一还是聚合; 4.先 aggregate; 5.用 on/ignoring; 6.检查重复结果。

不要通过删除 identity 修复 join

错误:

sum(A) / sum(B)

它可能跨 cluster/environment 聚合,虽然“有数了”,语义已丢失。

正确做法先确定 service scope,再用相同 bounded dimensions。

scrape freshness

本章正式采集使用:

timestamp(pg_up)
timestamp(pg_exporter_up)
timestamp(vmalert_iteration_total)
timestamp(alertmanager_notifications_failed_total)

并计算 newest sample age,要求不超过 180 秒。up=1 但最后样本很旧,不应视为 健康;storage 里旧值可能仍可查询。

current app SLI absence

查询:

count({__name__=~"pg36_shop_.*"}) by (__name__)

结果 series 为 0。结论:

application SLI not implemented in live sandbox

不是:

zero errors
zero latency
100% availability

这一区分贯穿全章。

25.5.3 面板结论回到 SQL、日志与主机事实复核

dashboard 是索引,不是裁判

一个 panel 应能回答:

query expression
data source
scope variables
unit
legend identity
window/step
missing behavior
link to native evidence

看不到 query 的 panel 不适合支撑高风险动作。

先检查 dashboard scope

事故前先读变量:

cluster
instance
database
query
time range
timezone
refresh interval

常见错误:

-选了 pg-meta 而非 pg-test; -instance 仍是旧 primary; -database 选 postgres 而用户在 test; -time range 不包含 onset; -browser timezone 与事件 UTC 不同; -panel 聚合 all instance; -Grafana repeat panel 隐藏一个 member。

本章 SSH 还遇到一个真实访问路径陷阱:工作站对多个逻辑 IP 的 SSH port forward 落到同一元节点。只有进入元节点再连接真实沙箱网络,并验证 hostname + Patroni scope + cluster_name,才证明查询了 pg-test-1

从 availability panel 回到 event

panel:

availability bad ratio 1h / 5m

复核:

  1. source metric 是否存在;
  2. eligible/good selector;
  3. event count;
  4. low traffic;
  5. release/route;
  6. missing;
  7. reconciliation; 8.独立 probe。

如果 app metric series 根本不存在,panel 不应该显示绿色 0。

从 connection panel 回到 activity

panel 显示连接增加:

SELECT
  backend_type,
  datname,
  state,
  wait_event_type,
  count(*)
FROM pg_stat_activity
GROUP BY backend_type, datname, state, wait_event_type
ORDER BY backend_type, datname, state, wait_event_type;

再看:

-PgBouncer client/server/wait; -HAProxy queue/session; -application pool config event; -connection churn log; -transaction age; -max connection headroom。

不要直接提高 max_connections

从 lock panel 回到 blocker graph

SELECT
  a.pid AS waiting_pid,
  a.datname,
  a.application_name,
  a.wait_event,
  clock_timestamp() - a.query_start AS wait_age,
  pg_blocking_pids(a.pid) AS blockers
FROM pg_stat_activity AS a
WHERE cardinality(pg_blocking_pids(a.pid)) > 0
ORDER BY a.query_start;

然后在受限会话按 queryid/application 找 owner。panel 的 lock count 不足以 授权 terminate。

从 I/O panel 回到两个系统

PostgreSQL:

SELECT backend_type, object, context,
       sum(read_bytes), sum(read_time),
       sum(write_bytes), sum(write_time)
FROM pg_stat_io
GROUP BY backend_type, object, context;

主机:

device latency/queue/throughput
filesystem capacity
memory/page cache pressure
other process activity

只有两层同窗,才能区分 PG workload 与 host path。

从 WAL/replication panel 回到原生位置

SELECT
  application_name,
  state,
  sync_state,
  pg_wal_lsn_diff(sent_lsn, replay_lsn) AS gap_bytes,
  write_lag,
  flush_lag,
  replay_lag
FROM pg_stat_replication;

再检查:

-Patroni role/timeline; -receiver; -slot; -WAL generation rate; -read routing; -commit token probe。

不要仅凭 panel 的“lag 0”关闭 freshness incident。

从 archive panel 回到时间顺序

SELECT *
FROM pg_stat_archiver;

问:

new failure or historical?
last success after failure?
WAL currently generated?
archive queue progressing?
pgBackRest check?
restore evidence age?

沙箱就是 failed_count=21 但后来成功。panel 若只把 total failed 画红,会永久 误报。

从 slow query panel 回到 reset

先看:

SELECT *
FROM monitor.pg_stat_statements_info;

再看 queryid 聚合:

SELECT
  dbid, userid, queryid, toplevel,
  calls, total_exec_time, mean_exec_time,
  shared_blks_read, temp_blks_written, wal_bytes,
  stats_since, minmax_stats_since
FROM monitor.pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 50;

检查:

-reset; -dealloc; -member/failover; -calls vs mean; -track planning/timing; -dashboard delta 算法; -query text 权限。

从 vacuum panel 回到对象与 blocker

SELECT
  schemaname,
  relname,
  n_live_tup,
  n_dead_tup,
  n_mod_since_analyze,
  last_autovacuum,
  last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 50;

再查:

-progress; -old transaction/xmin; -slot/feedback; -relation size; -freeze age; -autovacuum config; -host I/O。

不要因为 bloat panel 红就执行 rewrite。

从 log panel 回到 pipeline

先验证:

source file exists and advances
Vector source healthy
parse errors
VictoriaLogs ingest/query
time zone
retention
redaction

然后限定:

cluster / instance / database
severity or SQLSTATE
time window
row limit

本章不导出 body;如果必须查看,在受限界面完成。

面板与规则必须共享 contract

如果 alert:

bad_ratio 1h + 5m

dashboard 却画:

5m p99

值班无法复核 alert。至少提供:

-exact long/short expression; -event count; -threshold; -pending/firing start; -missing/freshness; -release marker; -rule evaluation error。

用 source link,不复制 payload

alert 携带:

dashboard id
query template id
time range
service/environment

而不是把 metric dump、SQL text、log body 全塞进通知。诊断包按权限拉取。

三次复核法

高风险动作前至少三类独立证据:

service symptom
  app SLI or independent probe

PostgreSQL fact
  native SQL / log / topology

platform/host fact
  pool / host / rule engine / change event

不是机械凑三条,而是让每条能 falsify 竞争解释。

Pigsty dashboard 的正确使用路径

overview
  locate service/cluster and onset

cluster
  topology, workload, replication, capacity

instance
  role, activity, I/O, WAL, maintenance

database
  transactions, tables, query workload

query/catalog/log
  focused evidence

native SQL and host
  verify before mutation

下钻过程中始终保留 time range 和 identity。

平台升级验收

Pigsty/pg_exporter/PG major 升级后:

  1. inventory/target identity;
  2. raw exporter HELP/TYPE/labels;
  3. required metric presence;
  4. series cardinality;
  5. recording rule dry run/unit test;
  6. dashboard no-data/error;
  7. alert route test;
  8. native SQL parity;
  9. log parse/redaction;
  10. production canary/rollback。

不要以“Grafana 首页能打开”验收监控升级。

本节验收

你应当能解释:

  1. Pigsty v4 metrics、logs、traces、rules、dashboards、routes 各由谁负责;
  2. raw exporter label 与 storage external label 为什么不同;
  3. clsinsip 与 scrape instance 的区别;
  4. RDS/Managed/Full 三种模式会缺哪些信号;
  5. pg_query_*query label 为什么是 queryid 而非 text;
  6. exporter endpoint up 为什么不等于所有 collector 正常;
  7. VictoriaMetrics series count 为什么需要趋势而非单次上限;
  8. VMAlert 无 error 为什么不等于本章规则已部署;
  9. Alertmanager 无失败为什么不等于 receiver 已收到;
  10. trace backend healthy 为什么不等于应用有 span;
  11. 从 connection、I/O、replication、archive、query、vacuum panel 分别回到什么原生证据;
  12. 平台升级为什么必须做 metric/rule/dashboard/native parity。

上一节:把观察契约变成告警 · 返回本章目录 · 下一节:从告警到诊断包 · 查看全书目录 · 查看索引中心

最后更新于