pg_dump 和 pg_dumpall

在 PostgreSQL 中,pg_dump 和 pg_dumpall 是两个常用的备份工具,分别用于逻辑备份单个数据库和整个数据库集群。

检查pg_dumppg_dumpall命令是否可用

su - postgres
pg_dump --version
pg_dumpall --version

在这里插入图片描述


使用 pg_dump 备份单个数据库

pg_dump -U <用户名> -h <主机名> -p <端口号> -F <格式> -f <输出文件路径> <数据库名>

参数:

  • -U:指定数据库用户名。
  • -h:指定数据库主机地址(默认 localhost)。
  • -p:指定数据库端口(默认 5432)。
  • -F:指定备份格式:
    • plain(默认):生成 SQL 脚本文件。
    • c:自定义格式(支持压缩,需用 pg_restore 恢复)。
    • d:目录格式(支持并行备份)。
    • t:tar 格式。
  • -f:指定输出文件路径。
  • --schema-only:仅备份表结构(不包含数据)。
  • --data-only:仅备份数据(不包含表结构)。
  • -t <表名>:备份特定表。
  • -j <并行任务数>:并行备份(适用于大数据库)。
示例
  1. 备份单个数据库为 SQL 文件:

    pg_dump -U postgres -h localhost -p 5432 -F p -f /path/to/backup.sql mydb
    
    • -F p 表示输出为普通 SQL 文件。
    • mydb 是要备份的数据库名。
  2. 备份单个数据库为自定义格式(支持压缩):

    pg_dump -U postgres -h localhost -p 5432 -F c -f /path/to/backup.custom mydb
    
    • -F c 表示输出为自定义格式(需用 pg_restore 恢复)。
  3. 备份特定表:

    pg_dump -U postgres -h localhost -p 5432 -F p -t users -f /path/to/users_backup.sql mydb
    
    • -t users 表示仅备份 users 表。
  4. 仅备份表结构:

    pg_dump -U postgres -h localhost -p 5432 --schema-only -f /path/to/schema.sql mydb
    
  5. 仅备份数据(不包含表结构):

    pg_dump -U postgres -h localhost -p 5432 --data-only -f /path/to/data.sql mydb
    

使用 pg_dumpall 备份整个数据库集群

基本用法

pg_dumpall 用于备份整个 PostgreSQL 集群,包括所有数据库、角色(用户)、表空间等全局对象。

命令格式:

pg_dumpall -U <用户名> -h <主机名> -p <端口号> -f <输出文件路径> [选项]

参数:

  • -g:仅备份全局对象(角色、表空间等)。
  • -c:在备份中包含删除数据库的命令(用于恢复时清理旧数据)。
  • -v:启用详细模式(显示备份过程)。

示例

  1. 备份整个集群:

    pg_dumpall -U postgres -h localhost -p 5432 -f /path/to/cluster_backup.sql
    
    • 生成的 SQL 文件包含所有数据库、角色和表空间。
  2. 仅备份全局对象(角色、表空间):

    pg_dumpall -U postgres -h localhost -p 5432 -g -f /path/to/globals.sql
    
  3. 备份整个集群并包含清理命令:

    pg_dumpall -U postgres -h localhost -p 5432 -c -f /path/to/cluster_backup.sql
    
pg_dumpall 备份问题

涉及到多个库需要重复输入密码,容易输入错误,可以配置 .pgpass 文件的方式解决重复输入问题

vi ~/.pgpass
192.168.24.11:5432:*:postgres:你的真实密码

chmod 600 ~/.pgpass

# 继续执行备份

恢复备份

恢复 pg_dump 备份
  • SQL 文件恢复:

    psql -U <用户名> -h <主机名> -d <目标数据库> -f <备份文件路径>
    

    示例:

    psql -U postgres -h localhost -d mydb -f /path/to/backup.sql
    
  • 自定义格式恢复:

    pg_restore -U <用户名> -h <主机名> -d <目标数据库> <备份文件路径>
    

    示例:

    pg_restore -U postgres -h localhost -d mydb /path/to/backup.custom
    
恢复 pg_dumpall 备份
  • 恢复整个集群备份:

    psql -U postgres -h localhost -d postgres -f /path/to/cluster_backup.sql
    
    • 需以 postgres 用户连接到默认数据库(如 postgres),因为恢复过程中会创建其他数据库。
  • 恢复全局对象备份:

    psql -U postgres -h localhost -d postgres -f /path/to/globals.sql
    


💾 WAL归档与恢复教程

📄 WAL归档

分为2步走,先制作基础备份,然后在基础备份的基础上使用wal归档,进行增量备份,先给pgsql文件归档和备份的写入权限,否则pgsql会写入失败

# 创建归档目录
mkdir -p /data/waldata/

# 设置PostgreSQL用户权限(关键!否则无法写入)
chown -R postgres:postgres /data/waldata/
chmod 700 /data/waldata/

# 验证权限
ls -ld /data/waldata/

1.制作基础备份(pg_basebackup)

重要:没有基础备份,仅靠 WAL 归档无法恢复数据库。基础备份是恢复的起点,建议每天或每周制作一次。

📖 基础备份制作命令
# 切换到postgres用户
su - postgres

# 创建基础备份目录
mkdir -p /data/backups/base/

# 制作基础备份(推荐参数)
pg_basebackup \
  -D /data/backups/base/backup_$(date +%Y%m%d_%H%M%S) \
  -Ft -z -P -v \
  -X stream \
  -c fast

参数说明

  • -D:备份输出目录
  • -Ft:输出为tar格式
  • -z:使用gzip压缩备份文件
  • -P:显示备份进度
  • -v:详细输出
  • -X stream:流式传输备份过程中产生的WAL文件,确保备份一致性
  • -c fast:快速执行检查点,减少备份时间

🛠️ 自动化备份脚本
#!/bin/bash
# ========== 配置变量 ==========
BACKUP_BASE_DIR="/data/postgresql/wal-basic-backup"
RETENTION_DAYS=7
LOG_FILE="/var/log/pg_base_backup.log"

# ========== 准备工作 ==========
mkdir -p "${BACKUP_BASE_DIR}" "$(dirname "${LOG_FILE}")"
if [ $? -ne 0 ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 无法创建备份或日志目录,退出" | tee -a "${LOG_FILE}" >&2
    exit 1
fi

# 生成带时间戳的备份目录名
BACKUP_NAME="backup_$(date +%Y%m%d_%H%M%S)"
BACKUP_DIR="${BACKUP_BASE_DIR}/${BACKUP_NAME}"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "${LOG_FILE}"
}

# ========== 执行备份 ==========
log "开始制作基础备份: ${BACKUP_NAME}"

pg_basebackup \
  -D "${BACKUP_DIR}" \
  -Ft -z -P -v \
  -X stream \
  -c fast >> "${LOG_FILE}" 2>&1

if [ $? -eq 0 ]; then
    log "基础备份成功完成"

    # ========== 历史备份清理(基于目录名日期,比 find -mtime 更可靠) ==========
    log "开始清理 ${RETENTION_DAYS} 天前的旧备份(基于目录名日期)"
    cd "${BACKUP_BASE_DIR}" || exit 1

    # 计算截止日期(格式与备份目录一致:YYYYMMDD)
    cutoff_date=$(date -d "-${RETENTION_DAYS} days" +%Y%m%d)
    log "截止日期:${cutoff_date}"

    for dir in backup_*; do
        [ -d "$dir" ] || continue

        # 提取目录名中的日期部分(YYYYMMDD)
        # 目录名格式:backup_YYYYMMDD_HHMMSS
        dir_date=${dir#backup_}          # 去掉前缀
        dir_date=${dir_date%%_*}         # 只取第一个_前的部分,即YYYYMMDD

        # 格式校验:必须为8位数字
        if [[ ! ${dir_date} =~ ^[0-9]{8}$ ]]; then
            log "警告:目录名格式异常,跳过 ${dir}"
            continue
        fi

        # 字符串直接比较(YYYYMMDD 可直接比大小)
        if [[ "${dir_date}" < "${cutoff_date}" ]]; then
            log "删除过期备份目录:${dir}"
            rm -rf "${dir}"
        fi
    done
else
    log "基础备份失败!"
    exit 1
fi

log "备份任务结束"
echo "----------------------------------------" >> "${LOG_FILE}"

2.开启WAL归档并配置自动压缩

1)备份原始配置文件
# 切换到PostgreSQL配置目录(默认路径)
cd /var/lib/pgsql/14/data/

# 备份原始配置
cp postgresql.conf postgresql.conf.bak.$(date +%Y%m%d)
cp pg_hba.conf pg_hba.conf.bak.$(date +%Y%m%d)
2)修改postgresql.conf核心参数

编辑/var/lib/pgsql/14/data/postgresql.conf,找到并修改以下参数:

# 开启WAL归档(生产环境必须设为replica或更高)
wal_level = replica

# 开启归档模式
archive_mode = on

# 归档命令(自动压缩,使用gzip,保留原始文件名)
archive_command = 'gzip -c %p > /data/waldata/%f.gz && test -f /data/waldata/%f.gz'

# 归档超时(防止WAL文件长时间不切换,生产建议10-30分钟)
archive_timeout = 10min

# 以下为生产环境优化参数(可选但推荐)
max_wal_size = 16GB  # 根据磁盘空间调整,建议为磁盘的10%-20%
min_wal_size = 4GB
wal_keep_size = 4GB  # 保留的WAL文件大小,用于流复制和本地恢复
wal_compression = on  # 开启WAL页级压缩,减少磁盘IO

参数说明

  • %p:PostgreSQL替换为WAL文件的完整路径
  • %f:PostgreSQL替换为WAL文件的文件名
  • test -f:确保压缩文件成功创建后才返回成功,否则PostgreSQL会重试归档
3)重启PostgreSQL服务使配置生效
systemctl restart postgresql-14

# 验证服务状态
systemctl status postgresql-14
4)验证归档是否正常工作
# 切换到postgres用户
su - postgres

# 手动切换WAL文件,触发归档
psql -c "SELECT pg_switch_wal();"

# 检查归档目录是否有压缩后的WAL文件
ls -l /data/waldata/

如果看到类似000000010000000000000001.gz的文件,说明归档配置成功。

🛠️ 自动化备份脚本
#!/bin/bash
# ========== 配置变量 ==========
ARCHIVE_DIR="/data/postgresql/wal-archive-path"
RETENTION_DAYS=7
LOG_FILE="/var/log/pg_wal_clean.log"

# ========== 日志函数 ==========
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}

# ========== 前置检查 ==========
if [ ! -d "$ARCHIVE_DIR" ]; then
    log "错误:归档目录 ${ARCHIVE_DIR} 不存在,退出。"
    exit 1
fi

# 确保日志目录存在
mkdir -p "$(dirname "$LOG_FILE")"

# ========== 清理旧 WAL ==========
log "开始清理 ${RETENTION_DAYS} 天前的WAL归档文件"

# 查找并删除超过 N 天的 .gz 归档文件
deleted_count=$(find "$ARCHIVE_DIR" -type f -name "*.gz" -mtime +${RETENTION_DAYS} -print -delete | wc -l)

log "清理完成,共删除 ${deleted_count} 个过期WAL文件"

echo "----------------------------------------" >> "$LOG_FILE"

📄 WAL恢复

恢复前准备

  1. 确保PostgreSQL服务已停止
  2. 备份当前损坏的数据目录
  3. 准备好最新的基础备份和对应的WAL归档文件

1.停止PostgreSQL服务

systemctl stop postgresql-14

2.备份当前数据目录(防止恢复失败)

# 重命名当前数据目录
mv /var/lib/pgsql/14/data /var/lib/pgsql/14/data.corrupted.$(date +%Y%m%d)

3.解压基础备份

# 创建新的数据目录
mkdir -p /var/lib/pgsql/14/data

# 找到最新的基础备份目录
LATEST_BACKUP=$(ls -td /data/backups/base/backup_* | head -1)
echo "使用最新备份: $LATEST_BACKUP"

# 解压备份文件到新的数据目录
cd $LATEST_BACKUP
for file in *.tar.gz; do
  tar -xzf $file -C /var/lib/pgsql/14/data/
done

# 设置正确的权限
chown -R postgres:postgres /var/lib/pgsql/14/data
chmod 700 /var/lib/pgsql/14/data

4.创建恢复配置文件

在新的数据目录下创建recovery.signal文件(PostgreSQL 12+可以使用此文件触发恢复):

touch /var/lib/pgsql/14/data/recovery.signal
chown postgres:postgres /var/lib/pgsql/14/data/recovery.signal

编辑/var/lib/pgsql/14/data/postgresql.conf,添加恢复相关参数:

# 恢复命令(解压归档WAL文件供PostgreSQL使用)
restore_command = 'gunzip -c /data/waldata/%f.gz > %p'

# 恢复到最新时间点(默认)
# recovery_target = 'latest'

# 可选:恢复到指定时间点
# recovery_target_time = '2024-05-20 10:30:00'

# 可选:恢复到指定事务ID
# recovery_target_xid = '12345'

# 恢复完成后自动提升为主库
recovery_target_action = 'promote'

5.启动PostgreSQL服务开始恢复

systemctl start postgresql-14

6.监控恢复过程

# 查看PostgreSQL日志
tail -f /var/lib/pgsql/14/data/log/postgresql-*.log

恢复过程中会看到类似以下日志:

LOG:  starting archive recovery
LOG:  restore_command = 'gunzip -c /data/waldata/%f.gz > %p'
LOG:  restored log file "000000010000000000000002.gz" from archive
LOG:  restored log file "000000010000000000000003.gz" from archive
...
LOG:  redo done at 0/40000D8
LOG:  last completed transaction was at log time 2024-05-20 14:25:30.123456+08
LOG:  restored log file "000000010000000000000004.gz" from archive
LOG:  selected new timeline ID: 2
LOG:  archive recovery complete
LOG:  database system is ready to accept connections

7.验证恢复结果

docker exec -it postgres psql -U postgres
# 验证
\l                                       -- 列出所有数据库
\c 业务库名                                -- 切到业务库
\dt                                      -- 查表
SELECT count(*) FROM 某张表;               -- 抽查数据量
SELECT now();              -- 查看当前数据库时间
SELECT pg_is_in_recovery();              -- - 返回 true(恢复模式)
SELECT pg_last_xact_replay_timestamp();  -- 显示恢复时间
# 提升为主库
docker exec -it postgres psql -U postgres -c "SELECT pg_wal_replay_resume();"

# 应返回 f(不再处于恢复模式)
docker exec -it postgres psql -U postgres -c "SELECT pg_is_in_recovery();"


Tips

  1. 权限要求:
    • pg_dump 需要对目标数据库有读取权限。
    • pg_dumpall 需要超级用户权限(以备份角色和表空间)。
  2. 备份格式选择:
    • 如果需要灵活的恢复选项(如选择性恢复表),建议使用自定义格式(-F c)。
    • 如果需要快速恢复,SQL 文件可能更直接。
  3. 并行备份:
    • 对大型数据库,使用 -j <并行任务数> 可加速备份(需 PostgreSQL 12+)。

删除数据库报错 ERROR: database “xxx_prod” is being accessed by other usersDETAlL: There are 33 other sessions using the database.

踢掉所有连接的服务,然后在删除数据库

-- 步骤 1: 阻止新连接到目标数据库
ALTER DATABASE "xxx_prod" ALLOW_CONNECTIONS false;

-- 步骤 2: 终止所有现有连接
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'xxx_prod';

-- 步骤 3: 删除数据库
DROP DATABASE "xxx_prod";
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐