Skip to content

postgresql 大型数据库 / 生产环境:使用 pg_basebackup(全量物理备份)+ WAL 归档(增量 / PITR),保证备份效率和灾备能力。 #24

@ipme

Description

@ipme

这个肯定不能 多讲了吧!
pg_probackup:PostgreSQL 官方推荐的备份工具,支持增量备份、压缩、校验、时间点恢复。

1. pg_basebackup(全量物理备份)

pg_basebackup 基于 PostgreSQL 的流复制机制,生成数据库集群的完整物理副本,支持热备份(不中断业务)。

前置条件(必须配置):

修改postgresql.confpg_hba.conf,开启流复制:

# 1. 编辑postgresql.conf        ###     /data/pgsql-18/postgresql.conf {看你安装的pgsql 什么版本,对应版本号,这里演示是pgsql-18}
sudo vim postgresql.conf
# 添加/修改以下配置
wal_level = replica       # 开启WAL日志的复制级别
max_wal_senders = 10       # 允许的流复制连接数
wal_keep_size = 128MB      # 保留的WAL日志大小(按需调整)
listen_addresses = '*'    # 允许远程连接(若备份在远程执行)

2. 编辑pg_hba.conf,#允许备份用户的流复制连接

PS:本地主机,就不用管这个配置文件了

sudo vim pg_hba.conf

# 添加流复制授权规则(根据实际场景选择)

# 场景1:本地备份(备份机和数据库在同一台服务器)
local   replication     postgres                                peer 

# 场景2:远程备份(指定备份机IP,比如备份机IP是192.168.1.100)
host    replication     postgres        192.168.1.100/32        md5

# 说明:
# replication:表示流复制连接(pg_basebackup用此类型)
# postgres:备份使用的用户(建议用超级用户,如postgres)
# 192.168.1.100/32:允许的备份机IP段(/32表示单个IP)
# md5:认证方式(本地可使用peer,远程建议md5)

# 3. 重启PostgreSQL服务
bypanel restart postgresql 

测试一下 直接在宿主机 运行命令

docker exec -u postgres bypanel-postgresql-1 \
  pg_basebackup -U postgres -D /shared/backups/pgsql_18/pg_base_20260109 -F p -X s -P -c fast

正常成功显示

waiting for checkpoint
32472/32472 kB (100%), 0/1 tablespace
32472/32472 kB (100%), 1/1 tablespace
pg_basebackup: base backup completed

验证备份结果(宿主机端)

# 查看新备份文件夹
ls -l /data/backups/pgsql_18/

# 预期输出(会看到pg_base_20260109,所有者为999:999/999:systemd-journal):
total 8
drwx------ 19 999 systemd-journal 4096 Jan  8 01:44 pg_base_20260108
drwx------ 19 999 systemd-journal 4096 Jan  8 XX:XX pg_base_20260109

# 检查核心备份文件(确认完整性)
ls -l /data/backups/pgsql_18/pg_base_20260109/ | grep backup_label
# 能看到backup_label文件即代表备份完整:
-rw------- 1 999 systemd-journal   207 Jan  8 XX:XX backup_label

新建一个 备份脚本(解决目录非空问题+只保存15天数据,超期删除)

/data/scripts/pgsql_backup.sh 添加「备份前检查并删除当天备份目录」的逻辑,避免冲突:

#!/bin/bash
# PostgreSQL容器物理备份脚本(修复目录非空问题)
# 解决pg_basebackup要求目录为空的问题:先删除已存在的当天备份目录

# 添加系统环境变量(避免crontab找不到docker命令)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 核心配置
BACKUP_DIR="/data/backups/pgsql_18"          # 宿主机备份目录
CONTAINER_BACKUP_DIR="/shared/backups/pgsql_18"  # 容器内备份目录
CONTAINER_NAME="bypanel-postgresql-1"        # 容器名
BACKUP_NAME="pg_base_$(date +%Y%m%d)"        # 当天备份目录名

# 步骤1:删除容器内已存在的当天备份目录(避免非空报错)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 检查并删除已存在的备份目录: ${CONTAINER_BACKUP_DIR}/${BACKUP_NAME}"
docker exec -u postgres ${CONTAINER_NAME} rm -rf ${CONTAINER_BACKUP_DIR}/${BACKUP_NAME}

# 步骤2:执行物理备份(此时目录为空,不会报错)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 开始执行PostgreSQL物理备份..."
docker exec -u postgres ${CONTAINER_NAME} \
  pg_basebackup -U postgres -D ${CONTAINER_BACKUP_DIR}/${BACKUP_NAME} -F p -X s -P -c fast

# 步骤3:清理15天前的备份(仅删除pg_base_开头的目录)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 清理15天前的备份文件..."
find ${BACKUP_DIR} -name "pg_base_*" -type d -mtime +15 -exec rm -rf {} \;

# 步骤4:输出备份完成日志
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 备份+清理完成!当前保留的备份目录:"
ls -l ${BACKUP_DIR} | grep pg_base_

执行脚本

# 1. 确保脚本执行权限
chmod +x /data/scripts/pgsql_backup.sh

# 2. 手动执行脚本测试(验证无报错)
./data/scripts/pgsql_backup.sh

预期正常输出(无目录非空报错)

[2026-01-08 10:00:00] 检查并删除已存在的备份目录: /shared/backups/pgsql_18/pg_base_20260108
[2026-01-08 10:00:00] 开始执行PostgreSQL物理备份...
32472/32472 kB (100%), 1/1 tablespace
[2026-01-08 10:00:10] 清理15天前的备份文件...
[2026-01-08 10:00:10] 备份+清理完成!当前保留的备份目录:
drwx------ 19 70 70 4096 Jan  8 10:00 pg_base_20260108

配置 crontab 定时任务

crontab -e

每天凌晨2:00执行PostgreSQL备份+清理(保留15天)

0 2 * * * /data/scripts/pgsql_backup.sh >> /data/scripts/pgsql_backup.log 2>&1

日志排查:若仍有报错,查看脚本日志定位问题

tail -f /data/scripts/pgsql_backup.log

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions