数据库教程FGMT50‑PostgreSQL体系结构深入与源码解析
数据库教程FGMT50‑PostgreSQL体系结构深入与源码解析
## 前言
理解 PostgreSQL 内部体系架构是 DBA 进行故障诊断、性能调优、问题深度排查的底层根基。只有理清逻辑存储、物理文件布局、进程模型、内存工作机制,遇到慢查询、锁等待、WAL 异常、实例启动失败等问题时,才不会停留在表面现象。风哥教程本文以两台实验主机`fgedu‑net‑cn1`、`fgedu‑net‑cn2`开展实操,硬件规格统一 8CPU、64GB 内存,全部数据路径统一为`/fgedudb`;实例名、业务数据库名、业务账号统一使用`fgedudb`、`fgedudb`、`fgedu`。
风哥教程本文包含 PostgreSQL 逻辑结构、物理存储目录、进程架构、内存模型、源码编译调试环境搭建、initdb 初始化流程跟踪、数据库启动流程 gdb 调试、源代码目录解读。面向数据库 DBA、运维工程师、数据库架构师、大数据工程师;学习完成后,能够看懂 PG 底层运行机制,具备源码级问题定位能力。
### 本文内容大纲
1. PostgreSQL 整体体系架构总览
2. PostgreSQL 逻辑存储结构理论与实操
3. PostgreSQL 物理存储目录、页结构、表空间理论与实操
4. PostgreSQL 进程架构:主进程、后台辅助进程、backend 会话进程
5. PostgreSQL 内存结构理论,64G/8C 硬件参数配置实操
6. PostgreSQL 源码文件目录结构与阅读工具
7. 源码编译搭建调试环境完整实战
8. gdb 调试工具跟踪 initdb 初始化全过程
9. gdb 跟踪 PostgreSQL 实例启动流程
10. 底层问题分析思路、运维落地建议
11. 风哥针对本文总结
—
## 一、PostgreSQL 整体体系架构总览
PostgreSQL 采用多进程模型,不使用多线程。每一个客户端连接对应独立 backend 后端进程,进程之间通过共享内存、信号量、轻量锁完成通信;整个实例分为实例集群(cluster),一个集群下包含多个 database 数据库,数据库之下包含 schema,schema 存放表、索引、视图、函数等对象PostgreSQL。
整体可以划分为四大模块:逻辑存储模块、物理文件存储模块、进程后台模块、内存共享模块。
1. **逻辑层**:集群 cluster → database → schema → table/index/view/function
2. **物理层**:PGDATA 数据目录,base、global、pg_wal、pg_xact、表空间目录,8KB 默认数据页 page 作为最小 IO 单元。
3. **进程层**:postmaster 主守护进程、backend 会话进程、checkpoint、bgwriter、walwriter、autovacuum、archiver 等后台辅助进程。
4. **内存层**:共享内存(shared_buffers、wal_buffers 等)、每个 backend 私有本地内存(work_mem、maintenance_work_mem)。
>
> 风哥 itpux‑com
集群 cluster 概念非常关键:**一套 PGDATA 目录代表一个数据库集群实例,一个集群内部可以创建多个 database 数据库,database 之间物理隔离,不能跨库直接访问表,只能通过 dblink/fdw 访问**。很多初学者混淆集群、实例、数据库三者概念,会造成部署、备份、迁移理解偏差PostgreSQL。
实验环境准备,两台主机`fgedu‑net‑cn1`、`fgedu‑net‑cn2`,root 账号执行,创建基础目录,后续源码编译、数据库数据全部放在`/fgedudb`路径下。
“`
#操作系统基础目录创建
mkdir -p /fgedudb/pg_soft
mkdir -p /fgedudb/pg_data/fgedudb
mkdir -p /fgedudb/pg_tablespace
mkdir -p /fgedudb/pg_log
#创建postgres操作系统用户
groupadd postgres
useradd -r -g postgres -s /bin/bash postgres
chown -R postgres:postgres /fgedudb
chmod 700 /fgedudb/pg_data/fgedudb
ls -ld /fgedudb/*
“`
安装基础依赖包,用于后续编译源码、gdb 调试:
“`
yum install -y gcc gcc‑c++ readline‑devel zlib‑devel bison flex libxml2‑devel gdb make cmake
“`
## 二、PostgreSQL 逻辑存储结构理论与实操
逻辑层级自上而下:**数据库集群 cluster → Database 数据库 → Schema 模式 → 对象(表、索引、序列、视图、函数、类型)**。
1. Cluster 集群:由 initdb 初始化生成,一套 PGDATA,一套 postmaster 进程;集群全局对象:角色用户、表空间、pg_database,保存在 global 子目录,不属于任何单一 database。
2. Database:集群内部独立数据库,不同 database 之间 SQL 不能直接跨库 select;template0、template1 为系统模板库,template1 作为新建数据库模板,template0 为干净只读模板,禁止修改PostgreSQL。
3. Schema:数据库之下的命名空间,一个数据库允许多个 schema;public 是默认 schema;可以做权限隔离,同一个库下不同业务放不同 schema。
4. 对象:表 table、索引 index、序列 sequence、视图 view、存储过程 function、自定义 type。
>
> 风哥教程 113257174
### 实操:逻辑对象创建,主机 fgedu‑net‑cn1
切换 postgres 操作系统用户,后续 initdb 初始化集群:
“`
su – postgres
#设置环境变量
export PGDATA=/fgedudb/pg_data/fgedudb
export PATH=/fgedudb/pg_soft/pg_bin/bin:$PATH
“`
执行 initdb 初始化数据库集群:
“`
initdb -D $PGDATA –encoding=UTF8 –locale=en_US.UTF‑8 –data‑checksums
“`
`–data‑checksums`开启数据页校验和,生产强烈建议开启,初始化之后无法关闭。
启动数据库集群:
“`
pg_ctl start -D $PGDATA -l /fgedudb/pg_log/fgedudb.log
“`
登录 psql,实操逻辑对象:
“`
psql -p 5432 -U postgres postgres
“`
“`
–查看集群下全部数据库
\l
–创建业务数据库 fgedudb
CREATE DATABASE fgedudb ENCODING ‘UTF8’ LC_COLLATE ‘en_US.UTF‑8’ LC_CTYPE ‘en_US.UTF‑8’ TEMPLATE template0;
\c fgedudb
–创建业务schema fgedu
CREATE SCHEMA fgedu;
SET search_path TO fgedu,public;
–创建业务测试表
CREATE TABLE t_biz_data (
id bigserial primary key,
biz_code text,
create_time timestamp without time zone default now()
);
INSERT INTO t_biz_data(biz_code) VALUES(‘biz‑001’),(‘biz‑002′);
–查看schema下对象
\dt
\dn
\q
“`
关键知识点:
– 跨 database 不能直接 select,必须使用 fdw 或者 dblink 组件;
– template0 只读,新建数据库优先 template0,避免 template1 有残留自定义对象带入新库;
– search_path 参数控制 schema 搜索顺序,业务开发经常踩坑。
>
> 网上搜索风哥教程可以学习全套数据库教程
## 三、PostgreSQL 物理存储目录、页结构、表空间理论与实操
PGDATA 目录就是数据库集群物理根目录,核心一级子目录含义PostgreSQL:
表格
| 目录 / 文件 | 说明 |
| — | — |
| PG_VERSION | 数据库大版本标记文件 |
| base | 各个 database 的数据目录,子目录为数据库 oid,存放表、索引数据文件 |
| global | 集群全局系统表,pg_database、pg_roles 等集群全局元数据 |
| pg_wal | WAL 预写日志,事务重做日志,PITR 恢复、流复制依赖,禁止随意删除 |
| pg_xact | 事务提交状态 clog,记录每个事务 commit/abort 状态 |
| pg_multixact | 多事务行锁状态 |
| pg_tblspc | 表空间软链接,指向外部表空间真实目录 |
每一张表、索引,对应 base 下以 relfilenode 命名文件;单个文件超过 1GB 自动分片,生成`xxx.1、xxx.2`分片;每个文件内部最小 IO 单元是**page 数据页,默认 8KB**;每个 page 内部包含页头、元组 tuple、空闲空间、行指针数组;同时配套`.fsm`空闲空间映射文件、`.vm`可见性映射文件,用于 vacuum 清理死元组。
表空间 tablespace:可以把表、索引存放在 PGDATA 之外的磁盘目录,用于冷热数据分离,高速 SSD 放热点索引,普通磁盘放归档冷数据;表空间目录必须操作系统 postgres 用户拥有,空目录;表空间属于集群元数据,不能脱离集群单独拷贝挂载到另外一套集群PostgreSQL。
### 实操 1:查看物理文件对应 oid、relfilenode
登录 psql,fgedudb 库:
“`
\c fgedudb
SELECT oid,relname,relfilenode FROM pg_class WHERE relname=’t_biz_data’;
SELECT oid,datname FROM pg_database WHERE datname=’fgedudb’;
“`
拿到 database 的 oid,进入 base 下对应 oid 子目录,就可以看到 t_biz_data 对应的 relfilenode 数据文件、fsm、vm 文件。
“`
#示例,替换为实际查询出来的oid
cd /fgedudb/pg_data/fgedudb/base/数据库oid
ls -lh
“`
### 实操 2:创建业务表空间
“`
–表空间物理目录操作系统提前创建,权限postgres
CREATE TABLESPACE fgedu_ts LOCATION ‘/fgedudb/pg_tablespace/fgedu_ts’;
–将表创建到此表空间
CREATE TABLE t_biz_hot (id bigserial primary key,info text) TABLESPACE fgedu_ts;
–索引也可以指定表空间
CREATE INDEX idx_biz_hot_code ON t_biz_hot(info) TABLESPACE fgedu_ts;
\db
“`
操作系统查看 pg_tblspc 目录,是软链接指向`/fgedudb/pg_tablespace/fgedu_ts`真实目录。
>
> 风哥数据库教程 itpux‑com
### 物理存储运维要点
1. pg_wal 目录文件绝对不能手动 rm 删除,会直接导致实例崩溃无法恢复;
2. 表空间目录不能直接拷贝给另外一套 PG 集群,元数据记录在 global 系统表;
3. relfilenode 会发生变化:truncate 表、vacuum full 会改变 relfilenode,物理文件名改变,DBA 排查故障要注意这点;
4. page 默认 8KB,编译阶段 configure 可以修改 BLCKSZ,编译后不可变更。
## 四、PostgreSQL 进程架构:主进程、后台辅助进程、backend 会话进程
PostgreSQL 完全多进程架构,没有多线程,每个客户端连接生成独立 backend 进程,进程隔离,一个 backend 崩溃不会直接搞垮整个集群,主进程 postmaster 会负责重启清理资源。
进程角色分解:
1. **postmaster(守护主进程)**:集群根进程,负责监听端口,接收客户端 TCP 连接,fork 生成 backend 会话进程,管理所有后台辅助进程,信号处理,实例启停管理;postmaster PID 是整个集群标识。
2. **backend 后端会话进程**:每一个客户端连接对应一个 backend,执行 SQL,执行读写,拥有私有内存,崩溃由 postmaster 回收资源。
3. **bgwriter 后台写进程**:把 shared_buffers 脏页刷盘,减轻 checkpoint 压力,避免 checkpoint 瞬间大量 IO 风暴。
4. **checkpoint 检查点进程**:执行检查点,把内存脏数据持久化磁盘,更新 WAL LSN,崩溃恢复从上一个检查点开始重放 WAL。
5. **walwriter WAL 写进程**:专门负责把 WAL 缓冲区内容写入 pg_wal 磁盘文件,PG 重要的预写日志 WAL 机制。
6. **autovacuum 自动清理进程**:多子进程,执行 vacuum、vacuum analyze,清理 dead tuple 死元组,更新统计信息,防止表膨胀,MVCC 核心配套进程。
7. **archiver 归档进程**:开启 archive_mode 后,将 pg_wal 段文件归档,用于时间点 PITR 恢复。
>
> 上 51CTO 搜索风哥可以学习全套数据库教程
### 实操:查看全部 PostgreSQL 进程,主机 fgedu‑net‑cn1
“`
ps -ef | grep postgres
“`
可以看到 postmaster 主进程,backend 会话,bgwriter、checkpoint、walwriter、autovacuum、archiver 等后台进程。
psql 内部查看会话 backend pid:
“`
SELECT pid,usename,datname,state,query FROM pg_stat_activity;
–查看当前自己backend进程pid
SELECT pg_backend_pid();
“`
生产运维常见进程相关故障点:
1. autovacuum 未正常工作,表疯狂膨胀,元组堆积;
2. checkpoint 过于频繁,磁盘 IO 打满;
3. 大量空闲 backend 会话占用连接数;
4. archiver 归档卡住,pg_wal 目录持续暴涨磁盘占满。
## 五、PostgreSQL 内存结构理论,64G 内存 8C 硬件参数配置实操
PG 内存分为两大块:**共享内存(所有进程共同访问)、每个 backend 进程私有内存(每个连接独立分配)**。
### 共享内存核心参数(64G 物理内存 8CPU)
1. `shared_buffers`:PG 自己的内存缓冲池,建议设置物理内存 1/4,64G 机器设置 16G;不能超过操作系统总内存;PG 会在这里缓存数据 page;
2. `wal_buffers`:WAL 日志缓冲区,一般设置 16MB‑64MB;
3. `effective_cache_size`:查询规划器估算可用总缓存,规划索引扫描成本,64G 主机建议 48G;
### backend 进程私有内存(每个会话独立)
1. `work_mem`:排序、hash join、hash 聚合操作单操作内存;大查询会多次分配,不能设置过大;64G 机器设置 64MB;
2. `maintenance_work_mem`:vacuum、create index、alter table 维护操作内存,全局维护操作,64G 机器设置 1GB;
3. `temp_file_limit`:会话临时文件上限,防止 SQL 疯狂写临时文件打满磁盘。
### 实操:postgresql.conf 配置,适配 64G 内存 8CPU 实例
配置文件路径`/fgedudb/pg_data/fgedudb/postgresql.conf`
“`
#共享内存
shared_buffers = 16GB
wal_buffers = 64MB
effective_cache_size = 48GB
#私有会话内存
work_mem = 64MB
maintenance_work_mem = 1GB
temp_file_limit = 10GB
#连接参数
max_connections = 300
superuser_reserved_connections = 10
#WAL参数
max_wal_size = 4GB
min_wal_size = 1GB
wal_level = replica
#autovacuum
autovacuum = on
autovacuum_max_workers = 4
autovacuum_naptime = 1min
“`
修改配置后重载生效,不需要重启(部分参数需要重启):
“`
pg_ctl reload -D /fgedudb/pg_data/fgedudb
“`
psql 查看内存相关参数:
“`
show shared_buffers;
show work_mem;
show effective_cache_size;
“`
内存重要理论:操作系统还有 page cache 文件系统缓存;PG 的 shared_buffers + OS page cache 共同缓存数据;effective_cache_size 不实际分配内存,仅仅给优化器做成本估算。
## 六、PostgreSQL 源码文件目录结构与阅读工具
PostgreSQL 主体由 C 语言开发,contrib 存放社区附加模块;源码目录结构说明:
1. `src/backend`:核心服务端代码,进程、执行器、优化器、存储、WAL、vacuum;
2. `src/bin`:客户端工具二进制源码,psql、pg_ctl、initdb、pg_dump;
3. `src/include`:全部头文件,数据结构定义;
4. `src/interfaces`:libpq 客户端库源码;
5. `contrib`:扩展模块,pg_stat_statements、dblink、pg_buffercache 等附加工具;
常用源码阅读工具:
1. gdb:调试器,跟踪函数调用、断点、堆栈,本教程重点实操工具;
2. cscope /ctags:生成索引,跳转函数、变量定义;
3. vscode+clangd:现代编辑器源码浏览;
关键入口源码文件:
– initdb 主逻辑:`src/bin/initdb/initdb.c`
– postmaster 主进程入口:`src/backend/postmaster/postmaster.c`
– backend 后端会话入口:`src/backend/tcop/postgres.c`
– WAL 写逻辑:`src/backend/access/transam/xlog.c`
– 缓冲池管理:`src/backend/storage/buffer/bufmgr.c`
>
> 提示:阅读源码优先从 main 入口函数跟踪调用链,不要漫无目的浏览全部文件。
## 七、源码编译搭建调试环境完整实战
编译开启`‑‑enable‑debug`加入调试符号,方便 gdb 断点跟踪;开启`‑‑enable‑cassert`内部断言,用于开发调试,生产环境不要开启断言,会严重降低性能Postg…。主机`fgedu‑net‑cn1`操作。
### 7.1 下载解压源码包
“`
cd /fgedudb/pg_soft
#下载源码包,放置/fgedudb/pg_soft目录
tar -zxvf postgresql‑*.tar.gz
cd postgresql‑*
“`
### 7.2 configure 配置编译选项,开启调试符号
“`
./configure \
–prefix=/fgedudb/pg_soft/pg_bin \
–enable‑debug \
–enable‑cassert \
–with‑readline \
–with‑zlib
“`
– `–enable‑debug`:加入 gdb 调试符号;
– `–enable‑cassert`:开启内部断言,调试环境使用;
– prefix 指定编译安装输出目录`/fgedudb/pg_soft/pg_bin`。
### 7.3 编译安装,使用 8 核 CPU 并行编译
“`
make -j8
make install
#编译contrib扩展模块
cd contrib
make -j8
make install
“`
配置环境变量:
“`
echo “export PATH=/fgedudb/pg_soft/pg_bin/bin:\$PATH” >> /etc/profile
source /etc/profile
which psql
which initdb
“`
>
> 注意:此套编译带 debug 符号,**不能直接上生产环境**,性能低,体积大,专门用于源码学习调试。
## 八、gdb 调试工具跟踪 initdb 初始化全过程
initdb 是独立可执行程序,不属于 postmaster 后台进程,程序入口`src/bin/initdb/initdb.c main()`函数,gdb 可以直接运行 initdb,打断点跟踪每一步集群初始化流程。
### 8.1 清理旧数据目录,准备全新调试环境
“`
#停止旧实例
pg_ctl stop -D /fgedudb/pg_data/fgedudb
#清空数据目录,initdb调试需要全新目录
rm -rf /fgedudb/pg_data/fgedudb
mkdir -p /fgedudb/pg_data/fgedudb
chown postgres:postgres /fgedudb/pg_data/fgedudb
su – postgres
export PGDATA=/fgedudb/pg_data/fgedudb
“`
### 8.2 gdb 直接运行 initdb,设置断点
“`
gdb –args initdb -D $PGDATA –encoding=UTF8 –locale=en_US.UTF‑8 –data‑checksums
“`
进入 gdb 交互控制台:
“`
#设置main入口断点
b main
run
#单步 next,进入函数step,查看堆栈bt
next
step
bt
#设置关键函数断点,例如initdb的创建template数据库函数
b setup_template_databases
#continue继续执行
c
quit
“`
initdb 内部执行主要流程:
1. 创建 PGDATA 目录,生成 PG_VERSION 版本标记;
2. 初始化共享内存、基础系统 catalog 元数据表;
3. 初始化 pg_xact、pg_wal、global 系统目录;
4. 构建 template1、template0 模板数据库;
5. 生成 postgres 默认数据库;
6. 设置超级用户 postgres 密码,配置默认 pg_hba.conf、postgresql.conf。
通过 gdb 单步调试,能够看清每一步物理文件生成逻辑;initdb 执行完成之后,PGDATA 目录完整生成,此时就可以启动 postmaster 实例。
>
> 实操提示:gdb 调试 initdb,必须使用 postgres 操作系统用户,否则目录权限报错。
## 九、gdb 跟踪 PostgreSQL 实例启动流程
postmaster 是数据库守护主进程,二进制程序为`postgres`;启动流程:执行`pg_ctl start`,调用 postgres 可执行程序,进入 postmaster.c main 函数,初始化共享内存、信号量、WAL 恢复、加载系统 catalog,开始监听 TCP 端口,准备接收客户端连接。
### 9.1 方式一:gdb attach 附加到已经运行的 postmaster 进程
启动实例,拿到 postmaster 主 PID 号:
“`
su – postgres
pg_ctl start -D $PGDATA
ps -ef | grep postmaster
“`
attach 附加调试(调试环境,不要生产操作):
“`
gdb -p 主进程PID
“`
常用 gdb 命令:
“`
bt #打印调用堆栈
info threads #查看全部线程(PG多进程,这里看到fork子进程)
b PostmasterMain #主循环断点
c
next
quit
“`
### 9.2 跟踪 backend 会话进程
获取当前 backend pid,psql 内部执行`select pg_backend_pid();`,使用 gdb attach 绑定 backend pid,可以跟踪 SQL 执行内部调用链。
“`
gdb -p backend‑pid
“`
### 9.3 启动阶段断点,直接 gdb 运行 postgres 程序
“`
#先停止实例
pg_ctl stop -D $PGDATA
gdb –args postgres -D /fgedudb/pg_data/fgedudb
(gdb) b PostmasterMain
(gdb) run
“`
启动流程关键步骤:
1. PostmasterMain 入口,解析启动参数;
2. 信号、操作系统资源初始化;
3. 初始化共享内存、信号量;
4. WAL 崩溃恢复:重放 pg_wal 日志,恢复到一致性状态;
5. 加载系统全局 catalog;
6. 初始化各个后台辅助进程 bgwriter/checkpoint/walwriter/autovacuum;
7. 开启 socket 监听 5432 端口,等待客户端连接;
8. 收到连接请求 fork 生成 backend 子进程。
>
> 重要提醒:gdb attach 附加进程会暂停数据库运行,**生产环境绝对禁止操作**,只允许测试学习环境使用。
## 十、底层问题分析思路、运维落地建议
风哥结合体系结构与源码学习,整理 DBA 运维分析思路:
1. **故障优先区分现象层级**:
– 实例无法启动:优先看 postmaster 日志,排查共享内存、WAL 损坏、目录权限、pg_hba.conf、postgresql.conf 参数;
– SQL 性能慢:看 backend 进程、explain 执行计划、buffer 访问、IO;
– 表膨胀:重点排查 autovacuum 进程运行状态,MVCC 死元组;
– WAL 暴涨:检查 archiver 归档进程是否卡住。
2. **不要只看表面现象,回溯底层模型**:遇到锁、膨胀、crash,回到进程模型、内存模型、page 元组 MVCC 机制去理解根因。
3. 源码学习建议:不要通读全部源码,针对具体问题跟踪调用链;例如想搞懂 checkpoint,就在 gdb 针对 checkpoint 相关函数打断点,跟踪执行流程。
4. 调试编译版本只用于学习,生产使用官方 release 版本,关闭 debug 与 cassert 断言。
5. 物理备份迁移要理解 PGDATA 内部各个目录作用,不要随意手动删除 pg_wal、pg_xact 目录文件。
## 风哥针对本文总结
风哥教程本文完整讲解 PostgreSQL 体系结构深入与源码解析,包含整体架构总览、逻辑存储结构、物理存储 PGDATA 目录、page 页、表空间原理与实操;进程模型 postmaster 守护进程、backend 会话进程、bgwriter、checkpoint、walwriter、autovacuum 后台进程;内存模型共享内存与 backend 私有内存,基于 64G 内存 8CPU 硬件规格 postgresql.conf 参数配置;源码目录结构、源码阅读工具;完整实战搭建带调试符号的源码编译环境;使用 gdb 调试 initdb 集群初始化全过程;gdb 跟踪 postmaster 实例启动流程、backend 会话进程。
PostgreSQL 是多进程架构,每个客户端连接独立 backend 进程;集群 cluster 是 PG 非常核心概念,一套 PGDATA 对应一个集群,集群内部多个 database 数据库,database 之间物理隔离;物理存储最小 IO 单元为 8KB page;WAL 预写日志保障崩溃恢复能力,pg_wal 文件严禁手动删除。
源码调试环境仅用于学习研究,**禁止直接上线生产**;gdb attach 会暂停进程,仅测试环境使用。掌握体系底层原理,DBA 面对实例启动失败、表膨胀、WAL 异常、慢 SQL、锁冲突等故障,能够穿透现象定位根因,而不是只停留在简单配置复制粘贴。掌握本套风哥教程全部实操,能够建立 PostgreSQL 底层认知,为后续性能调优、故障排查、高可用架构打下坚实底层基础。
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
