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 用户,以遵循最小权限原则。

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

相关推荐
丘山子21 分钟前
一些鲜为人知的 IP 地址怪异写法
前端·后端·tcp/ip
CopyLower1 小时前
在 Spring Boot 中实现 WebSockets
spring boot·后端·iphone
.生产的驴2 小时前
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
java·数据库·spring boot·后端·spring·eclipse·maven
景天科技苑2 小时前
【Rust】Rust中的枚举与模式匹配,原理解析与应用实战
开发语言·后端·rust·match·enum·枚举与模式匹配·rust枚举与模式匹配
追逐时光者2 小时前
MongoDB从入门到实战之Docker快速安装MongoDB
后端·mongodb
方圆想当图灵3 小时前
深入理解 AOP:使用 AspectJ 实现对 Maven 依赖中 Jar 包类的织入
后端·maven
豌豆花下猫3 小时前
Python 潮流周刊#99:如何在生产环境中运行 Python?(摘要)
后端·python·ai
嘻嘻嘻嘻嘻嘻ys3 小时前
《Spring Boot 3 + Java 17:响应式云原生架构深度实践与范式革新》
前端·后端
异常君3 小时前
线程池隐患解析:为何阿里巴巴拒绝 Executors
java·后端·代码规范
mazhimazhi3 小时前
GC垃圾收集时,居然还有用户线程在奔跑
后端·面试