土法炼钢兴趣小组的算法知识备份

PostgreSQL 内核机制 — 系列规划

目录

PostgreSQL 内核机制 — 系列规划

本文是写作规划,不是可发布正文。按 WRITING_GUIDE.md 第十三节流程:先定来源台账、实验台账、篇目结构,再写 index.md 和正文。


一、为什么写这个系列

1.1 现有内容的覆盖情况

博客已有的数据库/存储相关内容:

已有系列 视角 与 PG 内核的重叠
存储工程 (79) 通用存储介质、文件系统、存储引擎概览 讲到 B-Tree、Buffer Pool、WAL/ARIES 的通用原理,但不到 PG 具体实现
db-frontier (25) 顶会前沿(Learned Index、向量检索、HTAP、TEE) 不涉及 PG 内核实现
db/LSM-Tree (9) 从零实现 LSM 引擎 B-Tree 体系,与 PG 无关
db/mvcc (1) PG 的 MVCC、快照隔离、SSI 唯一一篇深入 PG 源码的文章,但只覆盖并发控制一个维度
分布式 (70) Paxos/Raft、一致性、复制 复制理论有覆盖,但不涉及 PG 流复制的具体实现
OS (111) 进程、内存、文件系统、同步原语 理论基础,不涉及 PG 如何使用这些机制

结论:博客有深厚的存储和并发理论基础,但缺少对一个完整生产级数据库内核的系统性源码拆解。PG 是开源关系型数据库的标杆,其源码和文档质量极高,天然适合这个角色。

1.2 为什么选 PostgreSQL(而不是 MySQL InnoDB)

维度 PostgreSQL MySQL/InnoDB
源码可读性 高,注释详尽,README 遍布关键目录 中等,历史包袱重
文档质量 官方手册即是事实标准,每个 GUC 有详细说明 官方文档覆盖面窄,依赖社区
学术关联 PG 论文传统强(Joseph Hellerstein、Michael Stonebraker 等) 论文少
扩展性 Hook 机制丰富,FDW 清晰 插件机制受限
社区讨论质量 pgsql-hackers 邮件列表归档详尽 内部化,公开讨论少
与博客已有系列联动 MVCC 文章已用 PG 源码,存储工程通用原理可落地 InnoDB 没有既有文章铺垫

1.3 系列定位

两条腿走路:内核机制拆解 + 生产运维实战

上半场(第 1–20 章)是 从进程模型到磁盘页面的完整内核拆解:每篇文章盯住一个内核子系统,从源码路径钉住结论。下半场(第 21–26 章)是 从内核知识到故障现场的反向应用:用内核机制解释真实生产事故的根因、排查路径和修复边界。

具体来说:

内核拆解线(原 20 章): - 对着 PG 源码追踪一条 SQL 的完整执行路径 - 理解每个 GUC 参数背后的内核行为 - 在遇到性能问题或异常行为时,知道从哪个内核模块入手排查

运维实战线(新增 6 章): - 识别经典故障模式的根因——连接风暴、wraparound 危机、OOM 连锁 kill、replication slot 溢出——而不只是跟着 runbook 操作 - 用 pg_stat_activity + wait_event + pg_locks + kernel trace 四层工具链定位性能异常 - 理解 pg_upgrade、PITR、pg_resetwal 的内部机制和操作边界——知道什么情况该用什么、什么情况绝对不能碰 - 掌握 PG 配置项之间的联动关系和隐性陷阱——work_mem 不只是”每个操作的内存上限”、fsync=off 为什么诱惑巨大但可能让你丢数据 - 从他人事故中学习模式而非个案——每条”常见坑”都配内核机制解释和可复现的验证方法


二、核心问题与目标读者

2.1 九个关键问题

  1. PG 的进程模型多进程共享内存到底是怎么工作的? Postmaster、backend、background worker、autovacuum launcher/worker — 这些进程如何协作?共享内存中有哪些关键数据结构?fork() 的开销 PG 怎么消化? → 第 1、2 章回答。

  2. 一条 SQL 从客户端到磁盘经历了哪些环节? Parser → Analyzer → Rewriter → Planner → Executor → Buffer Manager → WAL → Disk。每个环节的输入输出、关键数据结构和性能边界是什么? → 第三部分(第 9-13 章)逐环节拆解。

  3. PG 的 MVCC 为什么需要 VACUUM?膨胀到底怎么发生的? 已有 mvcc 文章讲了可见性判断,但没深入讲:CLOG 的结构、hint bit 的写入时机、VACUUM 的内部流程、freezing 的必要性、膨胀的量化分析。 → 第 3、8 章 + 扩展已有文章。

  4. PG 的查询优化器如何做决策?统计信息不准的时候怎么办? pg_statistic 里存了什么?选择率估算公式从哪来?Join 顺序搜索空间多大?GEQO 什么时候接管?Extension 怎么影响 plan? → 第 10、11 章。

  5. PG 的高可用方案(流复制、逻辑复制、逻辑解码)各自的机制边界在哪? WAL Sender/Receiver 的协议细节、同步复制 vs 异步复制的语义差异、逻辑解码的 reorder buffer、逻辑复制的冲突处理。 → 第 18、19 章。

  6. PG 最危险的 10 种故障模式——根因、排查路径和修复边界是什么? 连接风暴为什么能打垮 PG(哪怕 max_connections 设了上限)?事务 ID wraparound 在 pg_stat_activity 里最早期的信号是什么?replication slot 溢出的多米诺效应——一个 slot 如何拖垮整个集群? → 第 22 章集中回答,各机制章节点出前置知识。

  7. 排查慢查询的完整工具链怎么用——如何从现象定位到内核根因?pg_stat_statements 定位高耗时 queryid → EXPLAIN (ANALYZE, BUFFERS) 看实际行数和 buffer 访问 → pg_stat_activity + wait_event 诊断等什么锁或 I/O → perf / bpftrace 追踪内核调用栈。不是一个命令,而是一条调查链。 → 第 23 章集中回答,第 6、10、12 章提供排查所需的内核知识。

  8. PG 最容易被误解和配错的 15 个 GUC——配错之后会发生什么? work_mem 不只是”每个操作的内存上限”——当 200 个连接同时做 hash join 时会发生什么?fsync=off 为什么诱惑巨大但 COMMIT 之后数据真可能丢?huge_pages=on 在 Docker 里为什么静默退化?random_page_cost 在 NVMe 上的默认值有多离谱? → 第 26 章回答,第 5、10、18 章提供内核基础。

  9. pg_upgrade / PITR / pg_resetwal 的内部机制和操作边界是什么——什么时候该用、什么时候绝对不能碰? pg_upgrade --link 的原理和崩溃恢复风险、PITR 恢复的”正确时间点”怎么定、pg_resetwal 为什么是最后手段——以及用了之后哪些数据不可访问。 → 第 24、25 章回答。

2.2 目标读者

维度 说明
主要读者 数据库内核开发者、后端工程师(日常使用 PG 且想深入理解)、SRE/DBRE(需要内核视角排查问题)
次要读者 系统软件方向学生、从 MySQL 转 PG 的工程师、分布式数据库开发者(参考 PG 的单机设计)
先修知识 SQL、基本数据库概念(ACID、索引、WAL)、C 语言阅读能力、操作系统基础(进程、内存、I/O)
不假设 PG 内核贡献经验、数据库理论论文深度

三、篇目结构

全系列 20 章,分五部分。每章按”问题 — 源码 — 实验 — 边界”组织。

第一部分:体系结构地基(第 1-2 章)

第 1 章:进程模型与共享内存

第 2 章:页面布局与元组格式

第二部分:并发控制与崩溃恢复(第 3-8 章)

第 3 章:MVCC 实现(扩展已有文章)

第 4 章:WAL 内部机制

第 5 章:Buffer Manager

第 6 章:锁管理器

第 7 章:事务与子事务

第 8 章:VACUUM 与 Freezing

第三部分:查询生命周期(第 9-13 章)

第 9 章:查询解析与重写

第 10 章:查询规划器 — 统计信息与代价模型

第 11 章:查询规划器 — Join 顺序与路径生成

第 12 章:执行器与表达式求值

第 13 章:JIT 编译

第四部分:索引内部机制(第 14-17 章)

第 14 章:B-Tree 索引

第 15 章:GiST 索引

第 16 章:GIN 索引

第 17 章:BRIN 与其他索引

第五部分:扩展性与高可用(第 18-20 章)

第 18 章:流复制

第 19 章:逻辑复制与逻辑解码

第 20 章:扩展系统与 FDW

第六部分:运维实战与故障排查(第 21-26 章)

这 6 章是内核机制向生产现场的反向应用。每章以 2-5 个真实故障模式驱动,用”现象→根因(内核机制解释)→排查路径→修复边界”的结构组织。不写 runbook,写”为什么这样做、不这样做的后果”。

第 21 章:监控体系与告警设计

第 22 章:经典故障模式与排查手册

第 23 章:性能异常调查方法论

第 24 章:数据恢复与损坏应对

第 25 章:大版本升级与迁移实战

第 26 章:配置陷阱与生产最佳实践


四、篇目依赖关系

强依赖图

第 1 章 (进程/内存) ──→ 第 2 章 (页面/元组) ──→ 第 3 章 (MVCC/CLOG) ──→ 第 4 章 (WAL)
       │                        │                      │                      │
       └────────┬───────────────┘                      │                      │
                ↓                                      ↓                      ↓
          第 5 章 (Buffer Manager) ←──────────────── 共享依赖 ──→ 第 6 章 (Lock Manager)
                │                                                          │
                ↓                                                          ↓
          第 7 章 (事务/子事务) ──→ 第 8 章 (VACUUM)                        │
                │                       │                                   │
                └───────┬───────────────┘                                   │
                        ↓                                                   │
                  第 9 章 (解析/重写)                                       │
                        ↓                                                   │
                  第 10 章 (统计/代价) ←── 第 11 章 (Join/路径)            │
                        │                       │                           │
                        └───────────┬───────────┘                           │
                                    ↓                                       │
                              第 12 章 (执行器) ──→ 第 13 章 (JIT)         │
                                    │                                       │
                    ┌───────┬───────┼───────┬───────┐                       │
                    ↓       ↓       ↓       ↓       ↓                       │
              第 14 章 第 15 章 第 16 章 第 17 章 ──→ 第 18 章 (流复制)   │
              (B-Tree) (GiST)  (GIN)   (BRIN)          │                   │
                                                        ↓                   │
                                                  第 19 章 (逻辑复制)       │
                                                        │                   │
                                                        ↓                   │
                                                  第 20 章 (扩展/FDW)       │
                                                        │                   │
                                                        ↓                   │
                                              ┌─────────┴──────────┐        │
                                              ↓                    ↓        │
                                        第 21 章 (监控)    第 22 章 (故障)  │
                                              │                    │        │
                                              └────┬───────────────┘        │
                                                   ↓                        │
                                            第 23 章 (性能调查)              │
                                                   │                        │
                                      ┌─────────┬──┴──┬──────────┐         │
                                      ↓         ↓     ↓          ↓         │
                                第 24 章  第 25 章  第 26 章              │
                                (恢复)   (升级)   (配置陷阱)              │
                                                                              │
              第 3 章已有的 mvcc 文章作为前置阅读 ←─────────────────────────┘

弱依赖(可独立阅读)

已有文章的关系


五、阅读路径

路径 A:日常 PG 用户 → 想理解内核

1 → 2 → 3 → 5 → 10 → 11 → 14 先理解进程/内存/页面这些”物理基础”,再看查询规划和索引,这是日常工作最相关的内核知识。

路径 B:数据库内核开发者

1 → 2 → 5 → 4 → 6 → 7 → 12 → 14 先看存储层(页面、Buffer、WAL)和并发控制(锁、事务),再看执行器和索引——这是写一个数据库引擎的核心路径。

路径 C:SRE / DBRE → 排查问题

1 → 3 → 8 → 4 → 18 → 19 → 22 → 23 → 26 从 MVCC/VACUUM 的运维关键点入手(膨胀、wraparound),再看 WAL 和复制——是高可用和性能故障的主战场。第 22 章(经典故障)和第 23 章(性能调查)是排查速查手册,第 26 章(配置陷阱)是配置审计清单。

路径 D:应用开发者 → 优化查询

9 → 10 → 11 → 12 → 13 → 14 → 23 → 26 从解析/重写/规划/执行/JIT 的完整 SQL 生命周期,理解为什么某个查询慢。第 23 章提供性能调查方法,第 26 章避免配置踩坑。

路径 E:准备给 PG 贡献代码

1 → 2 → 5 → 6 → 14 → 20 从进程/页面/Buffer/Lock 这些你必须懂的基础设施,到索引和扩展系统——PG 内核贡献的入门路径。

路径 F:运维老兵 → 快速查 PG 特有的坑

22 → 26 → 8 → 18 → 23 从故障模式和配置陷阱切入(你不是来学内核的,你是来了解”PG 有什么不同于 MySQL/Oracle/其他数据库的特别坑”),第 8 章搞懂 VACUUM(PG 最独特的运维点),第 18 章搞懂复制,第 23 章学会 PG 的调查工具链。

路径 G:接手一个正在出问题的 PG 集群

22(定位故障模式)→ 23(性能调查方法)→ 21(建立监控防线)→ 26(审计配置)→ 24(如果需要恢复数据) 先止血、再调查、再建立防护、再审计配置、最后处理数据恢复——按紧急程度排序。


六、来源台账

A 级来源(支撑关键结论)

源码

官方文档

论文

开发者讨论

B 级来源(辅助参考)

C 级来源(线索,不直接引用)


七、实验台账

基础实验环境

项目 说明
PG 版本 优先 PG 17 (latest stable),涉及版本差异时补充 PG 16
编译 --enable-debug --enable-cassert --enable-depend
工具 gdbpageinspectpg_buffercachepgstattuplepg_stat_statementsauto_explain
测试数据集 pgbench 默认数据 + 定制倾斜分布数据

各章实验计划

章节 实验内容 工具/方法
第 2 章 观察 heap page 内部字节 pageinspect 扩展
第 3 章 追踪 CLOG 页面分配与可见性判断 gdb 断点 + pageinspect
第 4 章 测量 WAL 写入带宽与 wal_sync_method 影响 pg_stat_wal + pg_waldump
第 5 章 观察 shared_buffers 使用与 clock sweep pg_buffercache + EXPLAIN (BUFFERS)
第 6 章 构造死锁与锁等待链 pg_locks + pg_blocking_pids()
第 8 章 量化 VACUUM 前后的 dead tuple 数量与膨胀 pgstattuple + pg_stat_user_tables
第 10 章 构造统计信息不准导致糟糕计划的场景 定制倾斜数据 + EXPLAIN ANALYZE
第 11 章 追踪 Join 顺序搜索与路径选择 debug_print_plan + gdb
第 14 章 观察 B-Tree 页面分裂与去重 bt_page_items() + bt_metap()
第 18 章 搭建 primary-standby、测量复制延迟 pg_stat_replication
第 19 章 搭建逻辑复制、构造冲突场景 Publication/Subscription DDL
第 21 章 部署 Prometheus pg_exporter、配置告警规则 pg_exporter + Grafana
第 22 章 复现连接风暴/OOM/wraparound/slot 溢出/长事务故障 定制负载脚本 + gdb 断点
第 23 章 构造统计不准/锁等待/IO 瓶颈三类慢查询并排查定位 pg_stat_statements + EXPLAIN + wait_event
第 24 章 执行 PITR 恢复、模拟 WAL 损坏与 pg_resetwal pg_basebackup + pg_waldump
第 25 章 执行 pg_upgrade –link 升级 16→17、构造升级失败场景 两个 PG 安装 + 测试数据
第 26 章 对比不同配置下的性能差异、构造 work_mem 过量/fsync off/huge_pages 退化 pgbench + pg_buffercache + /proc/meminfo

Benchmark 要求

涉及性能结论时,至少交代: - 硬件:CPU 型号/核数、内存容量、磁盘类型 (NVMe/SSD/HDD) - OS:内核版本、文件系统、挂载选项 - PG 版本与关键配置:shared_bufferswork_memmax_wal_sizewal_level - 负载:pgbench scale factor、客户端数、运行时长、预热轮次 - 每次至少跑 3 轮,使用中位数


八、与其他系列的联动

本站已有系列 联动方式
storage/ (79) WAL/ARIES、Buffer Pool、B-Tree 的通用原理在 PG 中的具体实现
db/mvcc/mvcc.md (1) 第 3 章直接以该文为前置,扩展 CLOG/hint bit/snapshot scalability
db/lsm-tree/ (9) B-Tree vs LSM 的工程取舍在 PG 索引章节中对照
distributed/ (70) 一致性与复制的理论背景,在 PG 流复制/逻辑复制章节引用
os/ (111) fork()、shmem、fsync、fdatasync、信号量——PG 大量使用这些 OS 原语
linux/ (14) 内核层面的 I/O、内存、进程调度对 PG 性能的影响

九、边界承诺

承诺

不承诺


十、写作顺序

第一批(基础层,无外部依赖)

  1. 第 1 章:进程模型与共享内存
  2. 第 2 章:页面布局与元组格式

第二批(存储与并发,依赖第一批)

  1. 第 3 章:MVCC 实现(扩展已有文章)
  2. 第 5 章:Buffer Manager
  3. 第 4 章:WAL 内部机制
  4. 第 6 章:锁管理器

第三批(事务与运维,依赖第二批)

  1. 第 7 章:事务与子事务
  2. 第 8 章:VACUUM 与 Freezing

第四批(查询层,依赖第一/二批)

  1. 第 9 章:查询解析与重写
  2. 第 10 章:统计信息与代价模型
  3. 第 11 章:Join 顺序与路径生成
  4. 第 12 章:执行器与表达式求值
  5. 第 13 章:JIT 编译

第五批(索引与高可用,依赖基础层 + 部分查询层)

  1. 第 14 章:B-Tree 索引
  2. 第 15 章:GiST 索引
  3. 第 16 章:GIN 索引
  4. 第 17 章:BRIN 与其他索引

第六批(复制与扩展,依赖 WAL + 事务)

  1. 第 18 章:流复制
  2. 第 19 章:逻辑复制与逻辑解码
  3. 第 20 章:扩展系统与 FDW

第七批(运维实战,依赖全部前六批的基础机制知识)

  1. 第 21 章:监控体系与告警设计
  2. 第 22 章:经典故障模式与排查手册
  3. 第 23 章:性能异常调查方法论

第八批(运维实战续 + 配置,强烈依赖前七批)

  1. 第 24 章:数据恢复与损坏应对
  2. 第 25 章:大版本升级与迁移实战
  3. 第 26 章:配置陷阱与生产最佳实践

十一、待确认问题

  1. PG 版本锚定:以 PG 17 为主吗?PG 18 预计 2026 年 10 月发布,是否等到 PG 18 再开始?
  2. 系列规模:20 章扩展到 26 章是否合适?运维部分(第 21-26 章)是否考虑拆成独立系列?
  3. 题目风格:现有文章标题多为陈述式(“数据库 MVCC:快照隔离到底隔离了什么”),本系列是否沿用?
  4. 运维章的深度 vs 宽度:第 22 章(故障)现在是 5 种典型故障,是否扩展到更多?第 26 章(配置)现在是 11 个 GUC,是否包含更多?
  5. 发布时间节奏:26 章预计需要较长时间——是否先发前 20 章内核部分,第 21-26 章运维部分单独发?
  6. MySQL/InnoDB 对照:是否在某些章节(MVCC、锁、VACUUM vs undo)做 PG vs InnoDB 对比?运维部分是否加入 MySQL DBA 转向 PG 的对照提示?
  7. 示例代码语言:源码分析用 C,实验和图示生成用 Python?运维章的监控 SQL 和排查脚本用什么语言?
  8. 故障复现实验:第 22 章的 5 种故障模式需要真实复现(构造连接风暴、触发 OOM、导致 slot 溢出等)——这些实验有破坏性,是否在独立 VM 中进行?

附录:关键 GUC 参数速查(写作用)

以下 GUC 是 PG 内核行为的关键控制点,写作涉及对应章节时必须理解其内核含义,不能只写调优规则。

GUC 相关章节 内核含义
shared_buffers 第 5 章 Buffer pool 大小,直接影响 clock sweep 频率
wal_level 第 4、18、19 章 控制 WAL 记录类型集合,决定复制能力
wal_sync_method 第 4 章 WAL 写入的刷盘策略
max_wal_size / min_wal_size 第 4、8 章 Checkpoint 触发与 WAL 回收
checkpoint_timeout 第 4 章 Checkpoint 的时间触发
autovacuum_* 第 8 章 Autovacuum 的触发与限速
vacuum_freeze_min_age 第 8 章 Freezing 的触发条件
default_statistics_target 第 10 章 ANALYZE 采样精度
random_page_cost 第 10 章 代价模型的核心常量
jit_above_cost 第 13 章 JIT 编译的触发阈值
max_worker_processes 第 1、20 章 后台进程上限
synchronous_commit 第 18 章 同步复制的持久性语义
max_standby_streaming_delay 第 18 章 备机查询取消的时间窗口
max_replication_slots 第 18、19 章 复制 slot 上限
deadlock_timeout 第 6 章 死锁检测间隔
log_lock_waits 第 6、26 章 锁等待超时时写入日志——配合 deadlock_timeout 使用
checkpoint_completion_target 第 4、22 章 Checkpoint 的 IO 摊平策略,直接影响写入高峰
autovacuum_vacuum_cost_delay 第 8、22 章 Autovacuum 的 IO 限速——设太高可能追不上 dead tuple 产生速度
autovacuum_analyze_scale_factor 第 10、21 章 触发 auto-analyze 的表变化比例——insert-only 表可能永远达不到默认 0.1
hash_mem_multiplier 第 23、26 章 PG 15+ 的 hash join 内存倍数——与 work_mem 联动计算 hash 操作可用内存
maintenance_work_mem 第 8、25、26 章 VACUUM / CREATE INDEX / ALTER TABLE 等维护操作的内存上限
effective_cache_size 第 10、26 章 优化器对 OS page cache + shared_buffers 的估算——不分配内存,只影响代价计算
huge_pages 第 26 章 大页内存开关——Docker/K8s 中静默退化为小页的排查
idle_in_transaction_session_timeout 第 22、26 章 防止忘记 commit 的 session 持锁不释放
log_min_duration_statement 第 21、23、26 章 慢查询日志阈值——配合 auto_explain 使用,注意日志洪水
track_io_timing 第 21、23 章 启用 IO 计时统计——对查询性能有微小影响
plan_cache_mode 第 23 章 计划缓存策略——generic plan vs custom plan 的强制选择
fsync 第 4、24、26 章 关掉 COMMIT 不刷盘——最危险的配置之一
restart_after_crash 第 22 章 OOM kill 后 PG 是否自动重启——默认 on,关了就没自动恢复
zero_damaged_pages 第 24 章 遇到校验和不匹配的页面时跳过并返回零填充——数据已丢,不是修复

规划版本:v2,2026-06-16 主要变更:v2 — 扩展系列从 20→26 章,新增第六部分「运维实战与故障排查」(监控/故障/调查/恢复/升级/配置陷阱),增强现有章节(4/8/10/12/18/19)的运维/排查维度,新增阅读路径 F/G(运维老兵/应急排查),新增 8 个 GUC 参数速查项 下一步:确认本文档中的待确认问题 → 编写系列 index.md → 开始第一批写作(第 1、2 章)

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-06-16 · database / kernel

【PG 内核】PostgreSQL 内核机制深度拆解

从进程模型到磁盘页面、从 MVCC 到流复制——对 PostgreSQL 内核做完整的源码级拆解。不止步于源码分析:26 篇中 6 篇是运维实战——经典故障的根因与排查路径、性能调查的五层工具链、配置陷阱与恢复边界。面向想读懂 PG 内核源码、在生产环境排查过问题、准备给 PG 贡献代码的工程师。


By .