纲要
PostgreSQL系统架构概览- 客户端/服务器(C/S)模型
postmaster守护进程Backend进程与fork()机制
- 内存架构
- 共享内存(
Shared Memory)- 固定共享内存(
shared_buffers、wal_buffers等) - 动态共享内存(
Dynamic Shared Memory,DSM)
- 固定共享内存(
- 本地内存(
Local Memory)work_memmaintenance_work_memtemp_buffers
- 共享内存(
- 后台进程
Checkpointer(检查点进程)Background Writer(后台写进程)WAL Writer(预写日志写进程)Autovacuum Launcher/Autovacuum Worker(自动清理)Stats Collector(统计信息收集器,PostgreSQL 15 起移除)WAL Sender/WAL Receiver(物理复制)Logger(日志收集器)Archiver(归档进程)
- 进程查看与验证(
ps命令)
系统架构概览
PostgreSQL 采用经典的 客户端/服务器(C/S)模型 。客户端可以是 psql 命令行工具、JDBC 驱动程序、ODBC 驱动程序,以及 DBeaver、pgAdmin 等图形化管理工具。服务端则以 postmaster 为核心枢纽,统一管理连接请求、共享内存分配和后台进程的启停。
#mermaid-svg-xAvmjmofun8bqvIs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xAvmjmofun8bqvIs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xAvmjmofun8bqvIs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xAvmjmofun8bqvIs .error-icon{fill:#552222;}#mermaid-svg-xAvmjmofun8bqvIs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xAvmjmofun8bqvIs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xAvmjmofun8bqvIs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xAvmjmofun8bqvIs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xAvmjmofun8bqvIs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xAvmjmofun8bqvIs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xAvmjmofun8bqvIs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xAvmjmofun8bqvIs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xAvmjmofun8bqvIs .marker.cross{stroke:#333333;}#mermaid-svg-xAvmjmofun8bqvIs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xAvmjmofun8bqvIs p{margin:0;}#mermaid-svg-xAvmjmofun8bqvIs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xAvmjmofun8bqvIs .cluster-label text{fill:#333;}#mermaid-svg-xAvmjmofun8bqvIs .cluster-label span{color:#333;}#mermaid-svg-xAvmjmofun8bqvIs .cluster-label span p{background-color:transparent;}#mermaid-svg-xAvmjmofun8bqvIs .label text,#mermaid-svg-xAvmjmofun8bqvIs span{fill:#333;color:#333;}#mermaid-svg-xAvmjmofun8bqvIs .node rect,#mermaid-svg-xAvmjmofun8bqvIs .node circle,#mermaid-svg-xAvmjmofun8bqvIs .node ellipse,#mermaid-svg-xAvmjmofun8bqvIs .node polygon,#mermaid-svg-xAvmjmofun8bqvIs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xAvmjmofun8bqvIs .rough-node .label text,#mermaid-svg-xAvmjmofun8bqvIs .node .label text,#mermaid-svg-xAvmjmofun8bqvIs .image-shape .label,#mermaid-svg-xAvmjmofun8bqvIs .icon-shape .label{text-anchor:middle;}#mermaid-svg-xAvmjmofun8bqvIs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xAvmjmofun8bqvIs .rough-node .label,#mermaid-svg-xAvmjmofun8bqvIs .node .label,#mermaid-svg-xAvmjmofun8bqvIs .image-shape .label,#mermaid-svg-xAvmjmofun8bqvIs .icon-shape .label{text-align:center;}#mermaid-svg-xAvmjmofun8bqvIs .node.clickable{cursor:pointer;}#mermaid-svg-xAvmjmofun8bqvIs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xAvmjmofun8bqvIs .arrowheadPath{fill:#333333;}#mermaid-svg-xAvmjmofun8bqvIs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xAvmjmofun8bqvIs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xAvmjmofun8bqvIs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xAvmjmofun8bqvIs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xAvmjmofun8bqvIs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xAvmjmofun8bqvIs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xAvmjmofun8bqvIs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xAvmjmofun8bqvIs .cluster text{fill:#333;}#mermaid-svg-xAvmjmofun8bqvIs .cluster span{color:#333;}#mermaid-svg-xAvmjmofun8bqvIs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xAvmjmofun8bqvIs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xAvmjmofun8bqvIs rect.text{fill:none;stroke-width:0;}#mermaid-svg-xAvmjmofun8bqvIs .icon-shape,#mermaid-svg-xAvmjmofun8bqvIs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xAvmjmofun8bqvIs .icon-shape p,#mermaid-svg-xAvmjmofun8bqvIs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xAvmjmofun8bqvIs .icon-shape .label rect,#mermaid-svg-xAvmjmofun8bqvIs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xAvmjmofun8bqvIs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xAvmjmofun8bqvIs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xAvmjmofun8bqvIs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 服务端
fork
fork
fork
连接请求
刷盘
存储层
PGDATA 数据目录
base/
pg_wal/
pg_log/
共享内存区域
shared_buffers
wal_buffers
锁/信号量
动态共享内存
后台进程
Checkpointer
Background Writer
WAL Writer
Autovacuum Launcher
Stats Collector
PG 15 起移除
客户端层
psql
JDBC/ODBC
DBeaver/pgAdmin
postmaster 守护进程
Backend 进程 1
Backend 进程 2
Backend 进程 N
PostgreSQL 与 MySQL 的核心区别之一在于进程模型 :PostgreSQL 采用多进程架构 ,每个客户端连接对应一个独立的 Backend 进程;而 MySQL 采用多线程模型。
postmaster:一切进程的父进程
postmaster 是 PostgreSQL 实例启动时最先运行的进程。其主要职责包括:
- 加载
postgresql.conf等配置文件 - 分配共享内存区域
- 启动各类后台辅助进程
- 在指定 TCP/IP 端口监听客户端连接请求
Backend 进程:每个连接一个进程
当客户端发起连接请求时,postmaster 首先通过 pg_hba.conf 进行认证检查,认证通过后调用 fork() 系统调用创建一个新的子进程------即 Backend 进程。此后,该 Backend 进程专门负责与对应客户端的所有通信和 SQL 执行,postmaster 不再参与其中。
共享内存 Backend 进程 postmaster 客户端 共享内存 Backend 进程 postmaster 客户端 #mermaid-svg-FWW2gCSWaN00RLAD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FWW2gCSWaN00RLAD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FWW2gCSWaN00RLAD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FWW2gCSWaN00RLAD .error-icon{fill:#552222;}#mermaid-svg-FWW2gCSWaN00RLAD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FWW2gCSWaN00RLAD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FWW2gCSWaN00RLAD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FWW2gCSWaN00RLAD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FWW2gCSWaN00RLAD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FWW2gCSWaN00RLAD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FWW2gCSWaN00RLAD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FWW2gCSWaN00RLAD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FWW2gCSWaN00RLAD .marker.cross{stroke:#333333;}#mermaid-svg-FWW2gCSWaN00RLAD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FWW2gCSWaN00RLAD p{margin:0;}#mermaid-svg-FWW2gCSWaN00RLAD .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FWW2gCSWaN00RLAD text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-FWW2gCSWaN00RLAD .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-FWW2gCSWaN00RLAD .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-FWW2gCSWaN00RLAD .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-FWW2gCSWaN00RLAD .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-FWW2gCSWaN00RLAD #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-FWW2gCSWaN00RLAD .sequenceNumber{fill:white;}#mermaid-svg-FWW2gCSWaN00RLAD #sequencenumber{fill:#333;}#mermaid-svg-FWW2gCSWaN00RLAD #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-FWW2gCSWaN00RLAD .messageText{fill:#333;stroke:none;}#mermaid-svg-FWW2gCSWaN00RLAD .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FWW2gCSWaN00RLAD .labelText,#mermaid-svg-FWW2gCSWaN00RLAD .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-FWW2gCSWaN00RLAD .loopText,#mermaid-svg-FWW2gCSWaN00RLAD .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-FWW2gCSWaN00RLAD .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-FWW2gCSWaN00RLAD .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-FWW2gCSWaN00RLAD .noteText,#mermaid-svg-FWW2gCSWaN00RLAD .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-FWW2gCSWaN00RLAD .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FWW2gCSWaN00RLAD .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FWW2gCSWaN00RLAD .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FWW2gCSWaN00RLAD .actorPopupMenu{position:absolute;}#mermaid-svg-FWW2gCSWaN00RLAD .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-FWW2gCSWaN00RLAD .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FWW2gCSWaN00RLAD .actor-man circle,#mermaid-svg-FWW2gCSWaN00RLAD line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-FWW2gCSWaN00RLAD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 连接请求 pg_hba.conf 认证 fork() 创建子进程 连接成功,转交 BE 发送 SQL 查询 读取/写入数据 返回结果集
内存架构
PostgreSQL 的内存分为两大类别:共享内存(Shared Memory) 和本地内存(Local Memory)。
共享内存(Shared Memory)
共享内存是 PostgreSQL 实例中所有进程共同访问的内存区域,是进程间通信(IPC)的核心载体。共享内存可进一步细分为两种类型:
固定共享内存
在实例启动时,postmaster 根据配置参数一次性分配固定大小的共享内存。主要组成部分包括:
| 组件 | 配置参数 | 用途 |
|---|---|---|
| 共享缓冲区 | shared_buffers |
缓存表和索引的数据页 |
| WAL 缓冲区 | wal_buffers |
暂存 WAL 日志记录 |
| 锁空间 | --- | 轻量级锁、共享锁、排他锁等 |
| 元数据缓存 | --- | 系统表和对象元数据 |
shared_buffers 是 PostgreSQL 最核心的内存区域,相当于数据库的"二级缓存"。当执行查询需要读取数据时,Backend 进程会优先从 shared_buffers 中查找;若缓存未命中,再从磁盘读取并放入缓冲区。shared_buffers 的推荐配置为系统物理内存的 25% 左右。
sql
-- 查看当前 shared_buffers 配置
SHOW shared_buffers;
-- 查看当前 wal_buffers 配置
SHOW wal_buffers;
-- 动态修改 shared_buffers(需重启)
ALTER SYSTEM SET shared_buffers = '4GB';
动态共享内存(Dynamic Shared Memory, DSM)
动态共享内存是 PostgreSQL 9.6 版本引入的特性,用于支持并行查询(Parallel Query)。并行查询允许一个 SQL 语句利用多个 CPU 核心协同计算------即"人多力量大"。
并行查询执行时,leader 进程会动态创建 DSM 段,并启动多个 worker 进程。这些 worker 进程通过 DSM 进行通信和元组传递,查询执行完毕后 DSM 随即释放。
sql
-- 启用并行查询(默认开启)
SET max_parallel_workers_per_gather = 4;
-- 查看并行查询相关的 DSM 使用情况
SELECT * FROM pg_stat_activity WHERE backend_type = 'parallel worker';
本地内存(Local Memory)
每个 Backend 进程都拥有独立的本地内存区域,用于存放该会话执行 SQL 时的中间结果和临时数据结构。本地内存不与其他进程共享。主要参数包括:
| 参数 | 默认值 | 用途 |
|---|---|---|
work_mem |
4MB | 排序(ORDER BY、DISTINCT)、哈希连接(hash join)、聚合操作的内存 |
maintenance_work_mem |
64MB | VACUUM、CREATE INDEX、REINDEX 等维护操作的内存 |
temp_buffers |
8MB | 临时表的缓冲区 |
需要注意的是,work_mem 是每个操作 的内存上限,而非每个会话。一个复杂查询可能包含多个排序或哈希操作,每个操作都会独立申请 work_mem 内存。
sql
-- 会话级调整 work_mem(仅对当前会话生效)
SET work_mem = '64MB';
-- 查看当前会话的 work_mem
SHOW work_mem;
-- 查看 maintenance_work_mem
SHOW maintenance_work_mem;
后台进程
PostgreSQL 在启动时会自动启动一组后台进程,各司其职,协同完成数据库的日常维护工作。
Checkpointer(检查点进程)
检查点(Checkpoint) 是确保数据库一致性的关键机制。Checkpointer 进程定期将 shared_buffers 中的所有脏页(Dirty Pages)写入磁盘。检查点完成后,意味着数据库在该时间点达到了一致性状态------所有已提交事务的修改均已持久化到磁盘。
#mermaid-svg-zLIHv6g0mSwY6App{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zLIHv6g0mSwY6App .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zLIHv6g0mSwY6App .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zLIHv6g0mSwY6App .error-icon{fill:#552222;}#mermaid-svg-zLIHv6g0mSwY6App .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zLIHv6g0mSwY6App .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zLIHv6g0mSwY6App .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zLIHv6g0mSwY6App .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zLIHv6g0mSwY6App .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zLIHv6g0mSwY6App .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zLIHv6g0mSwY6App .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zLIHv6g0mSwY6App .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zLIHv6g0mSwY6App .marker.cross{stroke:#333333;}#mermaid-svg-zLIHv6g0mSwY6App svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zLIHv6g0mSwY6App p{margin:0;}#mermaid-svg-zLIHv6g0mSwY6App .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zLIHv6g0mSwY6App .cluster-label text{fill:#333;}#mermaid-svg-zLIHv6g0mSwY6App .cluster-label span{color:#333;}#mermaid-svg-zLIHv6g0mSwY6App .cluster-label span p{background-color:transparent;}#mermaid-svg-zLIHv6g0mSwY6App .label text,#mermaid-svg-zLIHv6g0mSwY6App span{fill:#333;color:#333;}#mermaid-svg-zLIHv6g0mSwY6App .node rect,#mermaid-svg-zLIHv6g0mSwY6App .node circle,#mermaid-svg-zLIHv6g0mSwY6App .node ellipse,#mermaid-svg-zLIHv6g0mSwY6App .node polygon,#mermaid-svg-zLIHv6g0mSwY6App .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zLIHv6g0mSwY6App .rough-node .label text,#mermaid-svg-zLIHv6g0mSwY6App .node .label text,#mermaid-svg-zLIHv6g0mSwY6App .image-shape .label,#mermaid-svg-zLIHv6g0mSwY6App .icon-shape .label{text-anchor:middle;}#mermaid-svg-zLIHv6g0mSwY6App .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zLIHv6g0mSwY6App .rough-node .label,#mermaid-svg-zLIHv6g0mSwY6App .node .label,#mermaid-svg-zLIHv6g0mSwY6App .image-shape .label,#mermaid-svg-zLIHv6g0mSwY6App .icon-shape .label{text-align:center;}#mermaid-svg-zLIHv6g0mSwY6App .node.clickable{cursor:pointer;}#mermaid-svg-zLIHv6g0mSwY6App .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zLIHv6g0mSwY6App .arrowheadPath{fill:#333333;}#mermaid-svg-zLIHv6g0mSwY6App .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zLIHv6g0mSwY6App .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zLIHv6g0mSwY6App .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zLIHv6g0mSwY6App .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zLIHv6g0mSwY6App .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zLIHv6g0mSwY6App .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zLIHv6g0mSwY6App .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zLIHv6g0mSwY6App .cluster text{fill:#333;}#mermaid-svg-zLIHv6g0mSwY6App .cluster span{color:#333;}#mermaid-svg-zLIHv6g0mSwY6App div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zLIHv6g0mSwY6App .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zLIHv6g0mSwY6App rect.text{fill:none;stroke-width:0;}#mermaid-svg-zLIHv6g0mSwY6App .icon-shape,#mermaid-svg-zLIHv6g0mSwY6App .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zLIHv6g0mSwY6App .icon-shape p,#mermaid-svg-zLIHv6g0mSwY6App .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zLIHv6g0mSwY6App .icon-shape .label rect,#mermaid-svg-zLIHv6g0mSwY6App .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zLIHv6g0mSwY6App .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zLIHv6g0mSwY6App .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zLIHv6g0mSwY6App :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 检查点触发
定时触发
checkpoint_timeout
Checkpointer
WAL 段累积
max_wal_size
扫描 shared_buffers
将所有脏页刷盘
更新 pg_control
标记检查点完成
sql
-- 查看检查点相关参数
SHOW checkpoint_timeout; -- 默认 5min
SHOW max_wal_size; -- 默认 1GB
SHOW checkpoint_completion_target; -- 默认 0.9
-- 手动触发检查点
CHECKPOINT;
Background Writer(后台写进程)
Background Writer 是 Checkpointer 的"好帮手"。它的职责是持续地、小批量地 将 shared_buffers 中的脏页写入磁盘,而不是等到检查点时一次性全部刷盘。
这种设计可以有效分散 I/O 压力,避免检查点期间产生大量的 I/O 突发,从而降低对业务高峰期的性能冲击。
sql
-- 查看 Background Writer 相关参数
SHOW bgwriter_delay; -- 默认 200ms
SHOW bgwriter_lru_maxpages; -- 默认 100
SHOW bgwriter_lru_multiplier; -- 默认 2.0
-- 查看 Background Writer 统计信息
SELECT * FROM pg_stat_bgwriter;
WAL Writer(预写日志写进程)
WAL Writer 负责将 wal_buffers 中的 WAL 日志记录写入磁盘上的 WAL 文件。WAL(Write-Ahead Logging,预写日志)是 PostgreSQL 实现事务持久性和崩溃恢复的核心机制。
sql
-- 查看 WAL 相关参数
SHOW wal_buffers; -- 默认 -1(自动调整)
SHOW wal_writer_delay; -- 默认 200ms
SHOW wal_writer_flush_after; -- 默认 1MB
Autovacuum Launcher / Worker(自动清理)
PostgreSQL 的 MVCC(多版本并发控制)机制中,UPDATE 和 DELETE 操作会在表中留下"死元组"(Dead Tuples)------类比房间里的外卖垃圾。Autovacuum 机制负责自动清理这些死元组并回收存储空间。
Autovacuum Launcher 是调度进程,它会定期检查哪些表需要清理,并启动 Autovacuum Worker 进程执行实际的清理工作。
此外,Autovacuum 还会更新表的统计信息(如表的行数、不同值的分布等),为查询优化器提供决策依据。
sql
-- 查看 Autovacuum 相关参数
SHOW autovacuum; -- on/off
SHOW autovacuum_vacuum_threshold; -- 默认 50
SHOW autovacuum_analyze_threshold; -- 默认 50
-- 手动执行 VACUUM(不回收空间给操作系统)
VACUUM my_table;
-- 手动执行 VACUUM FULL(回收空间,但会锁表)
VACUUM FULL my_table;
-- 手动更新统计信息
ANALYZE my_table;
Stats Collector(统计信息收集器)------ PostgreSQL 15 起移除
在 PostgreSQL 14 及更早版本中,Stats Collector 是一个独立的后台进程,负责收集全局统计信息(如表的行数、索引使用频率、值分布等),并通过临时文件(pg_stat_tmp 目录)进行持久化。
PostgreSQL 15 的重大变更 :官方社区移除了 Stats Collector 进程,改用动态共享内存(DSM) 直接存储统计信息。
这一变更带来的改进包括:
- 消除额外进程:不再需要独立的统计收集进程
- 减少 I/O 开销:统计信息不再频繁写入临时文件
- 更低延迟:统计信息实时写入共享内存,优化器可获得更及时的数据
sql
-- PostgreSQL 15+ 查看统计信息的系统视图(用法不变)
SELECT * FROM pg_stat_user_tables WHERE schemaname = 'public';
SELECT * FROM pg_stat_indexes WHERE schemaname = 'public';
SELECT * FROM pg_stat_activity;
WAL Sender / WAL Receiver(复制相关)
WAL Sender:在主库(发布端)按需创建,负责将 WAL 日志流式发送给备库WAL Receiver:在备库(订阅端)运行,负责接收来自主库的 WAL 日志流
这两个进程是 PostgreSQL 实现物理复制 和高可用的核心组件。
sql
-- 查看复制状态
SELECT * FROM pg_stat_replication;
SELECT * FROM pg_replication_slots;
其他后台进程
| 进程 | 用途 |
|---|---|
Logger |
将数据库运行日志写入 pg_log 目录 |
Archiver |
将 WAL 日志归档到指定目录 |
Logical Replication Launcher |
管理逻辑复制的 worker 进程 |
进程验证:使用 ps 命令查看
在 Linux/Unix 系统中,可以使用 ps 命令查看 PostgreSQL 的进程树:
bash
# 树形显示 PostgreSQL 进程
ps -ef | grep postgres
# 或使用 axjf 查看进程树
ps axjf | grep -E 'postgres|grep'
# 查看所有 PostgreSQL 相关进程
ps -eo pid,ppid,cmd | grep postgres | grep -v grep
典型的输出示例(PostgreSQL 14):
dir
postmaster (PID 3416)
├── checkpointer
├── background writer
├── walwriter
├── autovacuum launcher
├── stats collector
├── logical replication launcher
├── postgres: backend process (client connection 1)
├── postgres: backend process (client connection 2)
└── ...
在 PostgreSQL 15+ 中,stats collector 进程将不再出现。
API 速览
配置参数查询
sql
-- 查询单个参数
SHOW shared_buffers;
-- 查询所有参数
SELECT name, setting, unit, context FROM pg_settings WHERE name LIKE '%memory%';
动态修改配置(无需重启)
sql
-- 修改 work_mem(会话级)
SET work_mem = '128MB';
-- 修改 work_mem(全局,需重载配置)
ALTER SYSTEM SET work_mem = '128MB';
SELECT pg_reload_conf();
手动触发维护操作
sql
-- 手动检查点
CHECKPOINT;
-- 手动清理(不回收空间)
VACUUM my_table;
-- 手动清理并更新统计信息
VACUUM ANALYZE my_table;
-- 手动更新统计信息
ANALYZE my_table;
统计信息查询
sql
-- 查看表级统计信息
SELECT * FROM pg_stat_user_tables WHERE schemaname = 'public';
-- 查看索引使用统计
SELECT * FROM pg_stat_indexes WHERE schemaname = 'public';
-- 查看后台进程统计
SELECT * FROM pg_stat_bgwriter;
-- 查看当前活动会话
SELECT pid, usename, application_name, client_addr, state, query
FROM pg_stat_activity
WHERE state = 'active';
Demo 简单示例
以下是一个使用 Node.js + pg 库的完整示例,演示了 PostgreSQL 连接、查询执行以及统计信息查看。
运行说明
- 确保本地已安装 PostgreSQL 并启动服务
- 创建一个测试数据库和测试表
- 安装依赖:
npm install pg - 运行脚本:
node demo.js
代码示例
js
const { Client } = require('pg');
// PostgreSQL 连接配置
const config = {
host: 'localhost',
port: 5432,
database: 'postgres',
user: 'postgres',
password: 'your_password',
};
async function runDemo() {
const client = new Client(config);
try {
// 1. 建立连接 ------ 对应 postmaster 创建 Backend 进程
await client.connect();
console.log('✅ 连接成功,Backend 进程已创建');
// 2. 创建测试表
await client.query(`
DROP TABLE IF EXISTS test_users;
CREATE TABLE test_users (
id SERIAL PRIMARY KEY,
name TEXT,
age INTEGER,
created_at TIMESTAMP DEFAULT NOW()
);
`);
console.log('✅ 测试表创建成功');
// 3. 插入测试数据
await client.query(`
INSERT INTO test_users (name, age)
SELECT
'User_' || generate_series,
floor(random() * 50 + 20)
FROM generate_series(1, 10000);
`);
console.log('✅ 插入 10000 条测试数据');
// 4. 执行查询 ------ Backend 进程从 shared_buffers 读取数据
const res = await client.query(`
SELECT age, COUNT(*)
FROM test_users
GROUP BY age
ORDER BY age;
`);
console.log(`✅ 查询完成,返回 ${res.rowCount} 行`);
// 5. 查看当前会话的 work_mem 设置
const workMemRes = await client.query('SHOW work_mem;');
console.log(`📊 当前 work_mem: ${workMemRes.rows[0].work_mem}`);
// 6. 查看 shared_buffers 设置
const sharedBuffersRes = await client.query('SHOW shared_buffers;');
console.log(`📊 当前 shared_buffers: ${sharedBuffersRes.rows[0].shared_buffers}`);
// 7. 查看表统计信息(由 Stats Collector / 共享内存提供)
const statsRes = await client.query(`
SELECT
schemaname,
tablename,
n_live_tup,
n_dead_tup,
last_vacuum,
last_analyze
FROM pg_stat_user_tables
WHERE tablename = 'test_users';
`);
console.log('📊 表统计信息:', JSON.stringify(statsRes.rows[0], null, 2));
// 8. 查看后台进程统计
const bgwriterRes = await client.query(`
SELECT
checkpoints_timed,
checkpoints_req,
buffers_checkpoint,
buffers_clean,
buffers_backend
FROM pg_stat_bgwriter;
`);
console.log('📊 后台写进程统计:', JSON.stringify(bgwriterRes.rows[0], null, 2));
// 9. 查看当前活动会话(包含本会话的 Backend 进程)
const activityRes = await client.query(`
SELECT pid, usename, application_name, state, backend_type
FROM pg_stat_activity
WHERE pid != pg_backend_pid();
`);
console.log(`📊 当前其他活动会话数: ${activityRes.rowCount}`);
// 10. 清理测试数据
await client.query('DROP TABLE test_users;');
console.log('✅ 测试表已清理');
} catch (err) {
console.error('❌ 错误:', err.message);
} finally {
await client.end();
console.log('✅ 连接已关闭,Backend 进程终止');
}
}
runDemo();
代码说明
| 步骤 | 对应技术点 |
|---|---|
| 连接建立 | postmaster 监听端口 → fork() 创建 Backend 进程 |
| 数据插入 | 数据写入 shared_buffers,WAL 记录写入 wal_buffers |
| 查询执行 | Backend 进程从 shared_buffers 读取缓存页 |
SHOW work_mem |
查看本地内存参数(会话级) |
pg_stat_user_tables |
查看统计信息(PG 15 前来自 Stats Collector,PG 15+ 来自共享内存) |
pg_stat_bgwriter |
查看 Background Writer 和 Checkpointer 的工作统计 |
pg_stat_activity |
查看所有 Backend 进程和后台进程的状态 |
对应的 PostgreSQL 原生指令
sql
-- 连接数据库
psql -h localhost -p 5432 -U postgres -d postgres
-- 创建测试表
CREATE TABLE test_users (id SERIAL PRIMARY KEY, name TEXT, age INTEGER);
-- 插入测试数据
INSERT INTO test_users (name, age) SELECT 'User_' || generate_series, floor(random() * 50 + 20) FROM generate_series(1, 10000);
-- 执行查询
SELECT age, COUNT(*) FROM test_users GROUP BY age ORDER BY age;
-- 查看参数
SHOW work_mem;
SHOW shared_buffers;
-- 查看统计信息
SELECT schemaname, tablename, n_live_tup, n_dead_tup FROM pg_stat_user_tables WHERE tablename = 'test_users';
-- 查看后台写进程统计
SELECT * FROM pg_stat_bgwriter;
-- 查看活动会话
SELECT pid, usename, state, backend_type FROM pg_stat_activity;
-- 清理
DROP TABLE test_users;
技术点总结
- 进程模型 :每个客户端连接对应一个独立的
Backend进程 - 共享内存 :
shared_buffers缓存数据页,wal_buffers缓存 WAL 日志 - 本地内存 :
work_mem控制排序/哈希操作的内存上限 - 后台进程 :
Checkpointer、Background Writer、WAL Writer、Autovacuum等协同工作 - 统计信息 :PG 15 前由
Stats Collector进程收集,PG 15+ 改用共享内存
项目难点与解决方案
核心难点
- 多进程通信的复杂性 :PostgreSQL 的多进程架构需要依赖共享内存和信号量实现进程间通信,对操作系统的 IPC 配置(如
shmmax、shmall)有较高要求 - 检查点 I/O 冲击 :
Checkpointer一次性刷盘大量脏页会导致 I/O 突发,影响在线业务的响应时间 - MVCC 带来的垃圾膨胀 :频繁的
UPDATE/DELETE会产生大量死元组,若不及时清理会导致表膨胀和性能退化
解决方案
- Background Writer 分摊 I/O 压力 :通过
bgwriter_delay和bgwriter_lru_maxpages参数控制刷盘节奏,将集中式 I/O 转化为分散式 I/O - Checkpoint 调优 :通过
checkpoint_completion_target参数(默认 0.9)延长检查点的完成窗口,平滑 I/O 负载 - Autovacuum 精细化管理 :根据表的大小和更新频率,为不同表设置不同的
autovacuum_vacuum_scale_factor和autovacuum_analyze_scale_factor,避免全表扫描带来的性能开销
广度
涵盖 PostgreSQL 从客户端连接、进程模型、内存架构到后台进程的完整体系,涉及 10+ 种核心进程和 6+ 个关键内存参数。
深度
深入剖析了共享内存的两种类型(固定 vs 动态)、Checkpointer 与 Background Writer 的协作机制、以及 PostgreSQL 15 移除 Stats Collector 的架构演进原因。
复杂度
涉及操作系统层面的进程管理(fork())、IPC 通信(共享内存/信号量)、数据库内核层面的缓冲区管理、WAL 机制和 MVCC 垃圾回收,属于 PostgreSQL 中级到高级的系统架构知识。
官方文档
- PostgreSQL 官方文档 - 连接建立方式
- PostgreSQL 官方文档 - 资源消耗配置
- PostgreSQL 官方文档 - 累计统计系统
- PostgreSQL 官方文档 - 预写日志 WAL
- PostgreSQL 官方文档 - 自动清理 Autovacuum
- PostgreSQL 官方文档 - 并行查询
- PostgreSQL Wiki - 并行查询
参考链接
- PostgreSQL 15 Release Notes
- PostgreSQL 15 移除 Stats Collector 详解
- Inside PostgreSQL Shared Memory
- PostgreSQL 进程与内存浅析
总结
本文系统梳理了 PostgreSQL 的进程与内存架构。PostgreSQL 采用多进程 C/S 模型 ,以 postmaster 为守护进程,通过 fork() 为每个客户端连接创建独立的 Backend 进程。
内存方面分为共享内存 (包含固定大小的 shared_buffers/wal_buffers 和动态共享内存 DSM)和本地内存 (work_mem、maintenance_work_mem、temp_buffers)。后台进程各司其职:Checkpointer 保障数据一致性、Background Writer 平滑 I/O 压力、WAL Writer 确保事务持久性、Autovacuum 清理 MVCC 垃圾并更新统计信息。
PostgreSQL 15 起移除了 Stats Collector 进程,改用共享内存存储统计信息,减少了 I/O 开销和进程间通信。理解这些底层机制,是进行性能调优、故障排查和架构设计的基础。