跳至内容
34.1 第一动作:流量型还是保留型

34.1 第一动作:流量型还是保留型

资源告警出现后,先不要问“删什么”或“重启谁”,而要问:

当前资源是被正在到达和执行的工作消耗,还是被一个不能前进的历史边界 保留?

这不是给故障贴标签,而是选择安全动作。流量型压力需要减少进入量、并发或单项成本; 保留型压力需要找到保留者及其 owner。两类证据都成立时,先处理即将触发的硬失败, 同时保留另一条根因链;两类都不成立时,保持 unknown。

34.1.1 流量增长、慢查询、锁与连接导致的竞争

流量型的共同结构

下面四种表象最后都会形成“到达大于完成”:

放大源到达侧变化完成侧变化
业务流量增长请求数增加单次成本可能不变
慢查询或坏计划请求数不变每次占用 CPU/I/O/连接更久
锁竞争等待工作继续占连接有效并行度下降
连接风暴建连、认证、backend 创建增加正常查询拿不到 admission

若每秒进入 $\lambda$ 个工作、完成 $\mu$ 个工作,持续满足 $\lambda>\mu$,队列就增长。 这里的工作可以是 HTTP 请求、池等待者、数据库 session、正在运行的 statement 或磁盘 I/O。只看 PostgreSQL 的 active session 会漏掉在应用池和代理前排队的请求。

先把同一 UTC 窗口的证据放在一起:

SELECT application_name,
       state,
       wait_event_type,
       wait_event,
       count(*) AS sessions,
       max(clock_timestamp() - coalesce(xact_start, query_start))
         AS oldest_age
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY 1, 2, 3, 4
ORDER BY sessions DESC;

再对照:

application arrival / timeout / retry
pool waiting clients / server connections
proxy accept / queue / backend health
PostgreSQL active / idle-in-transaction / Lock waits
host run queue / memory pressure / device latency

state='active' 不表示正在使用 CPU;PostgreSQL 文档明确指出 statewait_event 相互独立。active 且 wait_event_type='Lock' 的 backend 正在执行语句,但实际被阻塞。 这也是为什么“active 数很多”必须继续拆成 running、lock wait、I/O wait 与 client wait。

判定成立的最低条件

把问题判为 flow,至少应看到一条能够闭合的因果链:

arrival/retry increases
  -> admission or execution concurrency increases
  -> queue/wait/rejection grows
  -> completion rate or user success falls

仅凭 CPU 90% 不够。CPU 高也可能是 checkpoint 后的恢复工作、压缩、备份或一个与用户 延迟无关的后台任务;连接数高也可能都是长期 idle、但尚未达到瓶颈。

34.1.2 WAL、XID、复制槽、归档和长事务导致的保留

保留型不是“有人正在大量使用”

PostgreSQL 为恢复、复制和 MVCC 正确性保留历史。只要某个消费者仍声明“我可能需要 这里以前的内容”,系统就不能越过它回收:

被保留对象常见保留者关键边界
旧 tuple 版本活跃快照、长事务、prepared transactionbackend_xmin、prepared XID
catalog tuplelogical replication slotcatalog_xmin
WAL segmentphysical/logical slot、备库、备份restart_lsn
待归档 WALarchive command/repository 失败pg_stat_archiver 与归档队列
事务 ID 安全空间未冻结表与被钉住的 xminrelation/database age

这里重要的是最老边界及其速度

SELECT pid,
       usename,
       application_name,
       state,
       xact_start,
       backend_xid,
       backend_xmin
FROM pg_stat_activity
WHERE backend_xid IS NOT NULL
   OR backend_xmin IS NOT NULL
ORDER BY xact_start NULLS LAST;

SELECT slot_name,
       slot_type,
       active,
       xmin,
       catalog_xmin,
       restart_lsn,
       wal_status,
       safe_wal_size,
       invalidation_reason
FROM pg_replication_slots
ORDER BY slot_name;

SELECT transaction, gid, prepared, owner, database
FROM pg_prepared_xacts
ORDER BY prepared;

inactive slot 不等于废弃 slot。它可能对应暂时离线的副本、迁移、CDC 消费者或恢复流程; active slot 也不等于健康,消费者可能连着却不推进。必须把 slot 映射到服务 owner、 consumer、恢复承诺和最后成功时间。

先测增长,再谈释放

两个快照比一个快照更有意义:

t0: free bytes, current LSN, restart_lsn, archive failure count
t1: same fields after a known interval

retained bytes     = current LSN - restart_lsn
growth rate        = (retained_t1 - retained_t0) / elapsed
time to hard limit = usable headroom / positive growth rate

max_slot_wal_keep_size=-1,replication slot 可以不受该参数上限地保留 WAL;即使配置 了有限值,相关状态也在 checkpoint 时才重新评估,不能把参数值误当作实时保险丝。

34.1.3 同样表现为“磁盘满”或“延迟高”,动作可以相反

症状相同,控制变量不同

症状可能的 flow 根因可能的 retention 根因需要区分的证据
pg_wal写流量突增、checkpoint 压力slot/归档/备份钉住 WALWAL 生成率与最老保留 LSN
表膨胀更新/删除量增长长快照或 slot catalog_xminDML 率、vacuum 进度与 xmin
磁盘延迟高并发查询、temp、checkpoint被保留数据持续占满并触发写放大device queue、文件分类、增长率
连接失败到达/重试超过连接预算磁盘满后新事务无法写 WALpool queue、PG error、filesystem
CPU 高执行/解析/自旋竞争recovery/cleanup 追赶保留积压backend type、wait、工作量变化

因此动作可以完全相反:

flow:
  stop admission -> cancel exact work -> queue falls

retention:
  preserve owner/lineage evidence -> repair consumer/archive
  -> only then release an exact, authorized boundary

把 retention 当 flow,取消再多普通查询也不会推进 restart_lsn。把 flow 当 retention, 忙着调查 slot 而不限制重试,服务可能先被连接和内存击穿。

同时发生怎么办

WAL slot 滞留期间又发生写入洪峰并不矛盾。事故记录应允许:

classification:
  flow: confirmed
  retention: confirmed
immediate_hard_failure: filesystem-full-in-18m
parallel_controls:
  - reduce noncritical write admission
  - preserve slot/archive evidence and contact owner
forbidden:
  - delete pg_wal files
  - drop unknown slot

“只能选一个根因”是复盘分类,不是在线处理原则。

34.1.4 判型不清时先停止破坏性清理

unknown 是一种有效状态

下面任一项不明,就不能执行不可逆释放:

which path is failing?
which object is growing?
who owns the oldest xmin/restart_lsn?
is there a valid backup or replica copy?
what client work will be canceled?
what data or recovery capability can be lost?

先收集最小证据包:

UTC + monotonic timestamp
user-facing probe and exact error class
pg_stat_activity grouped by app/state/wait
blocker tree and long/prepared transactions
pg_replication_slots and pg_stat_archiver
current/replay LSN and write rate
filesystem by mount/path plus inode usage
CPU/memory/pressure/device queue
recent config/deploy/failover/backup changes

然后将路线写成机器与人都能审阅的三态判定:

FLOW
  sufficient connection/queue/wait evidence
  and no contradictory retention evidence for this action

RETENTION
  exact owner boundary and retained quantity observed
  and flow relief cannot release that boundary

STOP_AND_INVESTIGATE
  both or neither predicate is sufficiently proved

停止线包括:有人建议删 pg_wal、drop 未知 slot、终止未知大事务、在唯一副本上试验 危险参数、或以“磁盘快满”为由跳过 owner/backup 识别。此时应保护现场并回到第 31 章 的事故指挥框架。

本节交付物

进入具体止血前,至少写出:

symptom: exact user and resource observation
scope: service / database / node / time window
classification: FLOW | RETENTION | BOTH | UNKNOWN
supporting_evidence: [...]
contradicting_evidence: [...]
first_action: bounded and reversible
stop_condition: measurable
owner: named role

没有这些字段,“先重启看看”不是 runbook。


返回本章目录 · 下一节:连接风暴与排队失控 · 查看全书目录 · 查看索引中心

最后更新于