在PostgreSQL的容灾和备份体系中,WAL(Write-Ahead Logging,预写式日志)是最核心的数据资产。只要拿到了完整的WAL流,理论上就能把数据库恢复到任意时间点。很多管理员习惯用archive_command做日志归档,但这种方式依赖归档命令的成功返回,一旦脚本卡住或者磁盘满了,主库的WAL就可能堆积甚至撑爆磁盘。pg_receivewal作为PostgreSQL官方自带的流式日志接收工具,提供了一种更实时的方案:它像一台Standby一样通过流复制协议连接主库,源源不断地把WAL接收下来写到本地磁盘,而且每写入一部分就fsync落盘,实时性远高于按段归档。

一、pg_receivewal的工作原理
pg_receivewal本质上是一个流复制客户端。它连接到PostgreSQL主库后,并不像普通Standby那样做回放,而是使用复制协议中的复制槽(Replication Slot)机制,向主库声明自己要持续接收WAL流。主库在WAL写入的同时,会把日志片段通过复制连接推送给pg_receivewal,后者把收到的数据写入本地目录,默认按16MB一段切分成与主库相同的WAL段文件名。
p>与传统archive_command归档方式相比,最大的区别在于触发时机。archive_command只有在一段WAL写满或者超时切换后才会触发归档,也就是说低写入量的数据库可能要等很久才能归档一个小段;而pg_receivewal是实时接收的,主库每写入几百KB就会被推送过来并落盘,故障时丢失的数据窗口非常小。另外,pg_receivewal写入时会周期性执行fsync,保证日志落盘后再向主库确认,配合同步复制参数还可以做到接近零丢失。需要注意一点:pg_receivewal接收下来的文件可能是不完整的WAL段,也就是当前正在活跃写入的那个段,它在本地会先用临时文件名(结尾类似.partial)写入,等这段日志写满后才改名为正式段文件。在恢复时,这类不完整的段需要特殊处理,这一点在后面的问题排查部分会展开讲。
二、基础用法与常用参数
pg_receivewal位于PostgreSQL安装目录的bin下,最基本的用法是指定连接串和写入目录:
pg_receivewal -D /data/wal_archive \ -h 192.168.1.10 -p 5432 -U replicator \ --slot=wal_receiver_slot -S wal_receiver_slot
其中-D指定本地存放WAL的目录,-h和-p是主库地址和端口,-U是复制用户,-S指定复制槽名。执行前需要在主库做几项准备:首先postgresql.conf中wal_level必须设置为replica或logical;其次max_wal_senders要大于当前已占用的发送进程数;最后要创建复制槽,可以手动创建,也可以让pg_receivewal用--slot配合初次运行自动创建。
几个值得关注的参数:
- --synchronous:开启同步模式,pg_receivewal在每次fsync完成后才向主库反馈flush位置,配合主库的synchronous_standby_names可以做到事务级别的零丢失保护。
- --wal-segsize:当无法从主库获取段大小时,手动指定WAL段大小,必须与主库initdb时的--wal-segsize一致,否则文件切分会出错。
- --no-loop:连接失败时不自动重连,适合在脚本中配合监控使用,避免故障被静默掩盖。
- --compress:对落盘的WAL进行压缩(新版本支持LZ4、zstd、gzip),能显著降低磁盘占用,恢复时用pg_restorecombine或相应解压工具处理即可。
- --status-interval:向主库汇报进度的间隔,默认10秒,同步模式下建议适当调小。
另外建议把pg_receivewal配置成systemd服务常驻运行,示例配置如下,通过Restart=always保证进程异常退出后自动拉起:
[Unit] Description=pg_receivewal WAL receiver After=network.target [Service] User=postgres ExecStart=/usr/pgsql-15/bin/pg_receivewal -D /data/wal_archive \ -h 192.168.1.10 -p 5432 -U replicator -S wal_receiver_slot Restart=always RestartSec=5 [Install] WantedBy=multi-user.target
三、与pg_basebackup配合搭建持续备份环境
pg_receivewal通常不会单独使用,而是和pg_basebackup组合成一套完整的备份链路。典型流程是:先用pg_basebackup -X stream做一个基础备份并同时创建复制槽,然后立刻启动pg_receivewal接管这个槽持续接收增量日志。这样基础备份加后续WAL流,就构成了完整的恢复资料。
具体操作时,基础备份命令可以这样写:
pg_basebackup -h 192.168.1.10 -p 5432 -U replicator \ -D /data/base_backup -Fp -Xs -P -R \ --slot=wal_receiver_slot -C
这里-C表示自动创建复制槽,-Xs表示用流方式接收基础备份期间的WAL。备份完成后马上启动pg_receivewal并使用同名槽,日志流就不会中断。恢复时用recovery_command或者restore_command指向归档目录,把pg_receivewal落盘的WAL段喂给恢复进程,即可实现时间点恢复(PITR)。
这种架构的优点是链路简单、组件少、不依赖额外的归档脚本和共享存储,一台低配的归档服务器就能承载。缺点是它是单进程串行写盘,如果主库写入量非常大(比如每秒产生几十MB以上WAL),本地磁盘IO可能成为瓶颈,此时要考虑RAID缓存、SSD或者用压缩来缓解。
四、常见问题与排查思路
1. 复制槽导致主库WAL堆积。这是使用pg_receivewal最常见的隐患。因为复制槽会保留未消费的WAL,如果pg_receivewal进程挂了且长时间没人发现,主库的pg_wal目录会持续膨胀甚至撑爆磁盘。排查方法是在主库查询pg_replication_slots视图,关注restart_lsn列;运维上要配合监控告警,对pg_wal目录大小和槽的滞后量设置阈值,同时用systemd自动拉起进程降低风险。
2. 断点续传与partial文件处理。pg_receivewal重启后可以从上次位置继续接收,不用重新来过。但目录里可能存在xxxx.partial结尾的文件,恢复工具默认不识别。处理方式是:如果这个partial段是恢复所需的最后一段,复制一份并去掉.partial后缀放入恢复目录;也可以直接用pg_waldump确认其内容有效性后再决定是否使用。PostgreSQL较新版本的恢复流程已经能自动识别.partial文件,但老版本需要手工干预。
3. 连接认证失败。报错一般是复制权限或pg_hba.conf的问题。需要确认复制用户具有REPLICATION属性,且pg_hba.conf中为该用户配置了replication类型的条目,例如:
# TYPE DATABASE USER ADDRESS METHOD host replication replicator 192.168.1.0/24 scram-sha-256
修改后执行pg_ctl reload重新加载即可,不用重启主库。
4. 版本与平台一致性。pg_receivewal的版本最好不低于主库版本,低版本工具连接高版本主库可能出现协议不兼容或段大小识别失败的问题。另外段大小不匹配时报错信息有时比较隐晦,如果遇到莫名其妙的文件名或切分异常,优先用--wal-segsize显式指定再排查。
总体来看,pg_receivewal是一个轻量但可靠的WAL流式接收工具,配合复制槽和systemd守护,可以低成本搭建一套准实时的日志归档链路。掌握它的工作机制和坑点之后,无论是做异地容灾还是时间点恢复,都会多一份从容的底气。
pg_receivewalWAL日志流复制修改时间:2026-09-13 06:42:32