跳至内容
8.3 关联日志、指标与计划

8.3 关联日志、指标与计划

activity 告诉你“此刻”,查询累计量告诉你“这段 epoch”,日志保存离散事件,指标保存时间序列,计划解释 executor 怎样处理数据。四者只有共享时间、实例、会话和查询身份,才能形成证据链。

8.3.1 日志最小基线与慢语句记录

诊断日志的第一个目标不是“把所有 SQL 打出来”,而是让一条事件可定位:

timestamp + timezone
cluster/instance
PID/session identity
user/database/application/client
severity/SQLSTATE
query or query identity
duration
transaction/session context

PostgreSQL 的 log_line_prefix 可以提供这些身份。一个需结合环境评估的示意:

log_line_prefix = '%m [%p] %c %q%u@%d/%a '

其中 %m 是带毫秒时间,%p 是 PID,%c 由 backend start time 与 PID 组成近似唯一的 session ID,%u/%d/%a 分别是用户、数据库和 application。若启用 compute_query_id,还可评估 %Q;但官方明确指出 log_statement 产生日志时 query ID 可能尚未计算,因此不能把某一类日志里的 %Q=0 当作真实 query identity。

生产日志更适合使用 csvlogjsonlog 等结构化目标,由采集器保留字段,而不是依赖脆弱正则拆纯文本。无论格式如何,都要实测 rotation、磁盘上限、采集延迟、丢弃策略与敏感字段。

记录慢完成语句的核心参数是:

log_min_duration_statement = '...ms'

它在语句完成且 duration 达阈值时记录,因此能发现“已结束的慢”,却不能解释当前一直没结束的 blocker。阈值不是通用常数:OLTP、批处理与维护任务的正常时长不同。先根据 SLO、流量和日志预算设基线,再用 role/database/session 或采样策略控制范围。

相关开关解决不同问题:

设置能回答主要代价/边界
log_min_duration_statement哪些完成语句越过阈值高流量下日志量;不记录未完成
log_min_duration_sample + sample rate采样慢/常规语句样本不等于全量;需保留采样率
log_lock_waits等锁超过 deadlock_timeout 的事件阈值与日志量;不是所有短锁等待
log_temp_files超阈值临时文件只证明 spill/临时文件,不自动证明根因
auto_explain被采样语句的执行计划ANALYZE/timing 成本、日志量与参数暴露
log_statement某类语句文本all 通常过量且可能泄密;不是性能万能开关

参数值比 SQL shape 更敏感。extended query protocol 的日志可能包含 bind parameters;log_parameter_max_lengthlog_parameter_max_length_on_error 可限制或禁止记录,但非零错误参数记录也会增加保存文本表示的开销。策略至少应覆盖:

  • token、密码、密钥、个人数据和业务 payload 的禁止/脱敏;
  • 每值长度和整条消息长度;
  • 谁能读取、传输是否加密、保留多久;
  • exporter/log pipeline 是否会复制到更多系统;
  • 调查结束后如何恢复临时配置。

不要在事故中即兴全局打开 log_statement=allauto_explain.log_analyze=on 和完整参数。先估算事件率、单条字节、磁盘余量与性能成本;能按单一 role/database/session 小范围复现时,就不要扩大到全局。

8.3.2 SQL 指标、主机资源与部署事件

慢查询证据通常跨四层:

代表信号用途
请求/应用route latency、errors、retries、pool wait、in-flight确认用户影响与 PostgreSQL 外时间
PostgreSQL query/sessioncalls/time/rows、wait、locks、plans、temp/WAL锁定查询族与数据库机制
PostgreSQL instanceconnections、xacts、checkpoints、WAL、vacuum、I/O判断共享资源与后台活动
主机/平台CPU、run queue、memory pressure、disk latency/queue、network解释系统资源与邻居效应

再叠加一条“变化流”:

application release
schema/index/statistics change
PostgreSQL/Pigsty/configuration change
failover/restart
data load/backfill/maintenance
traffic or tenant mix change

正确关联不是看到两条曲线同时升高,而是提出机制:

发布改变 SQL predicate
  → query family calls 与 rows/call 上升
  → plan estimate/actual 偏离
  → shared blocks 与 CPU 同范围上升
  → endpoint p99 上升
  → 回滚 SQL shape 后上述指标按预期恢复

反例也同样重要:

  • 主机 CPU 高,但目标 query 在 Lock wait:CPU 可能是另一 workload;
  • shared block hit 高:只说明 PostgreSQL buffer hit,不代表没有 CPU 或 kernel page-cache I/O;
  • disk latency 上升,但目标 plan buffers 几乎全 hit:时间相关不等于该 query 被磁盘拖慢;
  • temp files 上升,但来自报表 user,而事故来自 OLTP application;
  • 发布与事故同时发生,但未发布的 control instance 也同样退化:优先调查共享依赖。

PostgreSQL 的 pg_stat_iopg_statio_* 能补充数据库 I/O 视角,但官方提醒它们不能区分数据是从物理介质还是 kernel page cache 取得;仍需与操作系统工具联合。track_io_timing 能提供时间,但有平台计时开销,是否常开需基准验证。

计划证据沿用第 7 章的机器可读格式:

EXPLAIN (
    ANALYZE,
    BUFFERS,
    WAL,
    SETTINGS,
    SUMMARY,
    FORMAT JSON
)
SELECT ...;

它只应在安全、代表性环境执行。ANALYZE 会真实运行 SQL;写语句即使包在 rollback 中也可能有 sequence、外部函数等不可回滚副作用。事故时已有一条正在阻塞的生产写语句,不应为了“看计划”再执行一遍。

8.3.3 用同一时间轴排除巧合

把证据转换成 UTC 事件表,比叠十张截图更容易看出顺序:

UTC事件身份/范围证据
12:03:42release 2026.07.29-3 开始app-adeploy log
12:04:01route p99 越过 SLOcheckout/createhistogram + count
12:04:05pool wait 上升app-apool metric
12:04:07Lock wait 出现db/shop, query Xactivity snapshot
12:04:07blocker edge X→YPID + backend_startpg_blocking_pids()
12:04:31精确取消 Yapproved actionaudit log
12:04:32X 前进,pool queue 回落same scopesession/pool metrics
12:04:45p99 恢复same routehistogram

这条链同时满足:

  1. 先后:候选原因发生在结果之前;
  2. 同范围:实例、database、user、application/query 能对应;
  3. 剂量/机制:blocker 存在时等待积累,释放后 waiter 前进;
  4. 负对照:未受影响路由或无 blocker 窗口不呈现同样现象;
  5. 可逆性:受控动作后结果按预测变化。

时间对齐时记录数据本身的分辨率:

  • Prometheus scrape interval 与 recording rule window;
  • Grafana 查询 step、rate window、timezone;
  • 日志采集/索引延迟;
  • trace sampling rate;
  • PostgreSQL 累计统计刷新延迟与事务内 snapshot;
  • 应用与数据库主机的 clock synchronization;
  • failover 后 instance identity/计数器是否改变。

不要把面板像素对齐当毫秒级因果。某条一分钟 rate 曲线的点代表一个区间,日志 timestamp 代表事件,activity 是一次采样,它们的语义不同。先把每项转换成“事件或区间 + 误差/分辨率”,再讨论顺序。

一个实用的反巧合问题集:

候选原因是否先于症状?
是否只出现在受影响范围?
它通过什么数据库机制产生该症状?
该机制应留下什么额外证据?
未受影响对照是否缺少这些证据?
只移除这一原因后,哪些指标应先后恢复?
若未恢复,这个假设怎样被判错?

输出时保留原始 artifact,而非只有解释。原始 CSV/JSON plan、日志行、Prometheus expression、时间范围、source hash 和查询参数分桶使其他人能够重算;截图最多是导航附件。

下一节将这些关联结果整理为一个有优先级、可反驳的假设树。


上一节:从会话到语句定位范围 · 返回本章目录 · 下一节:建立而不是猜测假设 · 查看全书目录 · 查看索引中心

最后更新于