34.4 CPU、内存、I/O 与 OOM
数据库资源彼此耦合。内存紧张会增加 reclaim 与 swap I/O;I/O 变慢会延长 query 和 transaction,占住更多连接与内存;连接排队又会触发超时重试,进一步增加 CPU。 事故中不能把每张主机图分开解释,而要寻找同一时间线上的因果方向。
34.4.1 饱和、排队、抖动与抢占
利用率不是完整答案
CPU 100% 可能仍有高吞吐且尾延迟可接受;CPU 40% 也可能因为单核热点、锁、自旋、 steal time 或 I/O 等待导致业务停滞。主机证据至少包括:
per-CPU user/system/iowait/steal
run queue and runnable tasks
context switches
memory pressure / reclaim / swap
per-device latency, queue depth, throughput and errors
cgroup/container limits and throttling
filesystem free bytes and inodes再按 PostgreSQL backend type 与 wait event 对齐:
SELECT backend_type,
wait_event_type,
wait_event,
count(*) AS processes
FROM pg_stat_activity
GROUP BY 1, 2, 3
ORDER BY processes DESC;PostgreSQL 官方建议把统计视图与操作系统工具结合,因为数据库 I/O 统计不能区分数据 来自物理设备还是内核 page cache。数据库看到 read,也不等于磁盘实际发生同量读取。
饱和、排队和抖动
saturation
resource has little service headroom
queueing
work waits before resource service
jitter
completion latency varies sharply over time
contention/preemption
work loses CPU/lock/device service to other work平均设备延迟 2 ms 可能掩盖 checkpoint 时 500 ms 尖峰;五分钟 CPU 平均值也会抹掉 每 30 秒同步到来的任务。保留原始采样粒度、时钟和分位数,不要只截一张平滑后的图。
先区分主机级还是数据库级
| 证据组合 | 更可能的方向 |
|---|---|
| host run queue 高,PG 多数无 wait | CPU runnable 竞争 |
PG 大量 Lock,CPU 不高 | 数据库锁序列化 |
device await/queue 高,PG 大量 IO | 存储服务能力不足 |
| cgroup throttled,宿主机空闲 | 容器/服务配额 |
| swap/reclaim 高,连接与 query 同增 | 内存承诺或并发过大 |
| PG 平稳,其他进程占资源 | noisy neighbor/备份/扫描 |
不要在没确认 cgroup/虚拟化边界时用宿主机总容量推导数据库余量。
34.4.2 临时文件、并行、checkpoint 与后台维护
前台与后台会争同一设备
下面工作可能同时写盘:
sort/hash spill -> temp files
WAL writer / WAL sync
backend data writes
checkpointer flushing dirty buffers
autovacuum/vacuum
CREATE INDEX / REINDEX
base backup and archive
operating-system or storage maintenancepg_stat_io 按 backend type、object 与 context 提供集群级 I/O 统计;pg_stat_database
的 temp 计数、日志中的 temporary file、pg_stat_checkpointer、pg_stat_archiver 和
进度视图分别补充来源。统计是累计量,需要记录起点并取差值:
SELECT backend_type,
object,
context,
reads,
read_time,
writes,
write_time,
extends,
fsyncs,
fsync_time
FROM pg_stat_io
ORDER BY backend_type, object, context;列集合随 PostgreSQL 版本演进,生产脚本应绑定 major version 并做兼容检查。
临时文件是结果,不是单一根因
spill 可能来自:
work_mem对该 sort/hash 太小;- 行数估计错误导致计划不合适;
- 并发相同操作太多;
- 查询本来就必须处理大量数据;
- hash 操作按
hash_mem_multiplier获得更高上限; - parallel workers 各自执行内存/临时工作。
直接把 work_mem 全局放大,可能把磁盘事故变成 OOM。优先修 query/统计、限制该工作
并发,必要时只对可控 role/session 做有界调整并验证。
checkpoint 峰值与追赶效应
checkpoint 需要把脏页推进到 durable storage。写流量突增、WAL 配置、恢复/重启后的 缓存重新填充和存储变慢都可能让 checkpoint 与前台 I/O 相互干扰。事故中记录:
checkpoint requested/timed
buffers written and write/sync duration
WAL generation rate
device write latency/queue
replica and archive progress暂停 autovacuum 或 checkpoint 通常不是通用止血。autovacuum 还承担 XID freeze; 暂停后可能把短期 I/O 压力转成更危险的保留问题。只能对已识别对象、在明确时间窗与 回补计划下调整维护。
34.4.3 内存最坏并发、OOM killer 与进程重启
work_mem 不是每连接只分配一次
PostgreSQL 文档强调,work_mem 是一个 query operation(如 sort/hash)的基础上限;
一个复杂 query 可同时有多个 operation,多个 session 又可并发,parallel worker 也会
扩大总使用。粗略上界应按工作节点估算:
$$ M_{\text{query}} \approx \sum_{\text{sessions}} \sum_{\text{operations}} M_{\text{operation}} \sum_{\text{parallel workers}} M_{\text{worker}} $$
再加上:
shared_buffers and shared memory
backend base memory
maintenance_work_mem / autovacuum_work_mem
logical decoding and extension memory
kernel page cache
proxy, exporter, Patroni and other host processes
failure/recovery reserve因此:
max_connections * work_mem既不是准确实测,也不是足够保守的最坏值。它漏掉每 query 多个节点和并行,也忽略许多 非 work_mem 内存;反过来假设所有连接同时打满每个上限又可能极度悲观。容量测试要用 真实 workload envelope 和并发组合。
Linux OOM 不是数据库的流控机制
Linux overcommit 允许进程承诺超过物理内存的虚拟地址空间;真正耗尽时,OOM killer 可能选择某个进程。若 PostgreSQL child 被杀,postmaster 会把它当作异常退出,为保护 共享内存一致性,可能终止其他 server processes 并执行 crash recovery;若 postmaster 本身被杀,服务管理器行为又是另一条路径。
不要故意在共享/生产主机上“测一次 OOM”。安全实验应在有明确 cgroup/VM 边界的专用 环境里完成,并验证:
which cgroup/host reported OOM
which PID and backend_type was selected
whether postmaster remained
whether crash recovery occurred
client unknown outcomes
replica/archive/backup state after restart本章正式实验明确不注入 OOM。
事故动作
内存压力下优先:
- 阻止新低价值工作和重试;
- 识别 exact 高内存 query/role/pool;
- 暂停可恢复 batch 与并行任务;
- 用 query cancel 逐步释放,而不是一次 terminate 全部;
- 保留管理连接与 OS 控制面;
- 观察 reclaim、swap、RSS、队列和业务成功率;
- 稳定后修正连接预算、query、并行与内存配置。
不要在事故中 drop OS cache:它既不能修复内存承诺,还会把后续读取推向存储,破坏 现场并制造新的 I/O 峰值。也不要把 swap 使用本身等同于故障;关键是持续 swap in/out、 memory pressure 与用户影响。
资源证据矩阵
cpu:
utilization: ...
run_queue: ...
steal_or_throttle: ...
memory:
available: ...
pressure: ...
swap_rate: ...
oom_event: ...
io:
device_latency_queue: ...
pg_waits: ...
checkpoint_temp_maintenance: ...
workload:
admitted_running_waiting_rejected: ...
root_queries_or_jobs: ...
decision:
exact_control: ...
stop_and_rollback: ...单张 top 截图不够支撑数据库重启。
上一节:失控查询、锁与事务 · 返回本章目录 · 下一节:流量型止血动作 · 查看全书目录 · 查看索引中心