PostgreSQL 数据库开源版本的使用中在归档中容易出现问题,这也是最近有同学在询问并且产生问题的地方,实际上他已经问了我3个礼拜了,各种各样的问题,本篇将针对这个问题进行梳理,方便同学在安装和设置PostgreSQL的工作中遇到问题进行问题对的排查,所以千万别拿PostgreSQL当MySQL,他比那个MySQL要难得多,关联性问题比较多,顾此失彼想问题的不少。
首先我们先用一个 PostgreSQL 归档中的问题与配置注意点 的思维导图输出,以文本和层级结构的形式展现:
PostgreSQL WAL 归档:问题与配置要点
├── 1. 归档中的常见问题
│ ├── 1.1 WAL 文件堆积 (磁盘空间耗尽)
│ │ ├── 原因
│ │ │ ├── archive_command 执行失败/过慢
│ │ │ ├── 目标存储空间不足
│ │ │ ├── 权限问题
│ │ │ ├── 复制槽 (Replication Slots) 未清理/卡顿
│ │ │ └── wal_keep_size 设置过高
│ ├── 1.2 归档数据丢失/不完整
│ │ ├── 原因
│ │ │ ├── archive_command 未正确返回成功状态
│ │ │ ├── 网络/存储设备故障
│ │ │ ├── 归档脚本逻辑错误
│ │ │ └── 缺乏基础备份 (无法单独恢复)
│ ├── 1.3 恢复过程复杂/失败
│ │ ├── 原因
│ │ │ ├── 基础备份与 WAL 归档不匹配
│ │ │ ├── restore_command 配置错误
│ │ │ ├── WAL 文件损坏/缺失
│ │ │ ├── 归档文件压缩/解压问题
│ │ │ └── 归档目录结构混乱
│ └── 1.4 性能开销
│ ├── 原因
│ │ └── archive_command 消耗资源过多 (CPU/I/O)
│
├── 2. 归档配置的注意点 (postgresql.conf & 脚本)
│ ├── 2.1 postgresql.conf 参数
│ │ ├── wal_level
│ │ │ ├── 必须: replica/archive (旧版本), logical
│ │ │ └── 勿设: minimal
│ │ ├── archive_mode
│ │ │ └── 必须: on
│ │ ├── archive_command
│ │ │ ├── 核心:shell 命令,处理 %p (路径) & %f (文件名)
│ │ │ ├── 关键点
│ │ │ │ ├── 幂等性 (处理重复调用)
│ │ │ │ ├── 原子性 (先临时复制,后原子重命名)
│ │ │ │ ├── 成功退出码 (必须返回 0)
│ │ │ │ ├── 错误处理与日志记录
│ │ │ │ └── 权限 (Pg 用户对目标目录有写权限)
│ │ │ ├── 常用功能
│ │ │ │ ├── 压缩 (gzip)
│ │ │ │ └── 远程传输 (scp, rsync, S3 tools)
│ │ │ └── 容易出错
│ │ │ ├── 命令语法错误
│ │ │ ├── 硬编码路径
│ │ │ ├── 缺乏错误处理
│ │ │ └── 权限不足
│ │ ├── archive_timeout
│ │ │ ├── 作用:强制切换 WAL 段并归档 (即使未满)
│ │ │ └── 建议:低事务量时可设较小值 (如 60s, 300s)
│ │ └── wal_keep_size (或 wal_keep_segments)
│ │ ├── 作用:保留 WAL 文件供备库使用
│ │ ├── 建议:使用复制槽时可设为 0 (或很小)
│ │ └── 注意:过大导致本地磁盘空间浪费
│ ├── 2.2 基础备份 (Base Backup)
│ │ ├── 作用:PITR 的起点
│ │ ├── 工具:pg_basebackup
│ │ └── 最佳实践:定期全量备份,确保与 WAL 归档匹配
│ └── 2.3 恢复命令 (restore_command)
│ ├── 作用:在恢复时获取 WAL 文件
│ ├── 关键点:与 archive_command 对应 (路径,压缩/解压)
│ └── 容易出错:路径不匹配,权限问题,文件缺失/损坏
│
└── 3. 容易出现问题的地方与管理建议
├── 3.1 磁盘空间管理
│ ├── 监控:主库 pg_wal 目录
│ └── 监控:归档目标存储空间
├── 3.2 权限问题
│ └── 确保 Pg 用户对归档相关目录/文件有读写权限
├── 3.3 archive_command 脚本的健壮性
│ ├── 测试:充分测试各种场景 (成功,失败,重复)
│ ├── 日志:内部记录详细日志
│ └── 错误处理:正确返回退出码
├── 3.4 复制槽 (Replication Slots) 的使用与管理
│ ├── 优势:确保 WAL 不被删除
│ ├── 风险:备库卡顿导致 WAL 无限增长
│ ├── 管理:
│ │ ├── 监控 pg_replication_slots 视图
│ │ ├── 设置 max_slot_wal_keep_size 上限
│ │ └── 及时清理不再使用的复制槽
├── 3.5 灾难恢复演练
│ ├── 重要性:定期演练 (季度/半年)
│ └── 自动化:尽可能自动化恢复流程
└── 3.6 监控和告警
├── 监控:pg_stat_archiver (归档成功/失败计数)
├── 监控:磁盘空间 (pg_wal, 归档目录)
└── 监控:复制延迟 (结合流复制)
这里我们列出了在工作中容易产生问题的部分的列表,并且针对最近同学私信我的实际问题进行问题的描述和解决方案的给出。
咨询中第一个问题:
我是否可以将pg_waL的数据的日志目录,放到更廉价的磁盘系统中,主要产生这样想法的原因在于,pg_wal在使用中会产生大量的文件,而系统中做了主从且从库还要进行报表的给出,且还设置了从库强一致的设置,这里主库的日志有大量堆积的情况出现。
答:我们非常不建议将pg_wal放入目录单独放入到比较差的磁盘系统,这主要与pg_wal对于postgresql系统运行的性能起到了至关重要作用有关。
数据库事务的commit的效率与系统运行的性能有着直接的关系,事务的commit是需要等待事物日志落盘后才能进行事务的commit,如果将日志放到较差的磁盘系统中将直接影响整体数据苦的稳定运行。
而产生一些运维同学想把日志放到廉价磁盘的根本原因就是PostgreSQL FPW full page write ,在每次checkpoint后会将数据的首页面的数据页面写入到日志,保证数据库系统CRASH后的数据库页面出现问题后的恢复,越是繁忙的系统FPW产生的数据页面就越大PG_WAL就越大,硬盘的性能需求就越大。
所以同学问是否可以将PG_WAL,放入到廉价的系统,回答是不可以。
第二个问题,pg_wal能否进行压缩,这里建议如果想在核心系统上使用PostgreSQL建议考虑硬件压缩你的日志。从磁盘本身来进行数据的压缩。
Btrfs:支持在挂载时启用透明压缩。
ZFS:也提供透明压缩选项。
第三个问题,WAL的归档为什么拷贝到了归档的目录,PG_WAL的文件数还是没有下来,PG_WAL的文件夹的文件数还是那么的多。
这里我们需要注意我们的./pg_wal/archive_status/ 文件夹下的目录里面的文件是会显示每个文件的归档状态的结尾是.done 是归档完毕的,而.ready的意思是这个问题已经做好了要归档的准备。
真正的第三个问题,也就是那个同学一直在3个礼拜一直归档失败,PG_WAL被沾满影响数据库系统运行的核心就是,逻辑复制槽。
这里这个同学的公司有大数据部门,大数据会通过逻辑复制槽来消费数据,而大数据是不会管你数据库的死活,他们有如下的可能我们也是遇到的。
1 大数据更换逻辑复制槽来进行数据的同步,但原理的复制槽不使用并不会通知DBA,这就导致PG_WAL 一直下不去的根本原因。
2 大数据消费PG_WAL非常慢,导致他们消费不了PG_WAL而逻辑复制槽又必须等着他们消费完才能删除PG_WAL
3 网络的问题,或者大数据的磁盘满了,不消费了等等各种各样的问题。
所以如果你发现你的系统开了逻辑复制槽,就必须监控。
下面我们给大家一个关于逻辑复制槽的周边。
-- 1. 查看所有逻辑复制槽(slot_type = 'logical')
SELECT *
FROM pg_replication_slots
WHERE slot_type = 'logical';
-- 2. 判断复制槽是否存在(替换 'your_slot_name')
SELECT EXISTS (
SELECT 1
FROM pg_replication_slots
WHERE slot_type = 'logical' AND slot_name = 'your_slot_name'
) AS slot_exists;
-- 3. 查看逻辑复制槽是否活跃(active 表示是否被订阅端占用)
SELECT
slot_name,
active
FROM pg_replication_slots
WHERE slot_type = 'logical';
-- 4. 检查逻辑槽延迟(WAL 堆积字节数),判断是否可能失效或卡住
SELECT
slot_name,
active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS wal_delay,
pg_current_wal_lsn() AS current_lsn,
confirmed_flush_lsn
FROM pg_replication_slots
WHERE slot_type = 'logical';
-- 5. 查看逻辑订阅延迟(订阅端使用,查询 pg_stat_subscription)
SELECT
subscription_name,
received_lsn,
latest_end_lsn,
latest_end_time,
now() AS now,
EXTRACT(EPOCH FROM now() - latest_end_time)::int AS delay_seconds
FROM pg_stat_subscription;
-- 6. 查看 replication 连接状态(发布端,用于逻辑复制进程的状态)
SELECT
pid,
application_name,
state,
client_addr,
sync_state,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), flush_lsn)) AS flush_lag,
pg_size_pretty(pg_wal_lsn_diff(pg_current_w_
另外,这个同学后面又遇到了,系统重启后,从库连不上了问题,从库报找不到pg_wal的问题。
requested WAL segment has already been removed
could not receive data from WAL stream
这里我给你的的建议是设置如下参数会解决这个问题
# postgresql.conf 主库设置
wal_keep_size = '1GB' (具体设置多少根据你的情况而定,这个保留可以归档但不归档还放到pg_wal目录下的日志文件的大小)
写到这里,我认为基本上对于这个同学在这三个礼拜问的问题,我已经梳理了他遇到的大部分和未来可能会遇到的问题,以及解决方案,希望能对他有帮助。
本文分享自 AustinDatabases 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!