大数跨境
0
0

跟着问题学习PG3:进程哪些事

跟着问题学习PG3:进程哪些事 程序猿读历史
2025-08-18
5
跟着问题学习PG1:从备库查询被终止说起
跟着问题学习PG2:vacuum 前世今生
数据库设计哲学1:空间换时间
数据库设计哲学2:分而治之
数据库设计哲学3:局部性
数据库设计哲学4:池化
继续跟着问题学习PG,前两篇介绍流复制和vacuum,今天聊聊PG的另一大特点——多进程架构。不同于MySQL的多线程模式,PG 采用多进程设计。我们知道进程作为操作系统资源分配的基本单位,拥有独立内存空间和文件描述符,进程间彼此资源隔离,这种结构有效提升了数据库的稳定性。
本文深入分析PG 关键进程,包括守护、服务、后台、复制等进程,阐述其功能与协作机制,以及在生产问题排查提供理论依据和解决方案。全文约4000字,阅读时间约20分钟。
图片
01 进程结构

PG 中最重要两个进程是守护进程 postgres server process 和服务进程 postgres backend process。

PG 守护进程的名称有一段演变历史。在8.2版本之前称为 postmaster;此后社区将其更名为postgres,同时保留postmaster符号链接以确保兼容性;而在2023年发布的16版本中,"General incompatibilities"明确记载已移除postmaster二进制文件的符号链接。[1][2]

除了两个核心进程外,还包括Background writerCheckpointer、WAL writer、Autovacuum、Statistics collector、Log writerArchiver以及复制等其他相关进程。它的进程结构图如下图1.

图1:PG 进程结构,来自interdb.jp [3]

图片
02 进程介绍

Postgres server process

Server 进程守护进程负责数据库实例的启动、关闭、崩溃恢复、监听客户端连接以及启动和管理一系列后台维护进程,比如Checkpointer、Autovacuum等。

比如当守护进程监听到客户端请求并有新的连接到来时,fork 出一个专属的 backend 进程, backend 进程负责解析 SQL、生成执行计划并最终执行查询或更新。所有 backend 共享一块公共的内存区域(Shared memory),其中包含 Shared buffers、WAL buffers 等,用来在不同进程之间交换数据和保持一致性。

更多守护进程的信息,可以参考文模连接[4].

Postgres backend process

Backend 进程用于接收、执行客户端发送的命令,并调用底层存储、事务管理、索引等功能模块,完成客户端的各种数据库操作,并返回执行结果;除此之外,后端进程也会参与其他进程协作。比如后端进程本身不会长期刷盘,而是把脏页标记后,由 background writercheckpoint 等进程负责最终落盘。

一个连接结束,backend 进程退出,所有专属于该连接的资源都会释放。但如果使用了PgBouncer 连接池,backend 进程会存活更久,资源释放则取决于不同连接池的工作原理。

Background Writer

Background Writer 的主要任务是将 shared buffers 中的脏页异步周期性写入数据文件,通过持续、平滑地将缓冲区中的数据刷盘,有效平衡了数据的持久性和写入性能。主要相关参数是[5]:

bgwriter_delay = 200ms        bgwriter_lru_maxpages = 100   bgwriter_lru_multiplier = 2.0 bgwriter_flush_after = 512kB 
  • bgwriter_delay

backgroud writer 进程连续两次flush数据之间的时间的间隔。默认值是200,单位是毫秒。

  • bgwriter_lru_maxpages

backgroud writer进程每次写的最大数据量,默认值是100,单位buffers。

  • bgwriter_lru_multiplier

backgroud writer每次扫描的缓冲区数量与最近一次检查点以来实际被访问过的缓冲区数量的倍数关系,默认值是2。
  • bgwriter_flush_after 

是指定后台写入进程在累计写入一定量数据后,强制将操作系统缓存中的数据刷写到磁盘的阈值。Linux 上的默认值为 512kB,其他地方的默认值为 0。

Checkpoint

Checkpoint 负责生成数据库的检查点,确保在宕机或崩溃恢复时,系统能回到一致性的状态。它会将 shared buffers 中的所有脏页与 WAL 日志同步刷盘,从而保证数据文件和 WAL 的对应关系一致。检查点机制避免了在恢复过程中需要从很早的日志位置开始回放,缩短了恢复时间,同时保证了数据库事务持久化的可靠性。主要相关参数是:

checkpoint_timeout = 5mincheckpoint_completion_target = 0.9max_wal_size = 1GB
  • checkpoint_timeout

两次检查点之间的最大时间间隔,单位是秒。

  • checkpoint_completion_target

控制着检查点完成的速度,它决定了在两次检查点之间,系统应该花多长时间来完成一个检查点操作,值是0 到1 之间的浮点数,表示检查点完成时间占两次检查点间隔时间的比例

  • max_wal_size

WAL 文件允许的最大大小,超过后触发检查点。这不是严格限制,在特殊情况下,例如高负载、失败的 archive_command 或高 wal_keep_size 设置,WAL 大小可能会超过 max_wal_size 。

WAL Writer

WAL Writer 进程负责把 WAL 缓冲区中的日志数据定期写入磁盘文件,确保事务持久性。与每个事务自己写 WAL 的方式相比,集中写入可以显著减少磁盘写次数,降低 I/O 压力。这样既保证了事务提交后的数据安全性,又通过批量化写盘优化了性能,是数据库在高并发场景下维持稳定吞吐量的重要保障。

wal_writer_delay = 200mswal_writer_flush_after = 1MB
  • wal_writer_delay

WAL 写进程的唤醒间隔,单位毫秒。

  • wal_writer_flush_after

控制 WAL writer 每写多少字节后强制 fsync 刷新。如果未指定单位,则将其视为 WAL 块,即 XLOG_BLCKSZ 字节,通常为 8kB。默认值为 1MB 。

Autovacuum

Autovacuum 进程主要负责自动清理表死元组,防止表无限膨胀。它在后台按需运行,无需人工干预,保证了表空间的可控和查询效率的稳定。

关于Autovacuum 更多信息,在上一篇文章中有详细介绍,有兴趣的同学可以阅读跟着问题学习PG2:vacuum 前世今生

Log Writer

Log Writer 将数据库运行中的日志记录写入磁盘文件,方便管理员进行诊断和审计,记录系统运行日志,比如错误信息、慢查询、连接情况等,不包括WAL日志。通过及时刷盘,Log Writer 确保了系统运行日志的完整性和实时性,为定位问题、优化 SQL、追溯异常提供了可靠依据。相关参数有:

logging_collector = offlog_directory = loglog_filename = postgresql-%Y-%m-%d_%H%M%S.loglog_rotation_age = 24hlog_rotation_size = 10MB
  • logging_collector

是否启用日志收集进程,默认off

  • log_directory

日志文件存放目录。

  • log_filename

日志文件命名规则。

  • log_rotation_age

当 logging_collector 启用时,此参数确定单个日志文件的最大使用时间,之后将创建新的日志文件,默认1天。

  • log_rotation_size

当 logging_collector 开启时,此参数决定单个日志文件的最大大小。当向日志文件中写入这么多数据后,将创建新的日志文件,默认10MB

Archiver

Archiver 进程在数据库启用 WAL 归档模式时启动,其任务是将已完成的 WAL 文件复制到长期存储中。归档日志为时间点恢复(PITR)和主备复制提供了必要保障。即使主库发生故障,通过归档的 WAL 文件,数据库可以恢复到任意指定时间点。对于需要高可用和数据安全的生产环境,Archiver 是关键的数据保护工具。

archive_mode = offarchive_command = ''archive_timeout = 1min
  • archive_mode

是否启用 WAL 归档,默认OFF,可以设置on 和 always

  • archive_command

执行归档的命令,默认值是一个空字符串, “%p” 表示将要归档的wal文件包含完整路径的信息的文件名,“%f” 代表不包含路径信息的wal文件的文件名

  • archive_timeout

即使未填满 WAL 文件,也强制归档的最大时间间隔,默认是0。建议改成每分钟,确保即使在数据库活动较少的情况下,也能定期触发 WAL 日志的归档操作,从而减少未归档数据的积累。

根据上面介绍,整理出PG 主要进程表格,如表1。

表1:PG 主要进程介绍

在PG 中除上述进程外,还包含复制、统计信息收集以及18版本中最新退出的异步IO相关进程: 
逻辑复制中的Logical Replication Launcher 管理相关工作进程的启停与监控;WAL Sender 从发布端提取并传输逻辑变更;Apply Worker 在订阅端接收并应用变更以保持数据一致;流复制中,Replication Sender 从主库发送 WAL 日志,Replication Receiver 在备库接收以实现同步。  
此外,还有异步并发处理的 IO worker ,以及 Statistics Collector 专门收集数据库运行时统计信息。
图片
03 进程案例

在linux 操作系统中,我们可以通过ps 命令查看PG的进程。在以下示例中,有一个 postgres 守护进程,ID 为 6541,两个后端进程分别是8412 和 8482,以及其他后台进程。

$ pstree -6541-+= 00001 root /sbin/launchd \-+= 06541 postgres /usr/local/pgsql/bin/postgres -D data   |--= 06542 postgres postgres: io worker 0   |--= 06543 postgres postgres: io worker 1   |--= 06544 postgres postgres: io worker 2   |--= 06545 postgres postgres: checkpointer   |--= 06546 postgres postgres: background writer   |--= 06548 postgres postgres: walwriter   |--= 06549 postgres postgres: autovacuum launcher   |--= 06550 postgres postgres: walsummarizer   |--= 06551 postgres postgres: logical replication launcher   |--= 08412 postgres postgres: postgres testdb [local] idle   |--= 08482 postgres postgres: postgres testdb [local] idle in transaction
08412 postgres: postgres testdb [local] idle08482 postgres: postgres testdb [local] idle in transaction

这两个是服务进程,idle表示空闲,idle in transaction表示事务未提交。I/O Workers(PIDs 06542-06544)这三个进程是PG 18 新增加的通过异步I/O操作提升系统并发能力进程。

图片
04 进程运维实战

了解 PG 的进程模型,除了更清楚每个连接、查询和后台任务是怎么被调度和执行以外,在实际运维中,遇到 CPU 高、IO 卡、性能抖动或者阻塞时,也能知道问题出在哪个进程,方便调优连接池、内存和事务策略,做到有的放矢地提升性能和稳定性,实现数据库运维的知行合一。下面通过具体的生产案例,从进程角度解决。

Checkpoint 过于频繁

Checkpoint 是将共享缓冲区中的脏页写回磁盘的过程,这可能会带来大量磁盘 I/O,从而引起数据库 TPS下降,但这是在保证数据持久性与写入性能之间提供了平衡,也是几乎所有关系型数据库的通用设计。

查看PG 日志,看到类似下面信息:

LOG:  checkpoint starting: timeLOG:  checkpoint complete: wrote 1024 buffers (8.0%); 0 WAL file(s) added, 0 removed, 2 recycled; write=150.123 s, sync=2.456 s, total=152.789 s; sync files=100, longest=0.200 s, average=0.024 s

如果你在日志里频繁看到 checkpoint starting,而且间隔明显小于 checkpoint_timeout(默认 5min),说明 checkpoint 触发得太频繁。触发原因可能是大量写入操作导致脏页积压,max_wal_size 设置过小,WAL 快速膨胀导致频繁触发,需要讨论checkpoint_timeout 、checkpoint_completion_target 等参数是否设置合理。

Autovacuum 导致抖动

Autovacuum 是用于自动清理表中的死元组、回收空间并更新统计信息,防止表膨胀和查询性能下降。在高并发或大表环境下,Autovacuum 有时会触发大量 I/O 和 CPU 消耗,尤其是在清理大型表或执行复杂索引维护时。这种突然启动的资源占用会与业务查询争用 CPU 和磁盘,导致短时间内 TPS 下降或响应变慢,出现性能抖动。

查看日志,看到类似下面信息:

LOG:  automatic vacuum of table "public.orders": index scans: 1      pages0 removed, 2000 remain, 1500 skipped due to pins...      tuples50000 removed, 200000 remain

也可以从 pg_stat_activity 里看到 autovacuum worker 占用资源。

为缓解这种抖动,可以通过调整 Autovacuum 参数。比如降低 autovacuum_vacuum_cost_limit 和 autovacuum_vacuum_cost_delay,让清理过程更平滑;针对大表,可采用分区表或手动分批 VACUUM;同时,合理设置 autovacuum_naptime 和并发 worker 数量,使 Autovacuum 在业务低峰期运行,从而减少对正常事务的影响,保持系统稳定。

WAL Archiver 堵塞事务

WAL Archiver 是负责将 WAL(Write-Ahead Log)日志归档到外部存储,如 NFS、S3 或备份服务器,以保证数据库可以进行 PITR(时间点恢复)。当归档操作失败或速度跟不上 WAL 生成速度时,导致 WAL 文件在 pg_wal 目录中堆积,从而阻塞前端事务提交。

查看日志,看到类似下面信息:

LOG:  archive command failed with exit code 1DETAIL:  The failed archive command was: cp pg_wal/000000010000000A000000FB /backup/pg_wal/WARNING:  archiving transaction log file "000000010000000A000000FB" failed too many times, will try again later

这种堵塞通常由网络延迟、外部存储不可用、权限问题或归档命令脚本错误引起。为解决此问题,可以优化归档目标的性能,确保网络稳定和权限正确,同时对归档命令脚本进行异常处理和重试机制。

可通过监控pg_stat_archiver、配置合理的wal_keep_size、调整归档速率预防 WAL 堆积;清理归档目录空间,对pg_wal目录大小设置告警,检查archive_status文件状态,以维持数据库正常写入性能和高可用性。

实际上,Checkpoint、Autovacuum、WAL Arch 引发的问题看似都能从日志找到线索,深层次的是反映了数据库架构层面的资源管理问题。Checkpoint 受 WAL 写入和脏页压力影响,Autovacuum 抖动源于死元组清理与业务 I/O 冲突,Archiver 堵塞则暴露备份链可靠性问题。理解这些进程机制,能更准确、快速地解决问题。

图片
05 总结

本文主要介绍 PG 相关进程含义、作用,以及在实际运维中如何根据相关现象,从数据库进程角度解释问题原因,并给出可靠的解决方案。

参考

1、https://www.postgresql.org/docs/release/8.2.0/

2、https://www.postgresql.org/docs/release/16.0/

3、https://www.interdb.jp/pg/pgsql02/01.html

4、https://www.crunchydata.com/blog/postgres-postmaster-file-explained5、https://www.postgresql.org/docs/14/runtime-config-wal.html

图片

作者介绍

司马辽太杰,10余年数据库架构和运维管理经验,擅长常见关系型、NoSQL、MPP 等类型数据库。业余热爱历史、足球,读点闲书。欢迎关注个人公众号“程序猿读历史”。需联系,可从关注公众号,在公众号对话窗口中扫码添加好友。感谢您的支持!

图片

【声明】内容源于网络
0
0
程序猿读历史
这是一位数据库从业者以及历史爱好者的个人公众号。
内容 87
粉丝 0
程序猿读历史 这是一位数据库从业者以及历史爱好者的个人公众号。
总阅读123
粉丝0
内容87