实战指南:11 项自动检查、图表判读方法与源码实现解析)
Coroot Postgres 健康巡检Inspections实战指南11 项自动检查、图表判读方法与源码实现解析【免费下载链接】corootCoroot is an open-source observability and APM tool with AI-powered Root Cause Analysis. It combines metrics, logs, traces, continuous profiling, and SLO-based alerting with predefined dashboards and inspections.项目地址: https://gitcode.com/GitHub_Trending/co/corootCoroot 将 Postgres 视为一类需要持续体检的组件由 cluster-agent 连接每个已发现的实例、读取pg_stat_activity、pg_stat_statements、pg_stat_replication等系统视图采集指标再由审计器auditor基于这些指标运行一组带默认阈值的自动检查availability、latency、replication lag、connections、checkpoints、WAL archiving、wraparound、autovacuum、stale statistics、bloat、backups每项检查超标即产生告警并附带辅助图表。本文按官方文档 Postgres 巡检页 的脉络逐项讲解每个检查的触发条件、默认阈值、图表判读方法并对照 auditor/postgres.go、model/check.go 等源码说明这些判定是如何落地的帮助你在读完之后既能看懂巡检报告中的每一张图也能定位到产生该结论的代码逻辑。数据来源cluster-agent 与系统视图在深入各个检查之前先明确数据链路。Coroot 的 Postgres 指标并非来自 Postgres 自带的 exporter而是由独立的 cluster-agent 采集见 cluster-agent 指标说明agent 通过 Coroot 服务地图和 Kubernetes 控制面发现数据库实例使用 Coroot 提供或 Kubernetes 注解中的凭据连接 Postgres每次抓取scrape时验证连接存活形成pg_up指标指标来源包括pg_stat_activity、pg_stat_statements、pg_stat_replication、pg_stat_archiver、pg_stat_user_tables、pg_class等系统视图备份状态则不来自数据库本身而是读取 CloudNativePG 和 Percona Operator 的自定义资源见 Postgres backups按查询维度的指标只对 TOP-20 按总执行时间排序的查询采集且查询文本会被归一化、参数打码例如SELECT * FROM tbl WHERE id1归并为SELECT * FROM tbl WHERE id?以避免标签基数爆炸查询 I/O 时间来自pg_stat_activity.wait_event_type IO与pg_stat_statements的blk_read_time/blk_write_time。一个容易被忽视的前置条件如果实例没有开启track_io_timing按查询的 I/O 时间恒为零。Coroot 的巡检器会检测这种情况并在报告中直接给出配置提示——auditor/postgres.go 中的pgConfigurationHints函数会检查track_io_timing采样值若为 0 则附加 Enable track_io_timing to attribute disk I/O to specific queries 的提示。指标采集后由 constructor/postgres.go 组装成 model/postgres.go 中的Postgres结构按连接状态分组的Connections、按查询键db/user/query分组的PerQuerycalls、total_time、io_time、WAL 相关序列WalCurrentLsn、WalReceiveLsn、WalReplayLsn、WalArchivedSegments等、checkpoints、表级死元组与膨胀数据、Settings参数序列等全部以*timeseries.TimeSeries时间序列形式保存供审计器计算。报告结构检查项 实例总览表巡检报告以一组自动检查开头每个检查跨越阈值时产生告警并附带支撑图表。阈值可按项目project配置也可以按应用application单独覆盖。检查项与默认阈值定义在 model/check.go 的Checks表中汇总如下均可在项目设置中调整检查项默认阈值判定条件ConditionFormatTemplatePostgres availability0 个实例不可用 Postgres 实例数 阈值Postgres latency0.1 s实例平均查询执行时间 阈值Postgres replication lag30 s复制延迟 阈值Postgres connections90 %连接数 max_connections的阈值百分比Postgres checkpoints3 ×checkpoint_timeout距上次 checkpoint 时间 阈值Postgres WAL archiving最近一次归档失败最近一次 WAL 归档尝试失败Postgres transaction ID wraparound50 %事务 ID age 超过回绕上限的阈值百分比Postgres bloat50 %数据库估算浪费空间超过其大小的阈值百分比Postgres autovacuum2 × 触发阈值表的死元组超过其 autovacuum 触发阈值的倍数且有可观量Postgres stale statistics2 × 触发阈值大表的修改行数超过其 autoanalyze 触发阈值的倍数Postgres backups86400 s24h阈值内无成功备份、上次备份失败或连续 WAL 归档损坏检查项下方是每实例总览表列固定为 Instance含版本标签、Roleprimary/replica 并带图标、Status、QueriesQPS、Latency毫秒、Replication lag字节数 折算的时间、DB Size。auditor/postgres.go 中tableColumns常量定义了这七列Role 由ClusterRoleLast()得出Status 列在实例不可用时展示 agent 记录的错误信息或 down (no metrics)若存在告警则附带 warning 文本——这样一眼就能看出故障发生在 replica 还是 primary。Availability实例可达性检测不可达或不接受连接的 Postgres 实例。agent 在每次抓取时验证连接存活pg_up检查项统计实例不可用的时间占比IsUp()在 model/postgres.go 中就是Up.Last() 0的简单判断。不可用时auditor/postgres.go 会把实例加入availabilityCheck并从Postgres.Error对应采集侧的pg_scrape_error取出错误文案写入 Status 列。Latency平均查询延迟对平均查询延迟超过阈值默认 0.1s的实例告警。Coroot 把pg_stat_statements中已完成查询的统计与pg_stat_activity中的在途查询合并采集侧由pg_top_query_calls_per_second、pg_top_query_time_per_second两个指标支撑后者对在途查询用clock_timestamp() - pg_stat_activity.query_start计时因此慢查询在结束之前就能被看见。报告为每个实例提供以下图表用于定位原因Average query latencyavg、p50、p95、p99来自pg_latency_seconds的各 summary 标签。分布形态能告诉你劣化形状p50 上升说明所有查询都变慢p99 上升而 p50 持平说明只有少数慢查询长尾。用选择器切换实例可判断是集群性问题还是单节点问题。Queries per second。负载在涨还是在跌。如果延迟上升但查询量没有增加原因在数据库内部锁、I/O、坏执行计划而非入口流量。Queries by total time。按消耗容量给查询排名榜首通常是该优化的对象某条查询突然冲到这里往往是性能回归点。Queries by I/O time。若慢查询的时间主要花在 I/O 上说明它在等磁盘缺索引或缓存未命中而不是 CPU。Active connections by query与Idle transactions by query。展示繁忙 backend 实际在跑什么并暴露持有锁和快照的idle in transaction会话。Locked queries与Blocking queries。当劣化源于争用时直接点名阻塞其他查询的那条查询——阻塞方是通过pg_blocking_pids()归因的采集指标pg_lock_awaiting_queries的blocking_query标签即由此计算。auditor/postgres.go 中pgQueries函数从PerQuery中拆出TotalTime与IoTime两张 Top-5 堆叠图延迟告警的判定就是对i.Postgres.Avg.Last()与latencyCheck.Threshold比较。Replication lag复制延迟检测落后主库过多的副本默认 30s。Coroot 刻意把复制拆成两个阶段以区分*传输shipping问题网络或 WAL sender与回放apply*问题replay 卡住或被暂停。源码实现清晰印证了这一点auditor/postgres.go 中先用所有实例WalCurrentLsn的Max聚合出主库 LSN总延迟为primaryLsn - replayLsn而 Replication stages 图用两条堆叠序列分别绘制shipping (not yet received)primaryLsn - receiveLsn与apply (received, not yet replayed)receiveLsn - replayLsn。图表判读方法Replication lag, bytes。每个副本落后主库多远。看缺口是平稳的跟得上但一直落后还是持续爬升越落越远以及落在哪个副本上。Replication stages。shipping 段占主导说明 WAL 没到达副本网络问题或 WAL sender 慢/过载apply 段占主导说明 WAL 已到达但回放卡住典型原因是副本上的长查询引发 recovery conflict或 replay 被暂停。WAL throughput。主库上的 WAL 生成突发可以解释临时延迟尖峰——副本只是有更多数据要追。副本卡住时Coroot 还会直接点名原因。checkReplicationLag除了比较延迟字节数还会沿主库 LSN 序列回溯把字节差折算成时间差展示pgWalStallCause按优先级输出具体原因pg_wal_replay_paused置位 → WAL replay is pausedWalReceiverStatus为 0 → the standby is not connected to the primary否则比较 apply 与 shipping 的大小输出 WAL replay is slow or blocked (check standby queries and disk I/O) 或 WAL shipping cant keep up (network or primary load)。Connections连接数当实例连接数逼近max_connections默认 90%时告警。连接耗尽会阻止新客户端接入包括故障切换工具。判定逻辑在pgConnections函数按连接状态idle、active、idle in transaction以及active且wait_event_type Lock时单独归入active (locked)聚合连接数再叠加保留连接——代码同时读取superuser_reserved_connections和rds.rds_superuser_reserved_connections两个参数因此也覆盖了 AWS RDS 的保留连接语义。连接总数 /max_connections× 100 超过阈值即加入检查项。图表判读Connections。按状态堆叠并画出max_connections参考线。观察总量离线多近、哪个状态在涨。一片idle in transaction通常意味着客户端开了事务却不提交应用 bug 或泄漏的事务这些会话还持有锁和快照会阻塞 vacuum 和其他查询。Idle transactions by query。点名哪些查询的会话停在 idle in transaction帮你定位出问题的代码路径。Active connections by query。连接尖峰时活跃 backend 在跑什么指向驱动需求的负载。Checkpoints检查点停滞标记停滞或逾期的 checkpoint。距上次完成 checkpoint 过久会拉长崩溃恢复时间也可能意味着 checkpointer 卡住或 WAL 压力过大。Coroot 与复制检查共享同一套 WAL 停滞诊断pgCheckpointStallCause先调用pgWalStallCause例如磁盘满、archiver 卡住、复制槽扣留 WAL 等。源码中告警条件比较严格两个条件同时满足才计入距上次 checkpoint 超过checkpoint_timeout × 阈值倍数默认 3 倍且自上次 checkpoint 以来积累的 WAL 超过一个 16MB 段pgWalSegmentSizeBytes。避免在低负载时段因定时 checkpoint 尚未触发而误报。图表判读Time since last checkpoint。对照阈值线图中线即阈值倍数 × checkpoint_timeout。持续越过线说明 checkpoint 未完成。WAL to replay in the case of a crash。崩溃需要重放的 WAL 量即你的恢复时间。健康时应呈锯齿状在每个 checkpoint 处回落持续爬升印证 checkpoint 没完成。Checkpoints与Checkpoints by trigger。如果以requested由max_wal_size触发为主而非timed由checkpoint_timeout触发说明max_wal_size相对写入速率偏小导致频繁且昂贵的 checkpoint。Checkpointer write throughput。checkpointer 刷脏页的工作强度用于把 checkpoint 尖峰与 I/O 压力关联起来序列值为 buffer 数 × 8kB 块大小代码中pgBlockSize 8192。WAL archiving归档失败检测失败的 WAL 归档archive_command。WAL 无法外运时会在本地磁盘堆积并破坏时间点恢复PITR。该检查基于pg_stat_archiver对任意 Postgres 生效不依赖 operator。实现上是单点判断pgArchivingIsFailing检查WalArchivingStatus.Last() 0archiving 状态不是 ready成立则给该实例追加详情 the last WAL archive attempt failed - check archive_command and the archive storage。图表为每实例的 archived 与 failed 分段柱状图failed系列出现任何柱子即表示archive_command在报错凭据错误、存储不可达、桶已满。归档失败时 WAL 无法回收WAL 目录会持续增长见下文 Storage WAL且 PITR 不再有完整归档。Transaction ID wraparound事务 ID 回绕当最老事务或多事务multixactage 逼近回绕上限时告警默认2 billion 预算的 50%。放任不管会触发紧急 anti-wraparound vacuum最终可能导致数据库为保护数据而关闭值得尽早发现。源码细节auditor/postgres.go 中回绕上限常量pgWraparoundLimit 1 31约 21 亿告警值按worstAge / pgWraparoundLimit × 100计算。图表判读Transaction ID age与Multixact ID age。按库的 age对照autovacuum_freeze_max_age参考线。逼近线的库正在接近强制 anti-wraparound vacuum某个库的 age 稳定增长指向 vacuum 没有冻结其表。Oldest transaction ID held back。把钉住冻结地平线freeze horizon的原因归因到四类持有者running_transaction、replication_slot、standby_feedback、prepared_transaction直接告诉你该终止或清理什么让 vacuum 能重新推进地平线。归因逻辑在pgDominantXminHolder中并带两个经验比例持有者 age ≥ 冻结 age 的 80%pgXminHolderDominantRatio时判定vacuum cannot freeze past the oldest transaction ID并给出对应动作——drop/推进落后槽、结束长事务、提交或回滚 prepared 事务、降低开了hot_standby_feedback的 standby 延迟若持有者年龄只占 10%pgXminHolderMaterialRatio以下则回落到 autovacuum is not freezing fast enough 的通用建议。若是长事务还会附上最老事务所在库、已开启时长与查询文本。Autovacuumvacuum 落后检测 autovacuum 落后默认死元组达到该表 autovacuum 触发阈值的 2 倍以上。vacuum 跟不上时膨胀与回绕风险都会增长。压力指标的定义是精髓死元组数 ÷ (autovacuum_vacuum_threshold autovacuum_vacuum_scale_factor × reltuples)即归一化到该表自己的触发阈值。健康表围绕 1 锯齿波动越过 1 才会触发 vacuum持续高于 1 说明没被服务到因为归一化了大表的正常峰值不会误报。auditor/postgres.go 的pgAutovacuum实现里还有几个避免误报的门槛只有死元组字节数 ≥ 512 MiBpgDeadTupleMinBytes的表才参与告警排序——这样你关注的是真正持有大量可回收空间的表而不是一个远超触发阈值的小表。此外计算触发阈值时支持读取表级ALTER TABLE ... SET (autovacuum_vacuum_threshold / scale_factor)覆盖值pgTableSetting。图表判读是否落后与为什么Autovacuum Pressure。见上。Dead tuples by table。以字节计的体量聚焦真正持有大量可回收空间的表。Time since last autovacuum by table。表若很久以前才被 vacuum说明 autovacuum 没在跑被禁用、被饿死或参数失当若最近刚 vacuum 过死元组却还在堆积说明有快照钉住了 vacuum 地平线长事务、prepared 事务或复制槽——此时看上面 Oldest-xmin holder 图。Autovacuum workers与Throttled autovacuum workers。若所有 worker 都忙代码判定最近 5 个点均值 ≥autovacuum_max_workers − 0.5vacuum 在等空闲 worker提高autovacuum_max_workers若 worker 已在表上但处于限流状态单表 throttled 均值 ≥ 0.5说明它在 cost-based delay 上睡觉提高autovacuum_vacuum_cost_limit或降低autovacuum_vacuum_cost_delay。源码中最有实战价值的是根因文案pgAutovacuum会为最严重的表生成具体原因——表上autovacuum_enabledfalse、某类持有者钉住了 vacuum 地平线并附最老长事务的库与查询、vacuum 在跑但太慢大表或慢存储、被该表自定义的 cost_delay/cost_limit 限流、worker 忙但被 cost 上限限流加 worker 也没用、或 autovacuum last ran N ago。同时它按根因类型动态挂载对应图表复制槽问题挂 slots 图、长事务挂 longest transaction 图、限流挂 throttled 图让报告里出现的就是与诊断结论相关的证据。Stale statistics统计信息过期检测规划器统计信息过期的表默认修改行数达到 autoanalyze 触发阈值的 2 倍以上。统计信息过期会让规划器选错计划是批量加载或写入突发后延迟突然回归的常见原因。Autoanalyze Pressure。修改行数 ÷ 该表自己的 autoanalyze 触发阈值同样支持表级覆盖参数。大表持续高于约 2x 说明近期没有 analyze规划器在用过期行数估算。Time since last analyze by table。确认统计过期了多久以及 autoanalyze 是否在该表上被禁用。修复手段就是执行ANALYZE。源码中pgStaleStatistics设了一个过滤条件只有reltuples ≥ 100000pgStaleStatsMinRows的表才会触发检查项小表的统计过期没有实际影响。Bloat表与索引膨胀估算表与索引的浪费空间标记膨胀超过阈值的库默认 50%。膨胀空间只能靠VACUUM FULL、pg_repack或REINDEX归还给操作系统区别于普通 vacuum 即可回收复用的死行。Estimated bloat by database。总估算浪费空间看哪个库最差、是否在趋势性上涨。Top tables by estimated bloat与Top indexes by estimated bloat。具体要处理的关系。膨胀表用VACUUM FULL或pg_repack重写膨胀索引用REINDEX重建。pgBloat的判定有个门槛只有膨胀量 ≥ 1 GiBpgBloatMinBytes的库才参与检查避免小库因高比例产生噪音超阈值时详情会给出 is X% bloated (~Y wasted) 并附上库内膨胀最严重的表/索引结尾统一建议 reclaim with pg_repack (online) or VACUUM FULL (locks)。膨胀图与磁盘使用、最大表同组展示见下文 Storage WAL。Backups备份健康针对 CloudNativePG 或 Percona Operator 管理的集群报告备份是否健康。告警条件包括最近一次成功备份早于阈值默认 24h、备份失败、连续 WAL 归档损坏、或计划内备份逾期由 cron schedule 与最近备份推导调度器停摆也能被抓到。备份失败时Coroot 会直接展示 operator 的 condition reason 及可读化提示。这一节展示备份状态、目标destination、计划schedule、保留策略retention、上次/下次备份、可恢复窗口以及一个Recent backups列表最多 20 条含每次运行的类型、状态、完成时间。auditor/postgres.go 的pgBackups实现值得细看最近成功备份取各 method 的LastSuccessfulBackup与所有成功 run 完成时间的最大值逾期判定解析备份的 cron schedule先按标准 5 段格式失败再尝试含秒的 6 段格式从上次成功时间推出本应发生的下次备份若当前时间超过该时点 15 分钟pgBackupScheduleGrace且没有备份正在进行判定调度器可能没在跑原因聚合无成功备份记录、the last successful backup was N ago、the last backup attempt failed (reason)、continuous WAL archiving is failing当 operator 没有ContinuousArchivingcondition 时回退到逐实例检查pg_stat_archiver状态、the cluster is not ready for backups、the pgBackRest repo host is not ready条件原因可读化pgConditionHint把StanzaNotCreated翻译为 the pgBackRest repository isnt initialized - check the backup storage and credentials把RepoBackupNotComplete翻译为 the initial repository backup hasnt completed其余原因原文透传——这就是文档中那句 the pgBackRest repository isnt initialized... 提示的出处。Storage WAL磁盘空间去哪了这组图表用于定位磁盘空间去向尤其是 WAL 为什么释放不掉WAL size, bytes。WAL 目录大小对照max_wal_size参考线pgSettingBytes会把pg_settings中带单位的值——kB/8kB/MB/GB——换算成字节再画线。WAL 目录远超max_wal_size几乎总意味着 WAL 删不掉要么归档失败要么复制槽在扣留。Replication slots retained WAL。每个槽扣留的 WAL。一个 inactive 且 retained WAL 持续爬升的槽是磁盘写满的经典原因删掉无用的槽即可释放。Disk usage与Top tables by size。空间整体去向与最大的表。auditor/postgres.go 的pgDiskUsageFindings还会做一层增长归因对表体积与膨胀量序列计算增长率某表的增长主要由膨胀贡献时会标注 mostly bloat, consider reclaiming with pg_repackWAL 目录或某个复制槽的 retained WAL 增长超速率阈值时会被单列为磁盘增长点归档失败时还会在 WAL 目录名后追加 (archiving is failing, WAL cannot be recycled)。另有pgIOFindings会在 I/O 负载高时输出 disk writes are mostly WAL / checkpointer flushes 与最耗 I/O 的查询名把存储压力与具体来源挂钩。小结Coroot 的 Postgres 巡检把DBA 值班清单产品化11 项检查各自有明确默认阈值集中在 model/check.go可按项目配置、按应用覆盖每项检查背后是 auditor/postgres.go 中一套带防误报门槛最小字节数、最小行数、最近 N 点窗口的判定逻辑并尽量把结论落到具体是哪条查询、哪个表、哪个槽、哪个持有者。排查时建议按报告顺序先看总览表的 Role/Status/Lag 判断故障面再进入对应检查项的图表按本文的判读路径定位根因遇到 vacuum 相关结论时优先读检查项附带的根因文案它已替你完成了大部分归因工作。【免费下载链接】corootCoroot is an open-source observability and APM tool with AI-powered Root Cause Analysis. It combines metrics, logs, traces, continuous profiling, and SLO-based alerting with predefined dashboards and inspections.项目地址: https://gitcode.com/GitHub_Trending/co/coroot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考