修复后目录结构
/var/lib/pgsql/15/
├── data/ # PGDATA 主目录
│ ├── pg_tblspc/
│ │ └── 24610 -> /var/lib/pgsql/15/pg_tps # 符号链接
│ ├── base/ # 默认表空间数据
│ ├── global/ # 系统表
│ └── ...其他系统目录
├── pg_tps/ # 表空间 mydemotbs 的实际存储位置
│ └── PG_15_202209061/
│ ├── 16388/ # 某个数据库的数据
│ └── 24847/ # db_666 的数据
└── archive/ # WAL 归档
一、前提:
pg_basebackup -h 192.168.x.x -U rep -D /var/lib/pgsql/15/data -Fp -Xs -P -R
- 执行以上命令从主库拉取数据,搭建主从复制总是失败。
从库日志报错:
2026-07-07 20:00:46 CST [13082]: user=,db=,app=,client=LOG: database system was interrupted; last known up at 2026-07-07 19:53:31 CST
cp: cannot stat '/var/lib/pgsql/15/archive/00000011.history': No such file or directory
2026-07-07 20:00:46 CST [13082]: user=,db=,app=,client=FATAL: recovery target timeline 17 does not exist
二、根据日志报错先排查修复主库报错
主库日志报错:
2026-07-07 17:38:57 CST [17670]: user=,db=,app=,client=DETAIL: The database subdirectory "pg_tblspc/24610/PG_15_202209061/24847" is missing.
排查过程:
- 现象:表空间文件 /var/lib/pgsql/15/pg_tps 和 /var/lib/pgsql/15//var/lib/pgsql/15/ 之间缺少软链接,且各个表空间文件下都有重复数据,后续会导致严重问题。
1、停止主库
systemctl stop postgresql-15
2、删除各表空间目录下多余文件和目录,只保留数据最全的表空间文件
3、根据日志报错,进入数据目录创建软链接:
cd /var/lib/pgsql/15/data
ln -s /var/lib/pgsql/15/pg_tps pg_tblspc/24610
# 软链接结果:
$ ll data/pg_tblspc
lrwxrwxrwx 1 postgres postgres 24 Jul 7 19:39 24610 -> /var/lib/pgsql/15/pg_tps
4、重启主库验证:
systemctl start postgresql-15
# 查看日志
tail -50 /var/lib/pgsql/15/data/log/*.log
# 验证 db_666
psql -U postgres -c "\c db_666"
psql -U postgres -c "SELECT count(*) FROM pg_tables WHERE schemaname = 'public'
三、修复从库:
1、从库同目录创建表空间文件
mkdir -p /var/lib/pgsql/15/pg_tps
2、清理从库旧数据
rm -rf /var/lib/pgsql/15/data/*
rm -rf /var/lib/pgsql/15/archive/*
3、从主库拉取数据
pg_basebackup -h 192.168.x.x -U rep -D /var/lib/pgsql/15/data -Fp -Xs -P -R
4、修改postgresql.conf
# 设置为空:
restore_command = ''
5、重启从库报错:
systemctl start postgresql-15.service
从库日志报错:
2026-07-07 20:00:46 CST [13082]: user=,db=,app=,client=LOG: database system was interrupted; last known up at 2026-07-07 19:53:31 CST
cp: cannot stat '/var/lib/pgsql/15/archive/00000011.history': No such file or directory
2026-07-07 20:00:46 CST [13082]: user=,db=,app=,client=FATAL: recovery target timeline 17 does not exist
6、排查过程
1. 查看主库当前的 timeline
# 在从库执行
# 1. 查看 postgresql.auto.conf 内容
[postgres@pg05 data]$ cat postgresql.auto.conf
l# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
checkpoint_completion_target = '0.9'
primary_conninfo = 'user=rep password=123456 channel_binding=prefer host=192.168.6.9 port=5432 sslmode=prefer sslcompression=0 sslsni=1 ssl_min_protocol_version=TLSv1.2 gssencmode=prefer krbsrvname=postgres target_session_attrs=any'
# 2. .conf 里是否有 restore_command
grep "restore_command" postgresql.conf
grep "recovery_target_timeline" postgresql.conf
# 3. 查看 standby.signal 是否存在
[postgres@pg05 data]$ ls -la standby.signal
-rw-r----- 1 postgres postgres 0 Jul 7 19:54 standby.signal
# 4. 查看 recovery.signal(PG12+ 如果有的话)
[postgres@pg05 data]$ ls -la recovery.signal
ls: cannot access recovery.signal: No such file or directory
# 5. 检查 postgresql.conf 里是否有 restore_command
[postgres@pg05 data]$ grep "restore_command" postgresql.conf
restore_command = '' # command to use to restore an archived logfile segment
[postgres@pg05 data]$ grep "recovery_target_timeline" postgresql.conf
#recovery_target_timeline = 'latest' # 'current', 'latest', or timeline ID
# 1. 查找所有包含 restore_command 的配置文件
[postgres@pg05 data]$ grep -r "restore_command" /var/lib/pgsql/15/data/ 2>/dev/null
postgresql.conf 中 restore_command 的实际生效值
psql -U postgres -c "SHOW restore_command;" 2>/dev/null || echo "无法连接"
/var/lib/pgsql/15/data/pg_rman_recovery.conf:restore_command = 'cp /var/lib/pgsql/15/archive/%f %p'
/var/lib/pgsql/15/data/postgresql.conf-bak20260706:
#restore_command = '' # command to use to restore an archived logfile segment
/var/lib/pgsql/15/data/postgresql.conf-bak20251025:
#restore_command = '' # command to use to restore an archived logfile segment
/var/lib/pgsql/15/data/postgresql.conf:
restore_command = '' # command to use to restore an archived logfile segment
# 2. 检查是否使用了 include 指令引入了外部配置
[postgres@pg05 data]$ grep "^include" postgresql.conf
include = 'pg_rman_recovery.conf' # added by pg_rman 1.3.15
# 3. 查看 postgresql.conf 中 restore_command 的实际生效值
[postgres@pg05 data]$ psql -U postgres -c "SHOW restore_command;" 2>/dev/null || echo "无法连接"
结果:无法连接
根本原因:
# postgresql.conf 里有一行:
include = 'pg_rman_recovery.conf' # added by pg_rman 1.3.15
# 而这个 pg_rman_recovery.conf 文件里设置了:
restore_command = 'cp /var/lib/pgsql/15/archive/%f %p'
这就是问题所在! 虽然你在 postgresql.conf 里设置了 restore_command = '',但 include 指令在后面引用了 pg_rman_recovery.conf,覆盖了你前面的设置。
# PostgreSQL 的配置加载顺序是:
postgresql.conf → include 的文件 → postgresql.auto.conf。所以 pg_rman_recovery.conf 里的 restore_command 最终生效了。
7、修复步骤:
cd /var/lib/pgsql/15/data
# 备份 postgresql.conf
cp postgresql.conf postgresql.conf.bak
# 注释掉 include 行
sed -i 's/^include/#include/g' postgresql.conf
# 或者直接编辑
vi postgresql.conf
# 找到下面这行,在前面加 # 注释掉
# include = 'pg_rman_recovery.conf' # added by pg_rman 1.3.15
# 重命名或删除 pg_rman_recovery.conf(可选)
## 重命名,让 PostgreSQL 找不到它
mv pg_rman_recovery.conf pg_rman_recovery.conf.disabled
# 重置 postgresql.auto.conf
cat > postgresql.auto.conf << 'EOF'
primary_conninfo = 'user=rep password=123456 host=192.168.6.9 port=5432 sslmode=prefer'
recovery_target_timeline = 'latest'
EOF
# 删除所有 .history 文件
cd /var/lib/pgsql/15/data
find . -name "*.history" -type f -delete
rm -f pg_wal/*.history
# 清空 archive 目录
rm -rf /var/lib/pgsql/15/archive/*
# 启动从库
systemctl start postgresql-15
# 查看日志,验证修复是否成功
tail -100 /var/lib/pgsql/15/data/log/*.log
# 启动成功后,应该看到类似这样的日志:
LOG: database system was shut down at ...
LOG: entering standby mode
LOG: started streaming WAL from primary at ...
LOG: consistent recovery state reached at ...
补充:关于 pg_rman
pg_rman 是一个 PostgreSQL 备份工具,它生成的 pg_rman_recovery.conf 文件通常用于从归档恢复。但在流复制从库场景下,不需要这个配置,因为从库通过流复制直接从主库接收 WAL。
如果以后要用 pg_rman 做备份恢复,记得恢复完成后要把 include 行重新打开。
8、验证主从复制:
1. 检查从库:
# 查看从库日志
tail -50 /var/lib/pgsql/15/data/log/*.log
# 检查是否处于恢复模式
psql -U postgres -c "SELECT pg_is_in_recovery();"
# 应返回 t
# 查看流复制状态
psql -U postgres -c "SELECT * FROM pg_stat_wal_receiver;"
# 在主库查看复制连接
psql -U postgres -c "SELECT application_name, state, sync_state, write_lag FROM pg_stat_replication;"
2. 主库最终确认
# 主库健康检查
psql -U postgres -c "\l" | grep db_666
psql -U postgres -c "SELECT version();"
SELECT application_name, client_addr, state, sync_state FROM pg_stat_replication;
application_name | client_addr | state | sync_state
------------------+--------------+-----------+------------
walreceiver | 192.168.x.x | streaming | async
# 检查磁盘使用情况,确保没有不必要的副本
du -sh /var/lib/pgsql/15/data/pg_tblspc/24610/
du -sh /var/lib/pgsql/15/pg_tps/
du -sh /var/lib/pgsql/15/data/pg_tps/ 2>/dev/null # 如果存在可以删除