PostgreSQL主库未归档WAL文件恢复及主备集群崩溃数据恢复问询
嘿,作为常年和PostgreSQL主备集群打交道的老玩家,我来一步步帮你搞定这两个问题,都是生产环境里很常见的崩溃恢复场景~
主库崩溃时,正在写入的WAL文件(也就是pg_wal目录里current链接指向的那个)通常还没触发归档——因为PostgreSQL只有在WAL segment写满切换时才会执行archive_command。要恢复这个文件,按以下步骤来:
第一步:停稳主库,别乱碰
先确保主库已经彻底停止运行,绝对不要贸然重启,否则可能会覆盖损坏的WAL文件,把最后一丝恢复机会搞没。第二步:定位目标WAL文件
进入主库的数据目录下的pg_wal子目录,执行:ls -l current你会看到类似这样的输出:
current -> 000000010000000000000005箭头后面的
000000010000000000000005就是正在写入的未归档WAL文件。第三步:手动归档这个文件
按照你主库的archive_command逻辑,把这个文件复制到归档目录(你的归档目录是/data):test ! -f /data/000000010000000000000005 && cp /path/to/main/pg_wal/000000010000000000000005 /data/要是主库的数据目录还能正常访问,直接这么操作就行;如果数据目录损坏但磁盘还能读,就从磁盘的原始路径里找到这个文件复制过去。
最坏情况:磁盘彻底损坏
如果主库磁盘完全挂了,这个未归档的WAL就没法恢复了,你只能恢复到最后一个已归档WAL的位置,这部分未归档的数据会丢失。
结合你的场景(主库开了归档,备库用了复制槽),分两部分解答:
2.1 如何从归档WAL恢复数据?
这里分两种常见情况:
情况A:备库还存活,只是离线
你可以把备库恢复到主库崩溃前的状态,然后提升为主库:
检查备库的恢复配置
确保备库的restore_command(PG12+是在postgresql.conf里配置,旧版本是recovery.conf)指向你的归档目录:restore_command = 'cp /data/%f %p'同时确认
recovery_target = 'latest'(默认就是这个值,会恢复到最新的可用WAL位置)。补上未归档的WAL
把刚才第一步找到的主库未归档WAL文件复制到/data归档目录里。启动备库并提升
启动备库:pg_ctl start -D /path/to/standby/data备库会自动从归档里拉取WAL进行恢复,直到没有更多WAL可用。恢复完成后,执行提升命令让它成为可读写的主库:
pg_ctl promote -D /path/to/standby/data
情况B:备库也挂了,需要从归档新建主库
这种情况需要你有主库的基础备份(如果没有的话,只能从初始化状态恢复,数据损失会很大):
解压基础备份到新目录
把你之前做的基础备份(比如用pg_basebackup生成的)解压到一个新的数据目录。配置恢复参数
- PG12及以上:修改新目录下的
postgresql.conf,添加:restore_command = 'cp /data/%f %p' recovery_target = 'latest' recovery_target_action = 'promote' # 恢复完成后自动提升为主库 - PG11及以下:在新目录创建
recovery.conf,写入:restore_command = 'cp /data/%f %p' recovery_target = 'latest' trigger_file = '/tmp/promote_me'
- PG12及以上:修改新目录下的
补上未归档WAL
同样把主库崩溃前的未归档WAL复制到/data归档目录。启动新实例
启动PostgreSQL,它会先恢复基础备份,然后自动从归档拉取所有WAL进行恢复,最后提升为可读写的主库。
2.2 如何获取主库崩溃前正在写入的最后一个WAL文件?
有几种可靠的方法:
方法1:查看
pg_wal的current链接
这是最直接的方式,进入主库pg_wal目录,执行:ls -l $PGDATA/pg_wal/current输出里箭头指向的文件名就是最后一个正在写入的WAL。
方法2:如果主库能启动到只读模式
要是主库没彻底坏,能启动到只读状态,连接进去执行SQL:SELECT pg_walfile_name(pg_current_wal_lsn());结果就是当前的WAL文件名。
方法3:从归档目录推断
查看归档目录/data里的WAL文件,按文件名排序(PG的WAL文件名是按LSN递增的),最大的那个是最后一个已归档的WAL,主库的最后一个WAL就是它的下一个编号(比如归档里最大的是000000010000000000000009,那主库的就是00000001000000000000000A)。方法4:扫描磁盘上的
pg_wal文件
如果主库数据目录损坏但磁盘可读,直接查看pg_wal目录下的所有文件,按修改时间排序,最新的那个(排除临时文件)就是目标WAL。
内容的提问来源于stack exchange,提问作者Mohamed Adel

