一、架构总览图

二、详细架构说明

1. 进程架构:多进程模型

PostgreSQL 采用经典的多进程架构,每个客户端连接对应一个独立的操作系统进程。

1.1 主守护进程(Postmaster)

  • 启动与初始化:第一个启动的进程,负责初始化共享内存、启动后台进程
  • 连接管理:网络端口(默认5432),接受客户端连接请求
  • 进程派生:为每个新连接 fork() 出独立的子进程(后端进程)
  • 信号处理:处理系统信号(SIGTERM、SIGHUP等),实现优雅关闭和配置重载
  • 子进程坚控:坚控子进程状态,处理异常退出的子进程

1.2 后端进程(Backend Process)

每个客户端连接对应一个独立的后端进程,包含完整的查询处理上下文:

// 进程上下文结构示意
typedef struct {
    Port *port;                    // 连接端口信息
    MemoryContext top_memory;      // 顶级内存上下文
    TransactionState s_cur;        // 当前事务状态
    List *parse_trees;             // 解析树列表
    QueryDesc *query_desc;         // 查询描述符
    TupleTableSlot *slot;          // 元组槽
    ResourceOwner resowner;        // 资源所有者
} BackendProcess;

1.3 后台辅助进程组

进程名称主要职责触发条件关键参数
Writer将脏页刷回磁盘后台定期或缓冲区满bgwriter_delay, bgwriter_lru_maxpages
WAL Writer刷写WAL缓冲区事务提交或缓冲区满wal_writer_delay, wal_writer_flush_after
Checkpointer执行检查点定期或手动CHECKPOINTcheckpoint_timeout, checkpoint_completion_target
Autovacuum Launcher启动自动清理工作进程定期检查需要清理的表autovacuum_naptime, autovacuum_max_workers
Autovacuum Worker执行实际的VACUUM/ANALYZE由Launcher启动autovacuum_vacuum_threshold
Archiver归档WAL日志WAL段文件切换archive_mode, archive_command
Stats Collector收集统计信息定期或DDL操作后stats_temp_directory
Logical Replication Launcher启动逻辑复制工作进程配置了逻辑复制时max_logical_replication_workers

2. 内存架构:分层管理

2.1 共享内存(Shared Memory)

在数据库启动时一次性分配,所有进程共享访问:

// 共享内存主要区域
typedef struct {
    shmem_startup_hdr *shim;      // 启动头信息
    PGShmemHeader *header;        // 共享内存头
    BufferDescriptors *buf_desc;  // 缓冲区描述符数组
    BufferBlocks *buf_blocks;     // 实际数据缓冲区
    LWLockArray *lock_array;      // 轻量级锁数组
    ProcArray *proc_array;        // 进程状态数组
    XLogCtlData *xlog_ctl;        // WAL控制结构
    CLogCtlData *clog_ctl;        // 提交日志控制
    MultiXactState *multi_state;  // 多事务状态
    // ... 其他共享数据结构
} SharedMemoryArea;

关键共享区域:

  • 共享缓冲区(Shared Buffers) :缓存数据页,减少磁盘I/O
  • WAL缓冲区(WAL Buffers) :事务日志的写前缓冲区
  • 锁表(Lock Tables) :存储表级、页级、行级锁信息
  • 进程表(Proc Array) :所有活动进程的状态信息
  • CLOG缓冲区:事务提交状态的缓存

2.2 进程私有内存(Local Memory)

每个后端进程独立分配,用于查询执行:

内存上下文用途生命周期
TopMemoryContext进程生命周期内存进程存活期间
CacheMemoryContext系统缓存(如relcache)长期存在
MessageContext客户端消息处理每个消息
TupleContext元组处理临时内存每个元组处理
ExprContext表达式求值每个表达式
WorkMem排序、哈希操作每个操作
MaintenanceWorkMemVACUUM、CREATE INDEX等维护操作期间

3. 查询处理流水线

3.1 解析阶段(Parser)

-- 示例:SELECT * FROM users WHERE id = 1;

解析器生成原始解析树

typedef struct SelectStmt {
    NodeTag type;
    List *targetList;      // 目标列列表
    List *fromClause;      // FROM子句
    Node *whereClause;     // WHERE条件
    List *groupClause;     // GROUP BY
    Node *havingClause;    // HAVING
    List *windowClause;    // WINDOW
    // ... 其他字段
} SelectStmt;

3.2 分析/重写阶段(Analyzer/Rewriter)

  • 语义分析:检查对象存在性、权限、类型兼容性
  • 查询重写:应用规则系统(如视图展开)
  • 输出查询树(Query Tree)
typedef struct Query {
    NodeTag type;
    CmdType commandType;    // SELECT/INSERT/UPDATE/DELETE
    List *rtable;           // 范围表
    List *jointree;         // 连接树
    List *targetList;       // 目标列表
    List *returningList;    // RETURNING列表
    // ... 其他字段
} Query;

3.3 优化阶段(Optimizer)

基于成本的优化器(CBO)工作流程:

  1. 子查询处理:扁平化子查询,转换为连接

  2. 预处理表达式:常量折叠、函数内联

  3. 生成路径

    • 顺序扫描路径(SeqScan)
    • 索引扫描路径(IndexScan、BitmapHeapScan)
    • 连接路径(NestLoop、HashJoin、MergeJoin)
  4. 成本估算:基于统计信息计算I/O、CPU成本

  5. 路径选择:选择成本最低的执行路径

// 路径成本估算
typedef struct Path {
    NodeTag type;
    NodeTag pathtype;       // 路径类型
    RelOptInfo *parent;     // 父关系
    PathTarget *pathtarget; // 路径输出
    ParamPathInfo *param_info;
    List *pathkeys;         // 路径排序
    double rows;            // 预估行数
    Cost startup_cost;      // 启动成本
    Cost total_cost;        // 总成本
} Path;

3.4 执行阶段(Executor)

采用火山模型(Volcano Model) ​ 的迭代器模式:

// 执行器状态机
typedef struct PlanState {
    NodeTag type;
    Plan *plan;                    // 对应的计划节点
    EState *state;                 // 执行状态
    TupleTableSlot *ps_ResultTupleSlot;  // 结果元组槽
    
    // 迭代器接口
    TupleTableSlot *(*ExecProcNode)(struct PlanState *pstate);
    
    // 子节点
    List *child_ps;
} PlanState;

主要执行节点类型:

  • 扫描节点:SeqScan、IndexScan、BitmapHeapScan
  • 连接节点:NestLoop、HashJoin、MergeJoin
  • 聚合节点:Agg、Group、WindowAgg
  • 排序节点:Sort、Materialize
  • 修改节点:ModifyTable(INSERT/UPDATE/DELETE)

4. 存储引擎架构

4.1 表空间与文件布局

$PGDATA/
├── base/                    # 默认表空间
│   ├── 1/                  # 数据库OID
│   │   ├── 12345           # 关系文件(表/索引)
│   │   ├── 12345_fsm       # 空闲空间映射
│   │   ├── 12345_vm        # 可见性映射
│   │   └── 12345_init      # 初始化分支
├── pg_tblspc/              # 表空间链接
├── pg_wal/                 # WAL日志
├── pg_xact/                # 提交日志
└── pg_stat/                # 统计信息

4.2 堆表存储结构

页面结构(8KB默认):

+-----------------------+
| PageHeaderData (24B)  |
+-----------------------+
| LinePointer1 (4B)     |
| LinePointer2 (4B)     |
| ...                   |
+-----------------------+
| Free Space            |
+-----------------------+
| Tuple1                |
| Tuple2                |
| ...                   |
+-----------------------+
| Special Space         |
+-----------------------+

元组头结构:

typedef struct HeapTupleHeaderData {
    union {
        HeapTupleFields t_heap;
        DatumTupleFields t_datum;
    } t_choice;
    
    ItemPointerData t_ctid;      // 当前元组ID(页号+行指针)
    
    uint16 t_infomask2;          // 属性数量+标志位
    uint16 t_infomask;           // 标志位(可见性、锁等)
    uint8 t_hoff;                // 头长度
    
    bits8 t_bits[FLEXIBLE_ARRAY_MEMBER];  // NULL位图
} HeapTupleHeaderData;

4.3 索引架构

PostgreSQL支持多种索引访问方法:

索引类型适用场景内部结构特性
B-Tree默认索引,范围查询B+树变体支持排序、唯一约束
Hash等值查询哈希表仅支持等值比较
GiST地理数据、全文搜索平衡树可扩展,支持自定义操作符
SP-GiST非平衡数据结构空间分区树适合不规则数据分布
GIN多值类型(数组、JSON)倒排索引支持包含查询
BRIN大数据表,有序数据块范围索引存储空间小

5. 事务与并发控制

5.1 MVCC实现机制

元组可见性判断算法:

bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
                            Buffer buffer) {
    // 获取元组的事务信息
    xmin = HeapTupleHeaderGetXmin(htup->t_data);
    xmax = HeapTupleHeaderGetXmax(htup->t_data);
    
    // 根据快照判断可见性
    if (TransactionIdIsCurrentTransactionId(xmin)) {
        // 当前事务插入
        if (HeapTupleHeaderGetCmin(htup->t_data) >= snapshot->curcid)
            return false;  // 命令ID在快照之后
        else
            return true;
    } else if (TransactionIdIsInProgress(xmin)) {
        // 其他活跃事务插入
        return false;
    } else if (TransactionIdDidCommit(xmin)) {
        // 已提交事务插入
        // 检查删除事务
        if (!HeapTupleHeaderXmaxCommitted(htup->t_data)) {
            if (TransactionIdIsCurrentTransactionId(xmax)) {
                // 当前事务删除
                return false;
            }
            if (TransactionIdIsInProgress(xmax)) {
                // 其他活跃事务删除
                return true;
            }
            if (TransactionIdDidCommit(xmax)) {
                // 已提交事务删除
                return false;
            }
            return true;  // 删除事务已中止
        }
        return false;  // 已删除
    } else {
        // 插入事务已中止
        return false;
    }
}

5.2 快照隔离级别

-- PostgreSQL支持的隔离级别
SET TRANSACTION ISOLATION LEVEL 
    READ UNCOMMITTED |  -- 实际实现为READ COMMITTED
    READ COMMITTED |    -- 默认级别
    REPEATABLE READ |   -- 快照隔离
    SERIALIZABLE;       -- 可串行化

快照数据结构:

typedef struct SnapshotData {
    SnapshotType snapshot_type;  // 快照类型
    TransactionId xmin;          // 最早仍活跃的事务ID
    TransactionId xmax;          // 第一个未分配的事务ID
    TransactionId *xip;          // 活跃事务ID数组
    uint32 xcnt;                 // 活跃事务数量
    CommandId curcid;            // 当前命令ID
    uint32 speculativeToken;
    struct GlobalVisState *vistest;
    TimestampTz taken_at;        // 快照获取时间
    // ... 其他字段
} SnapshotData;

6. WAL与恢复机制

6.1 WAL记录结构

typedef struct XLogRecord {
    uint32 xl_tot_len;      // 记录总长度
    TransactionId xl_xid;   // 事务ID
    XLogRecPtr xl_prev;     // 前一条记录指针
    uint8 xl_info;          // 标志位
    RmgrId xl_rmid;         // 资源管理器ID
    pg_crc32c xl_crc;       // CRC校验
    // 之后是实际的数据
} XLogRecord;

6.2 检查点机制

检查点触发条件:

  1. 时间间隔(checkpoint_timeout,默认5分钟)
  2. WAL段文件数量(max_wal_size,默认1GB)
  3. 手动执行CHECKPOINT命令

检查点执行流程:

void CreateCheckPoint(int flags) {
    // 1. 开始检查点
    START_CRIT_SECTION();
    
    // 2. 刷新所有脏页到磁盘
    CheckPointBuffers();
    
    // 3. 写入检查点记录到WAL
    XLogBeginInsert();
    XLogRegisterData(&checkPoint, sizeof(checkPoint));
    XLogInsert(RM_XLOG_ID, XLOG_CHECKPOINT_SHUTDOWN);
    
    // 4. 刷新WAL到磁盘
    XLogFlush(recptr);
    
    // 5. 更新控制文件
    UpdateControlFile();
    
    // 6. 删除旧的WAL文件
    RemoveOldWalFiles();
    
    END_CRIT_SECTION();
}

7. 扩展性架构

7.1 扩展接口

// 扩展加载接口
typedef struct {
    const char *name;           // 扩展名
    void (*init)(void);         // 初始化函数
    void (*shutdown)(void);     // 关闭函数
    // ... 其他钩子函数
} ExtensionCallbacks;

// 注册示例
PG_MODULE_MAGIC;
void _PG_init(void) {
    // 注册扩展
    RegisterExtension("my_extension", my_init, my_shutdown);
}

7.2 可扩展组件类型

组件类型注册函数用途示例
数据类型CREATE TYPE自定义几何类型、货币类型
函数CREATE FUNCTION用户定义函数、聚合函数
操作符CREATE OPERATOR自定义比较操作符
索引方法CREATE ACCESS METHOD支持新的索引结构
外部数据包装器CREATE FOREIGN DATA WRAPPER访问外部数据源
表访问方法CREATE TABLE ACCESS METHOD自定义表存储格式
过程语言CREATE LANGUAGEPL/Python、PL/Java

8. 关键性能优化点

8.1 缓冲区管理策略

  • 时钟扫描算法(Clock-sweep) :用于缓冲区替换
  • 预取(Prefetch) :顺序扫描时的异步I/O
  • 批量写入:检查点期间的顺序写优化

8.2 并行查询执行

-- 并行查询配置
SET max_parallel_workers_per_gather = 4;
SET parallel_setup_cost = 1000;
SET parallel_tuple_cost = 0.1;

-- 并行执行计划示例
EXPLAIN (ANALYZE, VERBOSE)
SELECT COUNT(*) FROM large_table WHERE condition;
-- 输出将显示 Workers Planned/Launched

8.3 分区表支持

-- 声明式分区
CREATE TABLE measurement (
    city_id int not null,
    logdate date not null,
    peaktemp int,
    unitsales int
) PARTITION BY RANGE (logdate);

-- 创建分区
CREATE TABLE measurement_y2023m01 
    PARTITION OF measurement
    FOR VALUES FROM ('2023-01-01') TO ('2023-02-01');

-- 分区裁剪优化
EXPLAIN SELECT * FROM measurement 
WHERE logdate >= '2023-01-15' AND logdate < '2023-01-20';

三、架构优势与特点

1. 进程隔离优势

  • 稳定性:单个进程崩溃不影响其他连接
  • 安全性:进程间内存隔离,防止内存泄漏扩散
  • 简化编程:无需处理多线程同步的复杂性

2. 扩展性设计

  • 可插拔存储引擎:通过表访问方法接口
  • 自定义数据类型:完整的类型系统支持
  • 丰富的索引类型:多种索引访问方法

3. 企业级特性

  • 完整的ACID支持:通过WAL和MVCC实现
  • 在线备份:支持热备份和PITR
  • 逻辑复制:数据选择性复制
  • 并行查询:多核CPU利用

4. 社区生态

  • 丰富的扩展:PostGIS(地理信息)、pgvector(向量搜索)、TimescaleDB(时序数据)
  • 多种连接池:pgBouncer、pgpool-II
  • 坚控工具:pg_stat_statements、pgBadger、pgAdmin

四、配置调优建议

1. 内存相关配置

# postgresql.conf 关键参数
shared_buffers = 4GB           # 共享缓冲区,建议系统内存的25%
work_mem = 64MB                # 每个操作的内存,复杂查询需要更多
maintenance_work_mem = 1GB     # 维护操作内存
effective_cache_size = 12GB    # 优化器假设的OS缓存大小

2. WAL相关配置

wal_level = replica            # 或 logical 用于逻辑复制
max_wal_size = 4GB             # 最大WAL大小
min_wal_size = 1GB             # 最小WAL大小
checkpoint_timeout = 15min     # 检查点时间间隔
checkpoint_completion_target = 0.9  # 检查点完成目标

3. 并行查询配置

max_worker_processes = 8       # 最大工作进程数
max_parallel_workers_per_gather = 4  # 每个Gather节点的并行数
max_parallel_workers = 8       # 系统并行工作进程数
parallel_setup_cost = 1000     # 并行启动成本
parallel_tuple_cost = 0.1      # 并行元组传输成本

总结

PostgreSQL 的架构设计体现了"稳健优先、功能丰富、高度可扩展"的哲学思想。其多进程模型虽然在某些高并发场景下可能不如多线程模型高效,但提供了无与伦比的稳定性和隔离性。清晰的模块化设计使得每个组件都可以独立优化和扩展,而严谨的 MVCC 实现和完整的 WAL 机制确保了数据的一致性和持久性。

随着 PostgreSQL 的持续发展,其架构也在不断演进,如引入了并行查询、JIT编译、增量排序等现代特性,同时保持了向后兼容性。这种平衡传统与创新的设计理念,使得 PostgreSQL 能够在保持稳定可靠的同时,不断适应新的应用场景和技术挑战。

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:alixiixcom@163.com