22 深入专题:监控与故障诊断

22 深入专题:监控与故障诊断

统计视图、等待事件、慢 SQL 定位与日志分析。

Linux 下如何用 gcore/gdb/pstack/strace 排查 PG 进程 hang 的问题?

PG 进程 hang 无法用 pg_terminate_backend 杀掉时,用这些工具抓现场:pstack/gstack 是脚本(最终调用 gdb),用 gdb -p –batch -ex “thread apply all bt” 打印所有线程堆栈,可看到进程卡在哪个函数(如 epoll_pwait → WaitEventSetWait → secure_read → pq_getbyte → PostgresMain,说明在等客户端消息)。gcore 生成 core dump(core.)用于离线分析。strace -CvTt -p 追踪系统调用和信号,看进程在做什么 syscall、耗时多少(如 lseek/brk/sendto/recvfrom 各占多少时间)。lsof 查打开的文件,删除文件后空间未释放时可 lsof 找谁还打开着该文件。blktrace/blkparse/btt 用于块设备 IO 延迟分析(见下一问)。这些是 PG 进程 hang、crash 排查的必备工具。

PG 的 wait_event 体系分哪 9 大类?每类大概代表什么?

PG 9.6 起引入 wait_event 体系,PG 14+ 细分了 IO 类型。9 大类:Activity(空闲主循环)、BufferPin(等 buffer 排他锁)、Client(等客户端收发,如 ClientRead/ClientWrite)、IO(等数据文件/WAL/control file,如 DataFileRead/WALWrite/ControlFileSync)、IPC(等子进程/并行 worker)、Lock(重量级锁,如 transactionid/tuple)、LWLock(共享内存轻量锁,如 buffer_mapping/lock_manager/WALWriteLock)、Timeout(故意 sleep,如 PgSleep)、Extension(扩展自定义)。第一性原理:wait_event 告诉你这一刻这个 backend 为什么不在跑,是定位瓶颈的最强武器。

PG 等待事件统计为什么需要’时间’而不只是’次数’?采样和精确统计各有什么利弊?

pg_stat_activity 只有当前等待状态,pg_wait_sampling 只记采样次数不记耗时。但 Oracle 文档明确指出:应关注等待时间最多的事件,而不是次数最多的事件——有的事件次数多但每次很短(如 buffer_content lock),有的次数少但单次很长(如慢 IO、锁),只有等待时间才能判断影响和 justify 处理方案。采样(Oracle ASH 式)的缺点:1)不精确,会漏掉间歇性短等待;2)过采样耗资源(10ms/1ms 采样导致数据量大、后台采样进程阻止 CPU 空闲);3)无法判断是一次长等待还是多次短等待。精确统计(记录每次 wait 的 elapsed time)的顾虑是 gettimeofday 开销,Tom Lane 指出在 hot code path(如 lwlock.c)里调用计时不可接受,且 pgstat_report_wait_start/end 需保证无副作用。折中:可能以插件形式存在,用户自由开关。

PG12 对 incomplete startup packet 日志做了什么改进?哪些日志仍然会打印?

监控探测、端口扫描、HA 工具等连接 5432 端口但不发送 startup 报文,PG12 以前会为每次这样的探测打印 incomplete startup packet 错误日志,导致日志文件暴涨和多余 IO。PG12 的 patch 342cb650e 约定:连接被关闭且未发送任何数据时不记录任何日志(例如监控工具打开连接后立即关闭)。但以下仍会打印:1)客户端发送了数据但报文非法 → invalid length of startup packet;2)服务端读包时客户端已丢失(未正常握手关闭)→ could not receive data from client: Connection reset by peer(这个日志不会消失,因为对应 pq_recvbuf 读包时发现对端没了)。复现:for i in {1..100}; do nc -zv localhost 5432; done。正常存活探测建议用 pg_isready 命令。

PG14 新增 pg_stat_replication_slots 视图监控什么?关键字段含义是什么?

PG14 commit 98681675 新增 pg_stat_replication_slots,跟踪每个 logical replication slot 的 decode 统计,特别是超过 logical_decoding_work_mem 内存导致的 ReorderBuffer 落盘(spill)操作。视图每个 logical slot 一行,字段:name(集群唯一 slot 标识)、spill_txns(因 logical decoding 内存超限而落盘的事务数,含 top-level 和子事务)、spill_count(落盘次数,事务可能重复落盘,每次触发都累加)、spill_bytes(落盘的已解码事务数据量)、stats_reset(上次重置时间)。配套函数 pg_stat_reset_replication_slot(text),参数为 slot 名或 NULL(NULL 表示重置所有 slot),默认仅 superuser 可执行。如果 spill 增长频繁,说明 logical_decoding_work_mem 配得不够,需要调大。

PG14 的 PQtrace 相比之前有哪些改进?如何用协议层日志排查慢的问题?

PQtrace 是 libpq 记录客户端-服务端协议交互的函数。PG13 及以前输出无时间戳、message identifier/server 长度/content 分行显示、难读难分析。PG14 改进四点:1)加时间戳;2)方向代码直观化 F(frontend)/B(backend);3)输出正式 message 名而非标识符(如 Query、CommandComplete、ReadyForQuery 代替 Q/C/Z);4)有意义的协议消息一行输出。新增 PQsetTraceFlags 控制是否输出时间戳。价值:通过日志时间戳差可判断应用突然变慢时是服务端还是客户端处理慢;不输出时间戳时可用于回归测试对比。典型输出形如:2021-06-30 09:21:56.366741 F 133 Query “…"。未来方向:限制日志文件大小、用环境变量/连接参数控制日志目录。

PG14 的 pg_stat_replication_slots 视图监控什么?

PG14 新增 pg_stat_replication_slots 视图,每个逻辑复制槽一行,统计逻辑解码 ReorderBuffer 因超过 logical_decoding_work_mem 而落盘的事务数(spill_txns)、落盘次数(spill_count)、落盘字节数(spill_bytes)。若 spill 增长频繁,说明逻辑解码内存不足,应调大 logical_decoding_work_mem。

PG14 给 pg_stat_database 新增了哪些 session 相关计数器?各代表什么?

PG14 commit 960869da 为 SaaS 场景(serverless、按库计费)新增数据库维度 session 统计:session_time(该库所有会话总耗时,仅在状态切换时更新,长期 idle 不计入);active_time(执行 SQL 的时间,对应 active 和 fastpath function call 状态);idle_in_transaction_time(事务内空闲时间,对应 idle in transaction 及 aborted 状态);sessions(建立过的会话总数);sessions_abandoned(因客户端连接丢失而终止的会话数);sessions_fatal(因 fatal 错误终止的会话数);sessions_killed(被管理员操作终止的会话数)。这些指标让云厂商能按 database 维度统计每个租户消耗的 CPU/会话资源,用于计费和容量评估。

Planner 执行计划失准的 5 大根因是什么?各有什么对策?

1)数据倾斜:rows 估算严重偏高 → CREATE STATISTICS ON a,b FROM t 扩展统计;2)bulk load 后没 ANALYZE:全走 Seq Scan → COPY 后立即 ANALYZE;3)长时间小批量写入:统计陈旧 → 调小 autovacuum_analyze_scale_factor=0.025;4)关联列无统计:rows 估算为乘积 → CREATE STATISTICS 多维统计;5)数据分布随时间漂移:老统计不反映新常态 → 周期性 ANALYZE 或 cron。另外 random_page_cost=4(默认)会让 planner 认为随机 IO 很贵倾向顺序扫描,SSD 盘要调到 1.1(云盘 1.5、NVMe 1.0);plan_cache_mode=auto 时前 5 次选 plan 后固化(plan sniping),可用 force_custom_plan 对比。自检:select schemaname, relname, last_analyze, n_mod_since_analyze from pg_stat_user_tables order by n_mod_since_analyze desc。

PoWA4 是什么?它依赖哪些插件,各自贡献什么能力?

PoWA(PostgreSQL Workload Analyzer)是 PG9.4+ 的性能分析工具,通过插件采集统计并做分析诊断,带 WEB 展示,支持远程采集和把数据存到其他 PG 库。依赖插件:pg_stat_statements(TOP SQL 统计)、pg_qualstats(SQL 真实过滤性/选择性统计,用于判断是否需要索引)、pg_stat_kcache(buffer/OS cache/disk 命中统计,区分 page cache 与真实磁盘 IO)、pg_wait_sampling(等待事件采样,说明问题根源)、pg_track_settings(跟踪数据库配置变更)、HypoPG(虚拟索引,用于索引推荐)。它能展示 QPS、缓存命中率、SQL 洞察、等待时间统计、索引推荐等,是历史回溯和 TOP SQL 分析较强的方案。

PostgreSQL 的 pgcenter 是什么?

pgcenter 是采样、统计、性能诊断、profile 的 CLI 小工具,通过 SQL 接口定期采样 PG 的各类统计视图,提供类似 top 的实时面板和 profile 功能,方便在命令行快速观察数据库负载、等待、IO、SQL 等指标,无需部署重型监控。

PostgreSQL 的等待事件采样(ASH 理念)为什么重要?

pg_stat_activity 只显示会话当前等待状态,无法回答某事务/某 SQL 有多少种等待、各等了多少次多久。等待事件统计(类似 Oracle ASH/performance insight)记录每次等待的次数和耗时,能精准定位瓶颈。纯采样会漏掉短暂等待,纯计数没有时间无法判断影响,所以需次数+时间结合。性能损耗(gettimeofday)是引入完整计时的主要顾虑。

SlowQL 是什么,解决什么问题?

SlowQL 是离线 SQL 静态分析器,不需要连接数据库,针对 SQL 源文件、迁移脚本、dbt/Jinja 模板和应用代码里的 SQL 字符串做分析,内置 279 条规则覆盖 14 种 SQL 方言,六大维度(安全、性能、可靠性、质量、成本、合规)。价值在于把 SQL 风险拦截在代码提交前(治理左移),支持跨文件理解迁移、基线增量治理、CI 门禁和 SARIF 集成。

SlowQL 这类 SQL 静态分析工具解决什么问题?它的治理落地路径是什么?

SlowQL 是离线 SQL 静态分析器,不需要连接数据库,针对 SQL 源文件、迁移脚本、dbt/Jinja 模板、应用代码里的 SQL 字符串做分析,内置 279 条规则覆盖 14 种方言,把数据库治理从’人肉经验’升级为’工程系统’——在代码提交前把高风险 SQL 拦下来(SQL 是源代码资产,应像 Java/Go 一样做静态检查、CI 门禁、基线管理)。落地路径:1)本地先跑(pipx install slowql; slowql queries.sql);2)增量治理(–update-baseline 建基线,–git-diff 只分析变更文件,不碰存量烂账);3)门禁分层(–fail-on critical|high|medium,核心库 fail-on high);4)规范写进 slowql.yaml 配置;5)例外显式记录(slowql-disable-line 注释抑制);6)接 GitHub(GitHub Action 或 SARIF 给 code scanning)。适用前提:SQL 在源码里可治理,且问题属于源码层可判定(危险模式/反模式/结构引用错误),运行时数据分布/锁竞争等问题仍需执行计划分析和监控。

auto_explain 如何配置?为什么大流量场景必须抽样?

auto_explain 是 PG 自带模块,把超过阈值的 SQL 执行计划自动落盘。配置:shared_preload_libraries=‘auto_explain’,auto_explain.log_min_duration=‘3s’、log_analyze=on、log_buffers=on、log_format=‘json’(PG10+ 便于 ELK 解析)、log_timing=on、log_verbose=on、sample_rate=1。必须加载到 shared_preload_libraries 才能跨 session 全局生效。大流量(>5000 QPS)必须抽样:sample_rate=0.01~0.1,因为 log_analyze=on 会让每次捕获都真正 EXPLAIN ANALYZE 一次,全量会让 CPU 翻倍。注意 log_min_duration=3s + sample_rate=0.01 有盲区:平时 0.5s、事故时偶发 4s 的致命 SQL 可能一条都采不到,建议 log_min_duration=1s + sample_rate=0.05 起跳,配合 pg_stat_statements 快照双轨。

blktrace/blkparse/btt 如何分析一次 IO 的生命周期和各阶段延迟?

blktrace 采集块设备 IO 轨迹,blkparse 解析成可读文本,btt 做统计分析。一次 IO 生命周期 actions:Q(产生 IO 意向插入队列)→ G(发实际请求)→ P(plugging 插入,等待更多请求以便优化)→ I(调度,请求成型)→ U(unplugging 拔出,传给驱动)→ D(发布给驱动器)→ C(完成,返回状态,进程号为 0 表示成功)。时间指标:Q2Q(请求间时间)、Q2G(排队到分配 request)、G2I(分配到插入队列)、I2D(插入到实际下发驱动)、D2C(设备服务时间)、Q2C(块层总耗时,=Q2I+I2D+D2C)。用 btt -i sda.blktrace.bin -l sda.d2c_latency 看各阶段 MIN/AVG/MAX,D2C 是表征块设备性能的关键指标、Q2C 是客户端请求到响应时间。blkiomon 可按周期输出 d2c 直方图。这些能区分 IO 慢是设备问题(D2C 大)还是调度/排队问题(I2D 大)。

ftrace 如何做内核函数级追踪?function_graph tracer 怎么用?

ftrace 是内置内核的追踪程序(内核态 strace),API 位于 debugfs 的 /sys/kernel/debug/tracing。依赖内核开关:CONFIG_FUNCTION_TRACER、CONFIG_FUNCTION_GRAPH_TRACER、CONFIG_STACK_TRACER、CONFIG_DYNAMIC_FTRACE(启动后 mcount 转 NOP 保证性能,打开 tracer 时才转回跟踪)。用法:echo 0 > tracing_on 关;echo function_graph > current_tracer 设 tracer;echo ksys_pread64 > set_graph_function 指定跟踪函数;echo funcgraph-tail > trace_options、echo funcgraph-proc > trace_options 加注释;echo 1 > tracing_on 开;执行目标程序后关掉,cat trace 看输出。示例展示了 pread64 完整调用链(ksys_pread64 → vfs_read → __vfs_read → xfs_file_read_iter → generic_file_read_iter → pagecache_get_page),能精确看到某次 read 是否命中 page cache(无物理 IO)及各函数耗时,用于数据库 IO 深潜。

pgBadger 在监控生态里定位是什么?日志相关参数应如何配置以便分析?

pgBadger 是解析 pg_log 生成 HTML 报告的日志分析工具,偏日志分析、适合 DBA 巡检。要让它有效工作,日志参数需配合:logging_collector=on、log_destination=‘csvlog’(或 stderr,pgBadger 能解析多种格式)、log_min_duration_statement=3s(慢 SQL 阈值,OLTP 15s、OLAP 30s5min)、log_lock_waits=on(记录锁等待)、log_temp_files=0(全部记录临时文件)、log_autovacuum_min_duration=0、log_checkpoints=on、log_connections/log_disconnections=off(减少噪音)、log_line_prefix=’%m [%p] %q%u@%d from %h ‘、log_statement=‘ddl’(PG17+ 推荐只记录 DDL)。log_rotation_age=1d、log_rotation_size=1GB 控制切割。csvlog 格式便于 ELK/pgBadger 结构化解析,是日志分析的基础配置。

pgCluu 是什么?它如何做 PG 集群的监控和审计?

pgCluu(PostgreSQL Cluster utilization)是 Perl 编写的 PG 性能监控和审计工具,分两部分:1)collector(pgcluu_collectd)用 psql 命令抓取 PG 集群统计,用 sysstat 包的 sar 抓系统性能;2)纯 Perl grapher(pgcluu)生成 HTML 和图表报告,图表用 Javascript 库渲染、浏览器完成绘图,无需额外依赖。若不需要系统报告或不装 sysstat 可禁用(远程监控时 sar 自动禁用),也能单独从 sar 数据文件生成系统图表。安装:PGDG 仓库 apt/yum install pgcluu,或源码 perl Makefile.PL; make; make install。适合 DBA 巡检、生成全量审计报告,弥补 pgbadger 只做日志分析的空白。

pgSCV 是什么?它支持哪些采集能力和运行模式?

pgSCV 是 PostgreSQL 生态的 metrics exporter,采集系统、PostgreSQL、Pgbouncer 等统计,通过 HTTP /metrics 端点以 Prometheus 格式暴露指标。特性:Pull 模式(监听 /metrics 供 Prometheus/Vmagent 抓取);Push 模式(抓取自身 /metrics 推送到指定 HTTP 服务);多服务采集;服务自动发现(自动发现 Postgres 及生态服务);远程服务支持;Bootstrap 自安装(需 root);自动更新;用户自定义 metric;collector 管理和过滤(按块设备/网卡/文件系统/用户/库等 label 过滤)。只能跑 Linux。Charts 覆盖:数据库活动、运行中查询、等待事件与锁、运行负载、后台服务、第三方工具、系统负载、存储利用率。适合云原生 Prometheus + Grafana 方案,多实例(>5)首选。

pg_ash 插件是如何实现 PG 性能洞察(ASH)的?

pg_ash 是纯 SQL/PLpgSQL 实现的反插件(Anti-extension),不碰内核、免编译免重启,靠 pg_cron 每秒采样 pg_stat_activity 和 pg_stat_statements。它把会话信息编码成 integer[] 数组(每条约 100 字节),用 TRUNCATE 循环清空旧数据避免膨胀,保留最近 2-3 天。可事后回放任意时间段(如 top_waits_at)的等待事件和 TOP SQL,兼容 RDS 等云数据库。

pg_ash 是什么?它为什么被称为’反插件’,实现原理和代价是什么?

pg_ash 是纯 SQL + PL/pgSQL 实现的 ASH(Active Session History)插件,定时采样 pg_stat_activity 和 pg_stat_statements,可分析过去任意时间段的等待事件、TOP SQL,纯 SQL 接口、RDS 和自建都适用。它被称为’反插件’(Anti-extension):不写 C、不改 shared_preload_libraries、不用重启数据库,只要有 pg_cron(主流云都自带)跑一遍 SQL 就装好。原理:每秒由 pg_cron 对 pg_stat_activity 拍快照,把会话信息压缩编码成 integer[] 数组(每条约 100 字节,一天几十 MB),用 TRUNCATE 循环清理只保留 2-3 天(零碎片不 bloating)。代价:1 秒采样会产生约 2.4GB/天 WAL,写压力大可改 5 秒采样。查询示例 select * from ash.top_waits_at(‘2026-02-26 09:00’,‘2026-02-26 09:10’)。建议配合 pg_stat_statements 自动关联 SQL 文本。

pg_ash 的 CPU* 标志和 WAL 开销分别需要注意什么?

pg_ash 报告里的 CPU* 标志不一定代表 CPU 真的忙,它表示 wait_event_info=0,大多数情况是 CPU 执行,但也可能包含 PG 内核尚未 instrument 的’未知等待’路径,看到 CPU* 要结合系统监控一起看,不要机械理解成精确 CPU 时间。WAL 开销:pg_ash 每秒采样虽存储小(每条约 100 字节,一天几十 MB),但会产生约 2.4GB/天的 WAL 日志量,若数据库写压力极大或带宽/存储贵,可改为 5 秒采样:select ash.start(‘5 seconds’)。部署注意:RDS/Supabase 使用前确保启用 pg_cron;强烈建议开启 pg_stat_statements,pg_ash 能自动关联它直接显示 SQL 文本而不是冷冰冰的 query_id。

pg_stat_activity 有哪些核心字段?如何用它定位当前正在等待的慢 SQL?

pg_stat_activity 关键字段包括:pid(后端进程ID)、datname/usename/application_name、client_addr/client_port、backend_start/xact_start/query_start/state_change(时间戳)、wait_event_type/wait_event(等待事件)、state(active/idle/idle in transaction/idle in transaction (aborted)/fastpath function call 等)、backend_xid/backend_xmin、query、backend_type。定位慢 SQL 可用:select pid, now()-query_start during, query, wait_event_type, wait_event from pg_stat_activity where wait_event is not null order by query_start limit 1;。结合 wait_event_type/wait_event 判断该 backend 正在等 IO、锁还是 LWLock,是性能诊断的第一入口。

pg_stat_activity 里 query 字段显示的 SQL 有什么局限?如何在函数内部拿到当前会话最外层执行的 SQL?

pg_stat_activity.query 记录的是当前(或该连接最后一次)最外层 SQL,当一条 SQL 内部调用了函数、函数里又执行了别的 SQL 时,函数内部的 SQL 不会出现在这里。想要在函数里跟踪当前最外层 SQL,可以自定义函数查当前会话自身:create or replace function getquery() returns text as $$ select query from pg_stat_activity where pid=pg_backend_pid(); $$ language sql strict;。然后在任意 SQL 中调用 getquery() 即可拿到整条外层语句(例如 select getquery() as sql,oid from pg_class limit 1 会返回完整的外层 SQL 文本)。这在 DDL 审计、触发器记录来源 SQL 等场景很有用。

pg_stat_bgwriter 有哪些关键列?buffers_backend 过大说明什么?

pg_stat_bgwriter 反映 bgwriter、checkpoint、backend 三方刷盘情况,关键列:buffers_checkpoint(checkpoint 写出的 buffer)、buffers_clean(bgwriter 写出的)、buffers_backend(backend 进程自己主动写出的)、checkpoints_timed/checkpoints_req(按时/请求触发的 checkpoint 次数)、maxwritten_clean、buffers_alloc。buffers_backend 过大或相比 buffers_checkpoint/buffers_clean 没小很多,代表 shared_buffers 没维护好,后端进程不得不自己刷盘,说明 bgwriter 不给力或 shared_buffers 偏小,应调大 bgwriter_lru_maxpages 或 shared_buffers。checkpoints_req 远多于 checkpoints_timed 则是雪崩式 checkpoint,需调整 max_wal_size。也可用它算写入量:8*(buffers_checkpoint+buffers_clean+buffers_backend)/1024 得总写 KB。

pg_stat_database 有哪些关键指标?如何用它做数据库总览和健康判断?

pg_stat_database 是数据库级累计统计视图,关键字段:numbackends(当前连接数)、xact_commit/xact_rollback(提交/回滚数)、blks_hit/blks_read(缓存命中/落盘块)、deadlocks(死锁次数)、temp_bytes(临时文件字节)、blk_read_time/blk_write_time(IO 耗时)、stats_reset。总览 SQL:select datname, numbackends conns, xact_commit, xact_rollback, round(100.0xact_rollback/nullif(xact_commit+xact_rollback,0),2) rollback_pct, round(100.0blks_hit/nullif(blks_hit+blks_read,0),2) cache_hit_pct, deadlocks, temp_bytes, age(datfrozenxid) xid_age from pg_stat_database where datname not in (’template0’,’template1’,‘postgres’);。阈值经验:回滚率>5% 持续=应用层 BUG;连接>80%=拒连风险;缓存命中率应看趋势(OLTP 稳定 95~98% 突然掉到 80% = 热点被踢出 buffer),不宜当硬阈值。

pg_stat_kcache 插件跟踪什么指标?

pg_stat_kcache 2.2.0 支持 PG13,用于跟踪每条 SQL 的 CPU 使用和文件系统真实读写行为(实际 IO 次数和字节数)。结合 pg_stat_statements,可看到每条 SQL 的真实资源消耗(CPU 时间、物理读、物理写),区分逻辑读与真实磁盘 IO,帮助定位真正吃资源的热点 SQL。

pg_stat_kcache 解决什么问题?它如何区分 page cache 与真实磁盘 IO?

PG 的 shared buffer 统计容易误导人:shared_buffers 配得小,命中率看着低,但实际上 read 可能发生在 OS page cache,并未产生真实磁盘 IO,这些是文件系统接口完成的,数据库内核不知情。pg_stat_kcache(powa 团队出品)跟踪文件系统层真实读写行为,通过 getrusage 的 page fault 区分:major page fault(majflts)说明发生了真实磁盘访问,minor page fault(minflts)说明命中 page cache。它需要依赖 pg_stat_statements,加到 shared_preload_libraries=‘pg_stat_statements,pg_stat_kcache’。提供 pg_stat_kcache 视图(数据库级 exec_user_time/exec_system_time/exec_minflts/exec_majflts/exec_reads_blks/exec_writes_blks 等)和 pg_stat_kcache_detail 视图(按 query 明细),可精确判断某 SQL 到底落了多少真实盘。

pg_stat_progress_copy 在 PG14 有哪些增强?COPY 进度监控能看哪些信息?

PG14 commit 9d2d4570 增强 COPY 进度上报。通过 select * from pg_stat_progress_copy(底层 pg_stat_get_progress_info(‘COPY’))可看到:pid、datid/datname、relid、command(CASE param5:1=COPY FROM、2=COPY TO)、type(param6:1=FILE、2=PROGRAM、3=PIPE、4=CALLBACK)、bytes_processed/bytes_total(已处理/总字节)、tuples_processed(已处理元组数,原 lines_processed 改名以消除 CSV/BINARY 歧义)、tuples_excluded(被 WHERE 子句排除的元组数)。这让你能监控大批量 COPY 导入导出的进度、速度,以及 COPY FROM 里 WHERE 过滤掉了多少行,对大表数据迁移和 ETL 很有用。

pg_stat_statements 只有累计值,如何做趋势分析?queryid 有什么稳定性边界?

pg_stat_statements 默认只给累计值,没有历史趋势,这是新手最常踩的坑。做法是外部定时器(cron/pg_cron)+ 历史表 + 趋势 SQL:建 pg_stat_statements_history 表(snap_ts, queryid, query, calls, total_exec_time, rows, blks),每分钟 insert into … select now(), … from pg_stat_statements where calls>0,再按 date_trunc(‘hour’, snap_ts) 聚合出 7 天 TOP SQL 趋势。queryid 的稳定性边界:同一 major 版本内 + 同一规范化 SQL 文本才稳定;PG 大版本升级(14→15、16→17)会因内部算法微调而变化,不能说跨实例/跨版本稳定,做历史比对时要记住这一点。

pg_stat_statements 缺乏 p99/p95 指标会带来什么问题?如何评估 SQL 响应时间稳定性?

pg_stat_statements 提供 SQL 调用次数、平均 RT(mean_exec_time)、stddev(标准差)等,但缺乏 p99/p95 分位指标。p99/p95 含义:某 SQL 99% 请求 RT 低于某值、95% 低于某值,能说明 RT 稳定性。缺乏它的影响:只有平均值和方差,无法掌握 RT 稳定性边界,难与业务达成 benchmark 目标,尤其对高并发小事务(KV 查询)单次 RT 严苛的场景。业务上可用 stddev 评估抖动但不精确,基本无解。这也是 pgpro_stats、pg_wait_tracer 等插件通过 histogram 延迟分布补足的原因。希望 PG 未来在 pg_stat_statements 支持 RT 的 p99/p95 指标。

pg_wait_sampling 插件如何采集等待事件?它提供哪些视图和 GUC?

pg_wait_sampling(Postgres Professional 出品)是基于采样的等待事件统计插件,需加 shared_preload_libraries(要额外共享内存并启动 background worker),支持 PG9.6+。它采集两类统计:History(内存 ring buffer,按周期记录每个进程的等待事件样本)和 Profile(内存 hash 表,按 pid/事件累计采样次数,可 reset)。提供视图:pg_wait_sampling_current(当前等待事件)、pg_wait_sampling_history(历史样本,含 ts 时间戳)、pg_wait_sampling_profile(profile 计数),函数 pg_wait_sampling_get_current(pid)、pg_wait_sampling_reset_profile()。GUC:pg_wait_sampling.history_size(默认5000)、history_period/profile_period(默认10ms)、profile_pid、profile_queries(配合 pg_stat_statements 按 query 统计)。它只记录等待次数(采样计数),不记录真实等待耗时。

pg_wait_tracer 是什么?

pg_wait_tracer 用 BPF 硬件 watchpoint 把 PostgreSQL 的等待事件变成实时诊断。它利用硬件断点/观察点在低开销下跟踪进程等待状态变化,生成等待事件的实时时间线,帮助 DBA 像看电影一样观察等待事件的起止和切换,定位瞬时等待和瓶颈。

pg_wait_tracer 用 BPF 硬件 watchpoint 实现等待事件全量追踪,原理是什么?有哪些诊断视图?

pg_wait_tracer 不用 patch、不装 extension、不重启数据库,通过 BPF + CPU 硬件 debug register/watchpoint 盯住 PGPROC->wait_event_info 字段。backend 每次进入/退出/切换等待事件都会写这个字段,watchpoint 触发后 BPF 程序用 bpf_ktime_get_ns() 计算前一状态持续时间,把 timestamp、pid、old/new_event、duration、query_id 发到 ring buffer,用户态消费聚合。核心卖点是 no sampling:捕获每一次 wait event transition 而非采样,克服短事件易漏、顺序不完整、难做精确 latency histogram 的采样盲点。7 个诊断视图:time_model(DB Time 总入口,CPU*/IO/LWLock/Lock/Client 等占比)、system_event(Top 等待事件)、session_event(按 backend 看 CPU/Wait 比例)、histogram(16 个 log2 bucket 延迟分布)、query_event(归因到 query_id,需 compute_query_id=on)、active(类 top 当前视图)、transitions(Sankey 状态转移图)。支持 interactive/daemon/replay 三种模式。

pgcenter 有哪些子命令?它的 profile 命令如何给慢 SQL 的 PID 做等待事件画像?

pgcenter 是 CLI 管理工具,子命令:config(配置 PG 配合)、profile(等待事件 profiler)、record(记录统计到文件)、report(基于快照生成报告)、top(top 类实时视图)。找慢 SQL 后:select pid, now()-query_start during, query, wait_event_type, wait_event from pg_stat_activity where wait_event is not null order by query_start limit 1; 拿到 PID,然后 pgcenter profile -h host -p port -U user -d db -P -F 10(每秒采样 10 次),输出该 PID 每条 SQL 的等待时间占比(如 97.9% Running、1.47% IO.DataFileExtend、0.63% IO.DataFileRead、LWLock.WALWriteLock 等)。report 命令支持 -A(activity)、-S(表大小)、-D(database)、-T(表)、-I(索引)、-V(vacuum)、-X(statements) 等多维度报告,本质是采样各统计视图打快照,与 AWR、performance insight 类似。

pgpro_stats 相比 pg_stat_statements 增加了哪些能力?

pgpro_stats 基于 pg_stat_statements 增强:保存查询的执行计划(plan)、支持配置采样率(query_sample_rate)降低开销、计算每类查询的等待事件统计(基于 profile_period 时间采样,默认 10ms)、支持自动化监控 metric 配置。可通过 pgpro_stats_statements 视图查看 query、plan、wait_stats,帮助分析执行计划和等待分布。

pgpro_stats 相比 pg_stat_statements 增加了哪些能力?它的等待事件采样如何工作?

pgpro_stats(Postgres Professional)基于 pg_stat_statements,额外提供:1)存储查询计划(plan、planid 列,可对比同一 queryid 的多个执行计划);2)可配置采样率 query_sample_rate(0.0~1.0 随机选查询统计,降低开销);3)等待事件统计 wait_stats(JSON 列,如 {“IO”:{“DataFileRead”:10}});4)自定义 metric(metric_N_name/query/period/db/user 配置,pgpro_stats_metrics 视图查看)。等待事件采样用时间采样:按 pgpro_stats.profile_period(默认10ms)周期采样,若进程正在等待就把该周期计入对应事件时长,因此即使周期变化时间估算仍有效;enable_profile=false 可关闭。关键参数还有 pgpro_stats.max(默认5000,最少执行语句被丢弃)、track(top/all/none)、track_utility、save、plan_format(text/xml/json/yaml)。

pgsentinel 插件如何记录活跃会话历史?相比 pg_stat_activity 增加了哪些列?

pgsentinel 是记录活跃会话历史的插件(类似 Oracle ASH),通过 background worker 以可配置周期采样 pg_stat_activity,存入内存 ring buffer,并可配合 pg_stat_statements 关联 query 统计。需加 shared_preload_libraries=‘pgsentinel’(需重启)。GUC:pgsentinel_ash.sampling_period(采样周期,默认1秒)、pgsentinel_ash.max_entries(ring buffer 大小,默认1000)、pgsentinel_pgssh.enable(是否采样 pg_stat_statements 历史)。它可视为 pg_stat_activity 的采样,额外增加了列:ash_time(采样时间)、top_level_query(PL/pgSQL 场景的最外层语句)、query(未归一化的真实语句,能看到具体值)、cmdtype(SELECT/UPDATE/INSERT/DELETE/UTILITY/UNKNOWN/NOTHING)、queryid(关联 pg_stat_statements)、blockers/blockerpid/blocker_state(阻塞者数量和 pid,直接定位谁堵了谁)。

pgsentinel 插件是如何记录活跃会话历史的?

pgsentinel 是记录历史活跃会话的扩展,需加入 shared_preload_libraries。它用后台 worker 按 sampling_period(默认 1 秒)周期采样 pg_stat_activity,写入内存 ring buffer(max_entries 默认 1000),可回看最近一段时间的历史会话状态,并关联 pg_stat_statements。相比只看当前状态,能回溯过去任意时刻谁在跑、谁被阻塞。

powa4 是什么监控工具?

powa4 是 PostgreSQL Workload Analyzer,带 WEB 展示的监控工具,提供索引推荐、等待事件分析、命中率、配置变更跟踪等功能。它聚合 pg_stat_statements、pg_wait_sampling 等插件数据,帮助 DBA 分析负载、发现慢 SQL 和缺失索引、跟踪配置变更历史。

为什么 ANALYZE 后执行计划反而变差?可能的原因有哪些?

罕见但真实,原因:1)ANALYZE 触发扩展统计重建,但表数据量极小(<100 行)时统计信息不稳定;2)ANALYZE 时 default_statistics_target 过大(>1000),导致 plan 过分依赖极小概率事件;3)表刚 bulk load,ANALYZE 在最热路径上与业务 DML 冲突。证伪:把 default_statistics_target 调回 100 重新 ANALYZE,或对大表分区独立 ANALYZE 对比。这说明统计信息并非’越细越好’,样本过小或采样过大都可能导致 planner 过拟合,需要结合 n_live_tup 规模合理设置 default_statistics_target。

为什么 GIN 索引有时不快?如何诊断和修复 pending list 问题?

GIN 索引更新走’快路径’(放 pending list),只在 VACUUM 时才合并到主索引。pending list 越大,查询时遍历 pending list 的开销越大,RT 升高。诊断:create extension pageinspect; select * from gin_metapage_info(get_raw_page(‘idx_xxx’, 0)); 看 n_pending_pages 字段,越大越慢。修复:VACUUM tbl 触发 pending list 合并。第一性原理:GIN 为’读多写少’设计,高频写时必须配套高频 vacuum(对应 JSONB/数组/全文搜索索引)。这也是为什么大量写入的 JSONB 表要频繁 vacuum、否则查询越来越慢的原因。

为什么 OFFSET 大分页会慢?正确做法是什么?

LIMIT 20 OFFSET 1000000 必须把前 100 万+20 条按 ORDER BY 排好序,再扔掉前 100 万条——OFFSET 不是’跳过’,是’排序再扔’。EXPLAIN ANALYZE 会看到 Sort + 大量 Buffers: shared read。正解是 Keyset 分页:select * from t where id > $last_seen_id order by id limit 20; 固定排序键+应用层记上一页最大 ID,走 Index Scan 不再 OFFSET。边界:Keyset 不支持随机跳页,跨页查询(‘跳到第 1000 页’)仍要用 OFFSET。自检 SQL:EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM t ORDER BY id LIMIT 10 OFFSET 1000000。

为什么 count(*) 会扫表?为什么 index-only scan 有时还是会回表?

count(*) 扫表:PG 没有’记录总数’缓存(不像 MySQL InnoDB),必须扫可见版本链——MVCC 让每行有多个版本,count 必须判断哪些版本对当前事务可见。优化:用 pg_class.reltuples(统计估算,精度±10%)、物化视图、计数器表、采样估算(T-digest/HLL)。index-only scan 回表:它有 visibility map(VM)前提,只有当 VM 标记页面全部可见时才能纯索引返回,若页面有未提交事务产生的 dead tuple,仍需回表确认 visibility。诊断:VACUUM 后 index-only scan 概率升高(因为 VACUUM 维护 VM);查 pg_stat_all_tables 的 heap_blks_hit/idx_blks_read 或 pg_statio 系列看回表情况。

为什么 push/pull 大量数据慢?如何优化批量数据搬运?

核心原因:走 simple query 协议(每个语句单独解析/规划/执行),大量 round-trip;以及单条事务的 fsync。第一性原理:网络 round-trip + 单条事务 fsync = 大量数据搬运的两大成本。优化方向:1)用 prepared + bind(PREPARE p1 AS … EXECUTE)走 extended query 协议,省去重复解析;2)用 COPY 替代 INSERT(10x~100x 提速);3)批量提交(单事务 1000 行比单行快 100 倍,少 1 万次 fsync,参考 56 核 NVMe 上单行提交约 1500 行/s vs 单事务 1000 行约 145 万行/s);4)异步提交 SET synchronous_commit=off(配合 wal_writer_delay=10ms,最坏丢 3×wal_writer_delay)。

为什么 shared_buffers 设太大反而慢?PG16+ 有什么改进?

shared_buffers=RAM×1/4 是经验值。PG16 之前,超过 RAM 25% 后 buffer mapping 的 LWLock 争用急剧上升——所有 backend 抢 buffer tag 的 hash 表,表现为 wait_event 大量 LWLock:buffer_mapping。PG16+ 引入 8 个 buffer mapping 分区,大幅缓解争用,可以设到 40% 甚至更高,但仍需权衡:shared_buffers 越大 → OS page cache 越小,而 OS page cache 命中率对 planner 估算的 effective_cache_size 影响变小。判断:若 wait_event 分布中 buffer_mapping 占比高,说明 shared_buffers 偏大,应调小或升级 PG16+。

为什么 vacuum 不能并行回收同一张表?有什么替代方案?

PG 的 vacuum 是单进程扫表(maintain single relation lock),即使开 8 个 autovacuum worker,也只能在不同表上并行,同一张表内 vacuum 只能串行——这是大表 vacuum 慢的根因。替代方案:1)用 pg_partman 把大表分区,让 vacuum 在分区级并行(不同分区不同 worker);2)PG14+ 的 vacuumdb –parallel 仅对 index cleanup 阶段并行(主扫描仍串行);3)用 pg_prewarm 主动加载热点。理解这点有助于解释’大表为什么 vacuum 总是慢’,并指导大表按时间/范围分区以分散 vacuum 压力。

为什么要监控事务年龄 datfrozenxid?xid 回卷会导致什么灾难?

PG 的 xid 是 32-bit 无符号整数(PG17+ 可选 64-bit),最多 2^32≈43 亿,循环使用(wraparound)。当某表 relfrozenxid 距回卷点 <200000000(autovacuum_freeze_max_age)时,autovacuum 强制 freeze;xid 真正回卷后,原本’过去’的事务会变成’未来’的事务,数据突然消失,数据库进入保护模式拒绝写入只允许 VACUUM(著名’PG 库变只读’事故)。监控:select datname, age(datfrozenxid) from pg_database order by 2 desc; 任一库>2 亿报警、>15 亿紧急。治理:平时保持 autovacuum_freeze_max_age=200000000(默认不要改)、大表单独 SET 更大值、紧急手动 VACUUM FREEZE,绝对不要用 pg_resetwal 等清零工具。

分层定位漏斗如何用于故障诊断?报警后 5 分钟内该走哪条路径?

任何报警先分层:OS 层健康?(CPU/IO/内存/磁盘/网卡)→ 网络层?(带宽/RTT/丢包/防火墙)→ PG 实例存活?(连接打满/postmaster 死/crash)→ 数据库级?(锁等待/长事务/autovacuum 风暴)→ 表/索引级?(膨胀/统计失准)→ 最后才是单条 SQL。适用边界:本地单实例 PG 适用;托管 RDS 上 OS/网络层由云厂负责,只能拿到 PG 层指标。核心观点:SQL 层优先 + 漏斗排查补充——先用 pg_stat_statements 擒贼擒王(命中大多数场景),再按 OS/长事务/2PC 漏斗排查(命中突发场景)。证伪:OS、PG 实例、锁、autovacuum 都没事但业务还慢,说明不是 DB 层,去查 APP 层(连接池、ORM、GC、上下游)。

半小时用 Sampler 搭建 PG 简易监控,应监控哪几个关键指标?SQL 怎么取?

Sampler 是 Go 写的轻量监控工具,无需 agent/数据库,用 shell 命令取样展示。应监控:1)数据库年龄:select age(datfrozenxid) from pg_database where datname=current_database()(21 亿事务限制,到 2^31-1000 万打印 WARNING,剩 100 万变只读);2)写入量:基于 pg_stat_bgwriter,8*(buffers_checkpoint+buffers_clean+buffers_backend)/1024 得总写 KB,buffers_backend 过大说明 shared buffer 没维护好;3)缓存命中率:round(sum(blks_hit)100/sum(blks_hit+blks_read),2) from pg_stat_database(未考虑 page cache);4)事务提交回滚率:round(100(xact_commit/(xact_commit+xact_rollback)));5)服务器负载/CPU/内存;6)连接监控:按 state 分组 count(active/idle/idle in transaction),PG 是进程模型需防连接风暴。表膨胀、锁、vacuum 也可扩展。

如何判断一个会话是否使用了 SSL 连接?pg_stat_ssl 视图和 sslinfo 插件怎么用?

客户端连接时可以选择 sslmode(disable/prefer/require 等),服务端要判断具体会话是否走了 SSL,两种方法:1)sslinfo 插件:create extension sslinfo; select * from ssl_is_used(), ssl_cipher(); ssl_is_used() 返回 t/f,ssl_cipher() 返回如 ECDHE-RSA-AES256-GCM-SHA384。2)pg_stat_ssl 视图:select * from pg_stat_ssl where pid=pg_backend_pid(); 字段 pid、ssl(布尔)、version(如 TLSv1.2)、cipher、bits(如256)、compression、clientdn。PG12 增加客户端证书信息输出:新增 client_serial、issuer_dn 列,并把 clientdn 改名为 client_dn。可用于安全审计、确认哪些连接是明文哪些是加密。

如何根据 wait_event 的主导事件快速判断瓶颈并采取动作?举几个典型映射。

常用映射:IO:DataFileRead 主导 → iostat -x 1 看 r_await>10ms,pg_prewarm 预热热点或换 SSD;IO:WALWrite → iostat 看 w_await,检查主备复制延迟/同步复制降级;IO:ControlFileSync → checkpoint 风暴,设 checkpoint_completion_target=0.9;LWLock:buffer_mapping → shared_buffers 设太大(>RAM 25%),调小或升级 PG16+(8 分区优化);LWLock:lock_manager → 单实例连接数>500,上 pgbouncer;Lock:transactionid → 看 pg_blocking_pids,应用层事务顺序不一致;Lock:tuple → 看具体 SQL + blocking,用 SKIP LOCKED 改写。若 state=active 且 wait_event IS NULL,说明在 CPU 上跑(大排序/哈希聚合),用 perf top -p pid 判断是否 CPU bound。

如何理解 Linux read 调用的 IO 分层和各层测量工具的差异?

Linux 分层次:Userspace(应用、glibc)→ Kernelspace(系统调用接口、子系统 VFS/内存/进程、架构代码/驱动)→ Hardware(物理设备)。测量 IO 延迟时要注意:1)测量是平均还是绝对(平均值掩盖峰值,采样时间越长越平均);2)测量来自哪一层:iostat/sar/node_exporter 从 /proc 取(level 5 设备层);bcc 的 xfsdist/xfsslower 来自 level 3;biosnoop/biolatency 来自 level 5;perf trace/strace 来自 level 3;应用数据来自 level 1。不同层包含不同工作量,数值可能不同,且 strace/perf 自身会引入显著延迟,生产要极其谨慎。还要区分 buffered IO(用 page cache)和 direct IO(O_DIRECT 直接读进程地址空间),默认 Linux 全是 buffered。云环境 IO 延迟会波动,做 fio benchmark 时避免 bursting(突发模式相当于测两个系统)。

如何用 EXPLAIN 解读慢 SQL 的 6 个信号?EXPLAIN ANALYZE 有什么必避坑?

EXPLAIN (ANALYZE, VERBOSE, BUFFERS, TIMING, COSTS, SETTINGS, FORMAT TEXT) 读 6 个信号:1)actual time(真耗时,首行/末行,loops 相乘才是真实成本);2)rows vs actual rows(偏差>10× → 统计信息失真,需 ANALYZE);3)Buffers: shared hit/read(read 占比高 → shared_buffers 不够);4)loops(>1 多半 NestLoop 嵌套,cost 数字骗人);5)节点类型(Seq Scan/Index Scan/Bitmap Heap Scan/Hash Join/Sort);6)SETTINGS(打印实际生效的优化器参数,如 random_page_cost)。必避坑:EXPLAIN ANALYZE 真的执行 SQL!对 INSERT/UPDATE/DELETE 必须包 BEGIN; EXPLAIN ANALYZE …; ROLLBACK; 否则会真的改数据。

如何用 pg_blocking_pids 找出锁阻塞链?锁雪崩的三种典型形态是什么?

PG 9.6+ 提供 pg_blocking_pids(pid) 函数:select pid, pg_blocking_pids(pid) blocked_by, wait_event_type, wait_event, query from pg_stat_activity where wait_event_type=‘Lock’; 可递归找出谁堵谁,沿 blocked_by 一路回溯即得阻塞链(A→B→C…)。锁雪崩三形态:1)大事务持锁,小事务都等,一个慢查询卡 100 个 worker;2)大锁被已有长事务的小锁堵塞——DDL(ACCESS EXCLUSIVE)被普通 SELECT 阻塞,后续所有 DDL/DML 排队;3)高并发小锁等大锁——秒杀场景几百事务抢同一行 FOR UPDATE。第一性原理:没有超时=没有雪崩保护,DDL 必须包事务设 SET LOCAL lock_timeout=‘100ms’。

如何用 pg_stat_statements 抓 TOP SQL?它有哪些关键字段,分别代表什么含义?

pg_stat_statements 是 PG 内置 SQL 统计插件,需加到 shared_preload_libraries 并 create extension。抓 TOP SQL:select round(total_exec_time::numeric,2) total_ms, calls, round(mean_exec_time::numeric,2) mean_ms, rows, shared_blks_hit+shared_blks_read blks, query from pg_stat_statements order by total_exec_time desc limit 10;。关键字段:queryid 是查询指纹(同版本内规范化后稳定,跨 major 版本可能变化);query 是归一化后的 SQL(参数被替换为 $n);calls 调用次数;total_exec_time/mean_exec_time 总/平均执行时间(PG13+ 字段名);rows 总返回行数;shared_blks_hit/read 共享缓存命中/落盘块数。据此可快速找出耗时最长、消耗 IO 最多的 SQL。

如何用触发器和 C 扩展跟踪记录是谁写入/更新的,以及被更新了多少次?

跟踪写入者:用 contrib/spi 的 insert_username 扩展或 plpgsql 触发器。insert_username() 是 C 触发器,把 current_user 写入指定 text 列,创建 BEFORE INSERT OR UPDATE 触发器并传列名参数即可(如 create trigger … before insert or update on t for each row execute procedure insert_username(username))。plpgsql 版:create or replace function tg2() returns trigger as $$ begin new.username := current_user; return new; end $$ language plpgsql。跟踪更新次数:plpgsql 触发器 new.updcnt := old.updcnt+1;或用 contrib/spi 的 autoinc 扩展(autoinc() 把 sequence 下一个值写入 int 字段,可覆盖插入值,也支持 UPDATE 时递增,与 serial 列不同,需传列名+sequence 名成对参数)。plpgsql 触发器写法通用、C 触发器性能更高。

如何监控表膨胀?B-Tree 索引膨胀的硬伤是什么,如何处理?

找膨胀表:select schemaname||’.’||relname tbl, pg_size_pretty(pg_total_relation_size(oid)) total_size, n_live_tup, n_dead_tup, round(100.0*n_dead_tup/nullif(n_live_tup,0),2) dead_pct from pg_stat_user_tables where n_dead_tup>10000 order by n_dead_tup desc limit 20。找膨胀索引用 pgstattuple(‘idx’) 看 dead_tuple_percent(>30% 值得 REINDEX)。B-Tree 的硬伤:不释放空间,只 REUSE。DELETE 后索引项变 dead tuple,vacuum 标记后加入 FSM,新 INSERT 复用 dead slot;若长期无 INSERT 则永远不释放物理空间,且 nbtree 用双向链表连接 leaf page,一个 page 只剩 1 个有效 item 也不能释放,HEAP 水位能降但索引水位几乎只能 REINDEX。PG12+ 用 REINDEX INDEX CONCURRENTLY 不阻塞写,PG14+ 支持 REINDEX TABLE CONCURRENTLY。

如何诊断 autovacuum 风暴和 checkpoint 风暴?pg_stat_bgwriter 怎么看?

突发 IO/CPU 但 TOP SQL 无变化,答案多在后台进程三件套:autovacuum + checkpoint + bgwriter。autovacuum 风暴:查 pg_stat_progress_vacuum 看 worker 在跑哪些表、进度;查 select datname, age(datfrozenxid) from pg_database order by 2 desc,任一>200000000 触发 anti-wraparound vacuum(这是突然变卡的最大单一原因,autovacuum_freeze_max_age 硬编码防线)。checkpoint 风暴:select * from pg_stat_bgwriter,checkpoints_req 远多于 checkpoints_timed → 雪崩式 checkpoint,应增大 max_wal_size、延长 checkpoint_timeout、checkpoint_completion_target=0.9 摊平 IO。bgwriter:buffers_backend > buffers_clean → backend 写盘太多,bgwriter 不够,调大 bgwriter_lru_maxpages。证伪:临时关 autovacuum 看 IO 是否立刻下降。

如何诊断流复制延迟?send_lag/flush_lag/replay_lag/xmin 四段各代表什么?

先分清 send 慢还是 replay 慢:主库 select client_addr, state, sent_lsn, replay_lsn, (sent_lsn-replay_lsn) byte_lag from pg_stat_replication; 备库 select pg_last_wal_replay_lsn(), pg_last_wal_receive_lsn()。四段拆解:send_lag(primary→standby 网络,primary 写网卡速率/带宽,通常<1ms);flush_lag(standby 刷 WAL,受备盘 IO,synchronous_commit=on 强制 fsync);replay_lag(standby 应用 WAL,受备机 IO 和并行回放 worker 限制);xmin horizon(logical slot 或 hot_standby_feedback 卡死)。第一性原理:send 是网络问题,replay 是备机执行能力问题,xmin 不前进是全局被事务卡住问题,三件事分开看。证伪:暂时关掉 hot_standby_feedback,延迟立刻消失 → 锁定是 feedback 导致。

如何诊断连接风暴与连接打满?pgbouncer 出问题时怎么查?

PG 是进程模型,连接=进程,连接打满会导致拒连。诊断:select count(*), state from pg_stat_activity group by state; 看 active 是否接近 max_connections;再查最老 idle 连接 select pid, usename, application_name, now()-state_change idle_age from pg_stat_activity where state=‘idle’ order by idle_age desc limit 10。治理:立刻 pg_terminate_backend 最老 idle 连接腾位置(仅 superuser)、排查 APP 连接池泄漏、长期上 pgbouncer、预防设 idle_session_timeout=‘1h’(PG14+)。pgbouncer 故障:psql -p 6432 pgbouncer 后 SHOW POOLS 看 sv_active/pool_size,>0.8 说明后端不够;cl_waiting>0 说明前端在排队;SHOW STATS/SHOW SERVERS 看总量和映射。pool_size 太小时 sv_active=pool_size 全部满载,新客户端排队直到 query_wait_timeout 超时报错。

故障诊断的三个救命查询和止血三件套分别是什么?

三个救命查询:1)谁在跑 select pid, now()-query_start duration, state, wait_event_type, wait_event, query from pg_stat_activity where now()-query_start > interval ‘5s’ and state=‘active’; 2)谁在等(长事务/空闲事务/2PC)select pid, state, now()-xact_start xact_age, query from pg_stat_activity where state in (‘idle in transaction’,‘idle in transaction (aborted)’) and now()-xact_start > interval ‘30min’; 以及 select * from pg_prepared_xacts where now()-prepared > interval ‘1h’; 3)谁锁了谁 select pid, pg_blocking_pids(pid) blocked_by, wait_event_type, wait_event, query from pg_stat_activity where wait_event_type=‘Lock’。止血三件套:pg_terminate_backend(pid)(杀会话)、pg_cancel_backend(pid)(只杀当前 query)、SET LOCAL lock_timeout(DDL 加超时)。预防参数:statement_timeout=30s、lock_timeout=5s、deadlock_timeout=1s、idle_in_transaction_session_timeout=10min、idle_session_timeout=1h(PG14+)。

监控 PG 必须先开的 5 个统计开关是什么?为什么每个都必须开?

5 个必开开关:track_activities=on(否则 pg_stat_activity 拿不到会话信息);track_counts=on(否则 pg_stat_*_tables、pg_stat_database 累计计数器为空);track_io_timing=on(否则拿不到 blk_read_time 及 pg_stat_statements 的 IO 时间);track_functions=‘all’(否则 pg_stat_user_functions 无数据);compute_query_id=on(PG13+ 默认,作为 pg_stat_activity.query_id 与 pg_stat_statements 关联的桥梁)。另外半必开日志开关:log_lock_waits=on、log_temp_files=0、log_min_duration_statement=3s。改完 select pg_reload_conf() 生效,任何一个没开对应视图就是空的。

磁盘满、WAL 堆积、replication slot 卡死如何排查和紧急处理?

磁盘满排查:df -h /pgdata 定位目录,du -sh /pgdata/pg_wal/* 和 du -sh /pgdata/base/* 看 WAL 和哪个库占最多;找最大对象 select n.nspname||’.’||c.relname, pg_size_pretty(pg_total_relation_size(c.oid)) from pg_class c join pg_namespace n on n.oid=c.relnamespace where c.relkind in (‘r’,‘i’) order by pg_total_relation_size(c.oid) desc limit 20。WAL 堆积:查 replication slot 状态 select slot_name, plugin, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) lag_bytes from pg_replication_slots。logical slot 卡死:select slot_name, xmin from pg_replication_slots where xmin is not null 找出 xmin 不前进的 slot,重启消费端或 pg_drop_replication_slot。紧急清理:先 pg_switch_wal 归档、调小 wal_keep_size,绝对不要删未归档的 WAL。

阿里云 RDS PostgreSQL 自定义告警应配置哪些指标?各指标的合理阈值是什么?

RDS PG 云盘版需自行添加告警规则,建议配置(连续三次触发):1)active_connections_per_cpu 每 cpu 平均活跃连接数 >=2(与核数无关,8 核设 2 表示 16 活跃连接,负载已高);2)conn_usage 连接数使用率 >=80%;3)cpu_usage CPU 使用率 >=80%;4)local_fs_inode_usage inode 使用率 >=80%;5)local_fs_size_usage 空间使用率 >=80%;6)iops_usage 数据盘 IOPS 使用率 >=80%;7)mem_usage 内存使用率(排除 clean page cache)>=80%。周期和连续次数按业务调整。这是云上 RDS 监控的实操清单,覆盖连接、CPU、磁盘、inode、IOPS、内存六类核心容量指标,避免磁盘满、连接打满、CPU 打满等事故。