PgBackRest备份原理详解

pgBackRest 是一个功能强大、可靠且易于使用的 PostgreSQL 备份和恢复工具。它的设计目标是处理大规模数据库和高并发负载。

一、pgBackRest 核心特性

pgBackRest 的备份原理结合了 PostgreSQL 自身的物理备份机制和 WAL (Write-Ahead Log) 归档,并在此基础上增加了许多优化和管理功能。

  • 并行处理 (Parallelism): 备份和恢复过程可以使用多个进程并行执行,大大缩短了大型数据库的操作时间。
  • 压缩 (Compression): 支持多种压缩算法(如 gzip, lz4, zstd)来减少备份文件的大小和网络传输量。
  • 校验和 (Checksums): 在备份、恢复和 WAL 归档的各个阶段都进行数据校验,确保数据完整性。默认情况下,即使 PostgreSQL 本身的 checksums 关闭,pgBackRest 也会进行校验。
  • 断点续传 (Resumable Backups): 如果备份过程中断(例如网络问题),可以从中断点继续,而不是重新开始。
  • 备份轮转和保留 (Retention): 可以配置策略自动删除过期的备份,以节省存储空间。支持基于数量或时间的保留策略。
  • 加密 (Encryption): 支持对备份仓库中的数据进行加密。
  • Delta Restore: 在恢复时,如果目标目录已存在部分未损坏的数据文件,pgBackRest 可以只恢复不同的或缺失的文件/块,加速恢复过程。

二、pgBackRest 备份前提条件

  • 所有机器: 都安装了pgBackRest

  • 数据库服务器: pg_server (运行 PostgreSQL)

  • 备份仓库服务器: repo_server (存储备份文件)

  • PostgreSQL 用户: postgres (拥有 $PGDATA 权限)

  • 备份仓库用户: pgbackrest (拥有备份仓库目录权限)

  • Stanza 名称: mystanza

  • pgBackRest 配置:

    • pg_serverpgbackrest.conf: 配置了 repo1-host=repo_server, repo1-host-user=pgbackrest, pg1-path=/path/to/pgdata 等。
    • repo_serverpgbackrest.conf: 配置了 pg1-host=pg_server, pg1-user=postgres, repo1-path=/path/to/repo 等。
  • SSH 免密登录: 已配置好 pgbackrest@repo_server 可以免密登录到 postgres@pg_server,并且 postgres@pg_server 可以免密登录到 pgbackrest@repo_server

  • 命令执行: 我们将在 repo_server 上以 pgbackrest 用户身份执行备份命令。

三、全量备份流程 (pgbackrest --stanza=mystanza --type=full backup)

  1. 启动命令 (在 repo_server):

    • repo_server 上以 pgbackrest 用户执行 pgbackrest --stanza=mystanza --type=full backup
    • pgBackRest 进程启动,读取 repo_server 上的 /etc/pgbackrest.conf (或指定配置文件)。
    • 解析命令行参数 (--stanza, --type) 和配置文件,确定 Stanza mystanza 的相关信息,包括数据库服务器地址 (pg1-host=pg_server)、用户 (pg1-user=postgres) 和仓库路径 (repo1-path=/path/to/repo)。
  2. 获取仓库锁 (在 repo_server):

    • pgBackRest 尝试在备份仓库中为 mystanza 创建并锁定一个文件(例如 /path/to/repo/backup/mystanza/backup.lock)。
    • 目的: 防止同一时间对同一个 Stanza 执行另一个备份或恢复操作,保证操作的原子性和一致性。如果锁定失败(文件已存在并被锁定),命令会报错退出。
  3. 连接数据库服务器 & 准备备份 (SSH 交互):

    • pgBackRest 在 repo_server 上的主进程需要与 pg_server 上的 PostgreSQL 实例交互以开始备份。

    • SSH 命令 (概念性): 它会执行类似如下的 SSH 命令来在 pg_server 上启动一个 pgBackRest remote 进程来处理数据库端的操作:

      Bash 复制代码
      ssh postgres@pg_server "pgbackrest --stanza=mystanza --log-level-file=<level> --command=backup --type=db --process=1 remote"

      (注意: 这只是概念性表示,实际命令和参数可能更复杂,pgBackRest 使用其内部协议进行通信)

    • pg_server 上的 remote 进程:

      • 这个远程进程启动,读取 pg_server 上的 pgbackrest.conf 以获取 pg1-path 等本地信息。
      • 连接到本地 PostgreSQL 实例 (使用 pg1-path 找到 socket 或通过 pg1-host/pg1-port 连接)。
      • 执行 pg_start_backup('pgBackRest backup start ...') SQL 命令(或使用流复制协议的等效命令)。
      • PostgreSQL 进入备份模式,创建一个 backup_label 文件在 $PGDATA 中,并返回备份的起始 LSN (Log Sequence Number)。
      • 如果 start-fast=n (默认为 y),会等待检查点完成。通常会快速继续。
      • remote 进程将起始 LSN 和 backup_label 内容等信息通过 SSH 连接返回给 repo_server 上的主进程。
  4. 传输数据文件 (并行的 SSH 交互):

    • repo_server 上的主进程了解到备份已在 pg_server 开始。

    • 它会确定需要复制的文件列表(对于 full 备份,是 $PGDATA 下的所有文件,除了 pg_wal 等排除项)。

    • 主进程会启动多个工作 (worker) 进程 (数量由 process-max 控制) 在 repo_server 上并行处理文件传输。

    • 每个 worker 进程 (在 repo_server) 会与 pg_server 建立 SSH 连接来获取文件数据:

      • SSH 命令 (概念性): 每个 worker 可能执行类似命令,请求特定的文件或文件块:

        Bash 复制代码
        ssh postgres@pg_server "pgbackrest --stanza=mystanza --command=backup --type=file --process=<worker_id> remote --file-path=/path/to/pgdata/base/12345/67890 --compress=<type> --checksum ..."

        (同样,这是概念表示。pgBackRest 可能使用更优化的流式传输协议通过 SSH 隧道)

      • pg_server 上的 remote 进程 (或由主 remote 进程协调的文件服务): 读取请求的文件,进行压缩(如果配置在源端压缩)、计算校验和,然后将数据流通过 SSH 连接发送回 repo_server 上的对应 worker 进程。

      • repo_server 上的 worker 进程: 接收数据流,进行解压(如果压缩在源端)、校验和验证,然后将文件写入备份仓库 (repo1-path) 中对应的目录结构下。

    • 这个过程会持续进行,直到所有需要备份的文件都被 worker 进程成功传输和验证。

  5. 结束数据库服务器上的备份 (SSH 交互):

    • 当所有 worker 进程在 repo_server 上完成文件传输后,主进程再次通过 SSH 连接到 pg_server 来结束备份模式。

    • SSH 命令 (概念性):

      Bash 复制代码
      ssh postgres@pg_server "pgbackrest --stanza=mystanza --log-level-file=<level> --command=backup --type=db --action=stop --process=1 remote"
    • pg_server 上的 remote 进程:

      • 连接到 PostgreSQL 实例。
      • 执行 pg_stop_backup() SQL 命令(或流复制协议等效命令)。
      • PostgreSQL 退出备份模式,将包含结束 LSN 和其他元信息的 backup_label 文件重命名为 backup_history 文件(旧机制)或完成相关记录,并返回结束 LSN、所需的最后一个 WAL 文件名等信息。
      • remote 进程将这些结束信息通过 SSH 返回给 repo_server 上的主进程。
  6. 验证 WAL 归档 (在 repo_server):

    • repo_server 上的主进程现在知道了备份覆盖的 LSN 范围(从 pg_start_backup 的 LSN 到 pg_stop_backup 的 LSN)。
    • 它会检查备份仓库中的 WAL 归档目录 (/path/to/repo/archive/mystanza),确认从上一个备份结束到本次备份结束之间的所有必需的 WAL 文件是否都已存在
    • 重要: backup 命令本身通常不负责 触发 WAL 的推送 (archive-push)。它依赖于 PostgreSQL 配置的 archive_command (指向 pgbackrest archive-push) 持续不断地将 WAL 文件推送到仓库。backup 命令只是在结束时检查 这些必需的 WAL 是否已经在那里。
  7. 写入备份元数据 (在 repo_server):

    • pgBackRest 在备份仓库中为这次备份创建一个重要的清单文件 (manifest file) ,通常是 backup.manifest

    • 此文件包含:

      • 备份的详细信息 (类型、时间戳、LSN 范围、PostgreSQL 版本、系统标识符等)。
      • 备份中包含的所有文件的列表,及其大小、修改时间、校验和等。
      • 关于依赖的 WAL 段的信息。
      • 表空间信息(如果有)。
    • 这个文件对于后续的恢复操作至关重要。

  8. 更新备份信息和清理 (在 repo_server):

    • 更新 Stanza 的全局信息文件 (例如 backup.info),记录这次新备份的状态。
    • 根据配置的保留策略 (repo1-retention-full, repo1-retention-diff 等),检查并删除过期的旧备份集及其相关的 WAL 文件。
    • 释放仓库锁: 删除之前创建的锁文件 (/path/to/repo/backup/mystanza/backup.lock)。
    • 备份命令执行结束,向用户报告成功或失败。

四、重要注意事项

  • SSH免密: 在远程仓库备份场景下,SSH 是 pgBackRest 实现服务器间协调和数据传输的主要通道

  • 权限: 运行 pgBackRest 的用户(如 postgrespgbackrest)需要对 PG 数据目录有读权限,对备份仓库目录有读写权限。如果使用 SSH,确保 SSH 用户有相应权限。

  • 一致性: 确保 pgbackrest.conf 在所有相关服务器(PG 主库、备份服务器、可能还有备库)上保持一致(至少 [global] 和 Stanza 的定义部分)。

  • 用户: 推荐使用专门的 pgbackrest 用户来管理备份仓库,而不是直接使用 postgres 用户,以遵循最小权限原则。

  • 测试恢复: 定期测试你的备份是否可以成功恢复,这是备份策略中至关重要的一环。

相关推荐
千|寻4 分钟前
【画江湖】langchain4j - Java1.8下spring boot集成ollama调用本地大模型之问道系列(第一问)
java·spring boot·后端·langchain
程序员岳焱18 分钟前
Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解
后端·sql·mysql
龚思凯24 分钟前
Node.js 模块导入语法变革全解析
后端·node.js
天行健的回响27 分钟前
枚举在实际开发中的使用小Tips
后端
wuhunyu32 分钟前
基于 langchain4j 的简易 RAG
后端
techzhi32 分钟前
SeaweedFS S3 Spring Boot Starter
java·spring boot·后端
写bug写bug2 小时前
手把手教你使用JConsole
java·后端·程序员
苏三说技术2 小时前
给你1亿的Redis key,如何高效统计?
后端
JohnYan2 小时前
工作笔记- 记一次MySQL数据移植表空间错误排除
数据库·后端·mysql
程序员清风2 小时前
阿里二面:Kafka 消费者消费消息慢(10 多分钟),会对 Kafka 有什么影响?
java·后端·面试