暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

pgbackrest 的异步模式

飞象数据 2022-05-20
1082

pgbackrest 是一个惊人的备份工具,它坚如磐石(就像PostgreSQL一样),设计用于在繁重的数据库负载下工作。

pgbackrest
的“异步”模式可以提高WAL的归档效率。

在“标准”模式下,pgbackrest
将使用PostgreSQL提供的archive_command
将WAL段推送到备份服务器。您可能已经知道,PostgreSQL将等待archive_command
完成并确认WAL的传输。可能发生以下情况:

  • archive_command
    可能需要很长时间,虽然PostgreSQL将继续工作,但尚未转移的wal将使pg_wal
    增长;

  • archive_command
    可能会失败,PostgreSQL将(在日志中)警告您此事件,并将再次尝试归档失败的WAL(直到成功)。

另一方面,在执行还原时,PostgreSQL执行restore_command
获取WAL段,这反过来会导致单个WAL请求运行pgbackrest

pgbackrest
通过“异步归档管理”的“推送”和“获取”,可以改善这种情况。这样做的目的是对pgbackrest
进行更多的控制,以便它可以优化输入/输出操作。

当PostgreSQL归档WAL段时,它会在循环中执行archive_command
:当WAL准备就绪时,会调用archive_command
,并且在它完成之前,不能归档其它的WAL段。另一方面,当PostgreSQL需要获取WAL以执行还原/恢复时,它会在希望重放的每个WAL段上执行restore_command
。因此,如果必须重放多个WAL,则必须依次执行restore_command
来“获取”每个WAL。

那么异步模式如何改进上述内容?

  • 归档意味着推送pgbackrest
    可以决定在一个批次中推送多个WAL,这意味着减少与备份服务器建立网络连接的操作。

  • 恢复意味着获取PGbackback
    可以执行预取,在本地服务器上下载一些WAL,并在需要时立即将它们提供给PostgreSQL服务器。

测试环境

在这篇文章中,我将使用两台机器来演示pgbackrest
的异步用法:

  • miguel
    是PostgreSQL 服务器,运行Fedora Linux和PostgreSQL 13.3;

  • carmensita
    是备份计算机,运行Fedora Linux。

pgbackrest
的版本为2.34


异步配置参数

配置参数可以在pgbackrest.conf
文件中配置,也可以像往常一样在命令行中指定。

异步参数设置主要考虑spool目录、队列和异步模式的启用。

异步模式的启用

只有一个配置参数可以启用异步模式:async
。默认是false。打开它,将自动使任何archive-get
archive-push
处于异步模式。


spool目录

为了管理异步操作,pgbackrest
在PostgreSQL服务器上创建一个spool目录,通常是/var/spool/pgbackrest
,其中放置一个“archive”目录和一个以服务器命名的目录,或者更好的是以 stanza命名的目录。然后,可以将此类目录拆分为in
out
,分别用于archive-get
archive-push

可以使用spool-path
配置参数定义spool 目录。

例如,给定名为miguel
的stanza ,spool目录将是/var/spool/pgbackrest/archive/miguel/out
/var/spool/pgbackrest/archive/miguel/in

系统将在out
目录中写入簿记内容,主要是小文本文件,用于确定归档的时间点。

in
目录中,系统将存储准备对PostgreSQL服务器进行还原的WAL。


队列

有两种不同的设置来管理pgbackrest
的队列:

  • archive-push-max-queue
    ;

  • archive-get-max-queue
    .

它们的意义是配置在推送和获取操作时排队的数据的最大大小。当队列已满时,pgbackrest
将根据正在进行的操作进行不同的处理,如下所述。


配置

这台名为carmensita
的备份服务器有一个7etc/pgbackrest.conf
文件,配置如下:

    $ cat etc/pgbackrest.conf
    [global]
    start-fast = y
    stop-auto = y
    repo1-path = backup/pgbackrest


    repo1-retention-full=2


    repo1-host-user = backup
    log-level-console = info




    [miguel]
    pg1-host = miguel
    pg1-path = postgres/13/data
    复制

    在PostgreSQL 服务器上,名为miguel
    /etc/pgbackrest.conf
    文件

      [global]
      repo1-path = backup/pgbackrest
      repo1-host-user = backup
      log-level-console = info
      repo1-host = carmensita






      archive-async = y
      archive-push-queue-max = 500MB
      spool-path = var/spool/pgbackrest
      archive-get-queue-max = 32MB
      复制

      最后,PostgreSQL 服务器上的archive_command
      配置如下:

        archive_command = '/usr/bin/pgbackrest \
        --pg1-path=/postgres/13/data \
        --config=/etc/pgbackrest.conf \
        --stanza=miguel \
        archive-push %p'
        archive_mode = on
        复制

        请注意,archive-async
        参数是在配置中指定的,而不是在archive-push
        archive-get
        中设置的。在我看来,这简化了pgbackrest
        的用法。

        通过以上所有操作,可以了解异步模式的工作原理。


        归档(archive-push)

        让我们从备份场景开始,即archive-push

        当一切进展顺利

        让我们看看一切正常时会发生什么:我启动了一个pgbench
        会话,以生成一些流量,从而生成一些WAL段并进行归档。pgbench
        的运行方式如下:

          % pgbench -c 8 -T 120 -h miguel -U pgbench -n -P 5 pgbench
          复制

          pgbench
          运行时,让我们检查一下PostgreSQL机器上发生了什么,特别是spool文件夹:

            # ls -1s var/spool/pgbackrest/archive/miguel/out \
            && psql -h miguel -U postgres \
            -c 'select last_archived_wal from pg_stat_archiver;' postgres


            0 000000070000014E00000015.ok


            last_archived_wal
            --------------------------
            000000070000014E00000015




            # # after a while


            # ls -1s var/spool/pgbackrest/archive/miguel/out \
            && psql -h miguel -U postgres \
            -c 'select last_archived_wal from pg_stat_archiver;' postgres


            0 000000070000014E00000016.ok


            last_archived_wal
            --------------------------
            000000070000014E00000016
            复制

            如您所见,在spool目录中,将有一个空文件,以最后一个存档的WAL段命名,这是发送到备份计算机的最后一个段,后缀为.ok

            在PostgreSQL日志中,pgbackrest
            完成推送时会有一个通知(取决于您配置的日志级别):

              INFO: pushed WAL file '000000070000014E000000AD' to the archive asynchronously
              复制


              当出现问题时

              第一种情况:关闭备份计算机

              假设备份服务器carmensita
              已关闭。归档无法工作,如果您在PostgreSQL 服务器上再次生成一些流量(例如,使用如上所示的pgbench
              ),spool目录上的情况是:

                # ls -1s var/spool/pgbackrest/archive/miguel/out \
                && psql -h miguel -U postgres \
                -c 'select last_archived_wal, last_failed_wal from pg_stat_archiver;' postgres


                4 global.error


                last_archived_wal | last_failed_wal
                --------------------------|--------------------------
                000000070000014E0000001A | 000000070000014E0000001B
                复制

                global.error
                文件包含对所发生情况的文本描述:

                  # cat var/spool/pgbackrest/archive/miguel/out/global.error 
                  103
                  unable to find a valid repository:
                  repo1: [UnknownError] remote-0 process on 'carmensita' terminated unexpectedly [255]: ssh: connect to host carmensita port 22: No route to hos
                  复制

                  如果随后重新启动备份服务器,归档再次开始工作,则spool目录上的情况如下:

                    # ls -1s var/spool/pgbackrest/archive/miguel/out \
                    && psql -h miguel -U postgres \
                    -c 'select last_archived_wal, last_failed_wal from pg_stat_archiver;' postgres


                    0 000000070000014E0000001B.ok
                    0 000000070000014E0000001C.ok
                    0 000000070000014E0000001D.ok
                    0 000000070000014E0000001E.ok
                    0 000000070000014E0000001F.ok


                    last_archived_wal | last_failed_wal
                    --------------------------|--------------------------
                    000000070000014E0000001F | 000000070000014E0000001B
                    复制

                    正如您所看到的,.ok
                    文件已经存在,归档工作又开始了。

                    在此期间,可能有一个或多个.ok
                    文件。最后一个.ok
                    文件表示最后一个异步存档的WAL段(在上面,是以1F
                    结尾的那个)。


                    第二种情况:生成了更多的WAL

                    再次关闭备份服务器,使PostgreSQL 服务器无法归档WAL段;然后生成大量流量以增加WAL目录的大小(pg_wal
                    )。

                    让我们检查一下情况:

                      # ls -1s var/spool/pgbackrest/archive/miguel/out \
                      && psql -h miguel -U postgres \
                      -c 'select last_archived_wal, last_failed_wal from pg_stat_archiver;' postgres


                      4 global.error


                      last_archived_wal | last_failed_wal
                      --------------------------|--------------------------
                      000000070000014E000000ED | 000000070000014E000000EE

                      # cat var/spool/pgbackrest/archive/miguel/out/global.error
                      103
                      unable to find a valid repository:
                      repo1: [UnknownError] remote-0 process on 'carmensita' terminated unexpectedly [255]: ssh: connect to host carmensita port 22: No route to host
                      复制

                      因此,000000070000014E000000ED
                      是备份计算机上最后一个归档的WAL。

                      假设现在PostgreSQL上有大量数据被修改,因此它开始生成WAL段。显然,PostgreSQL无法再存档段,将开始把它们累积到pg_wal
                      中,以使它们在archive_command
                      再次开始工作时可用。spool目录中的情况会还是这样吗?让我们再次检查:

                        # ls -1s var/spool/pgbackrest/archive/miguel/out \
                        && psql -h miguel -U postgres \
                        -c 'select last_archived_wal, last_failed_wal from pg_stat_archiver;' postgres


                        4 000000070000014F00000053.ok
                        4 000000070000014F00000054.ok
                        4 000000070000014F00000055.ok
                        4 000000070000014F00000056.ok
                        4 000000070000014F00000057.ok
                        4 000000070000014F00000058.ok
                        4 000000070000014F00000059.ok
                        4 000000070000014F0000005A.ok.pgbackrest.tmp


                        last_archived_wal | last_failed_wal
                        --------------------------|--------------------------
                        000000070000014F00000059 | 000000070000014F00000053




                        # cat /var/spool/pgbackrest/archive/miguel/out/000000070000014F00000059.ok
                        0
                        dropped WAL file '000000070000014F00000059' because archive queue exceeded 500MB
                        复制

                        首先:last_archived_wal
                        已经往前推了,即使acrhive_command
                        失败(请记住备份服务器已关闭)
                        !这怎么可能?

                        答案是pgbackrest
                        的异步工作原理:如果失败的WAL数量大于指定的大小,pgbackrest
                        将“承认”归档到达备份服务器,即使归档的WAL没有到备份服务器。

                        其想法是,pgbackrest
                        将阻止pg_wal
                        无休止的增长,从而有可能阻止PostgreSQL的工作。
                        但是,承认一个虚假归档意味着WAL流已被破坏,因此无法再围绕这个漏洞进行时间点恢复,因此强烈建议使用新的备份机器!

                        pgbackrest
                        将一个信息插入其.ok
                        文件中,该文件现在是非空的,并通知管理员WAL段已明确删除。

                        您可以在PostgreSQL日志中找到相同的信息,pgbackrest
                        会在日志中打印一条消息,以明确:

                          % sudo grep 000000070000014F00000059 $PGLOG


                          INFO: archive-push command begin 2.34: [pg_wal/000000070000014F00000059] --archive-async --archive-push-queue-max=500MB --config=/etc/pgbackrest.conf --exec-id=40124-af251b1c --log-level-console=info --pg1-path=/postgres/13/data --repo1-host=carmensita --repo1-host-user=backup --repo1-path=/backup/pgbackrest --spool-path=/var/spool/pgbackrest --stanza=miguel


                          WARN: dropped WAL file '000000070000014F00000059' because archive queue exceeded 500MB


                          INFO: pushed WAL file '000000070000014F00000059' to the archive asynchronously
                          复制

                          有三条信息:

                          • pgbackrest
                            试图归档WAL段,失败;

                          • 有一个WARN
                            通知您,pgbackrest
                            检测PostgreSQL以删除WAL文件,就好像它已正确归档;

                          • pgbackrest
                            表示它已保存该归档文件,因此PostgreSQL可以继续删除或回收该文件。

                          pgbackrest
                          什么时候决定放弃并开始冒充PostgreSQL?acrhive-push-queue-max
                          配置确定了pgbackrest
                          归档失败的数据大小。在我的配置中archive-push-queue-max=500MB
                          ,这意味着产生500MB
                          的堵塞之后,pgbackrest
                          将开始进行伪造,WAL流中将出现一个洞。这大致对应堵塞了32
                          个WAL日志。


                          并行进程

                          配置参数process-max
                          用于控制启动多少个push workers来为异步系统服务。假设在配置中有process-max = 4
                          ,那么在WAL归档期间,您可以在进程列表中看到以下内容:

                            # pstree -c  -A
                            systemd-|-NetworkManager-|-{NetworkManager}
                            ...
                            |-pgbackrest-|-pgbackrest---ssh
                            | |-pgbackrest---ssh
                            | |-pgbackrest---ssh
                            | |-pgbackrest---ssh
                            | `-ssh
                            ...
                            |-postmaster-|-postmaster
                            | |-postmaster
                            | |-postmaster
                            | |-postmaster
                            | |-postmaster
                            | |-postmaster---pgbackrest
                            | |-postmaster
                            | `-postmaster
                            ...
                            复制

                            如您所见,PostgreSQL已启动了pgbackrest
                            (即正在执行archive_command
                            ),共有四个pgbackrest
                            进程。如果系统以同步模式推送归档文件,则忽略process-max
                            参数。

                            每个并发进程将共享一个exec-id
                            ,用于标识进程所属的批次:

                              # pstree -A -c -a -l | grep pgbackrest
                              ...
                              |-pgbackrest --config=/etc/pgbackrest.conf --exec-id=46475-10e060a1
                              | |-pgbackrest --config=/etc/pgbackrest.conf --exec-id=46475-10e060a1
                              | |-pgbackrest --config=/etc/pgbackrest.conf --exec-id=46475-10e060a1
                              | |-pgbackrest --config=/etc/pgbackrest.conf --exec-id=46475-10e060a1
                              ...
                              复制


                              还原 (archive-get)

                              让我们从最近的备份执行恢复:

                                % sudo systemctl stop postgresql-13.service
                                % sudo -u postgres pgbackrest --stanza miguel \
                                --pg1-path /postgres/13/data --delta restore
                                ...
                                INFO: restore command end: completed successfully (69861ms)
                                复制

                                在还原过程中,pgbackrest
                                的spool目录中的archive
                                目录将被清理,尤其是特定的服务器目录miguel
                                将被删除,因为没有进行WAL归档。

                                postgresql.auto.conf
                                文件包含archive-get
                                命令,提取WAL段:

                                  % sudo cat /postgres/13/data/postgresql.auto.conf


                                  # Recovery settings generated by pgBackRest restore on 2021-07-27 05:26:26
                                  restore_command = 'pgbackrest --pg1-path=/postgres/13/data --stanza=miguel archive-get %f "%p"'
                                  复制

                                  在系统启动期间,pgbackrest
                                  将(像往常一样)从备份服务器获取WAL段,但这次是以异步方式:

                                    INFO: archive-get command begin 2.34: [000000070000014F000000A4, pg_wal/RECOVERYXLOG] --archive-async --archive-get-queue-max=32MB --exec-id=42831-f4ada646 --log-level-console=info --pg1-path=/postgres/13/data --repo1-host=carmensita --repo1-host-user=backup --repo1-path=/backup/pgbackrest --spool-path=/var/spool/pgbackrest --stanza=miguel


                                    INFO: found 000000070000014F000000A4 in the archive asynchronously


                                    INFO: archive-get command end: completed successfully (713ms)
                                    复制

                                    以上是PostgreSQL日志的摘录。同时,spool目录中填充了服务器的in
                                    子目录,在该目录中存储了传入的WAL,并等待PostgreSQL服务器重放:

                                      % sudo ls -1s /var/spool/pgbackrest/archive/miguel/in
                                      16384 000000070000014F000000A4.pgbackrest.tmp
                                      复制

                                      在这种情况下,archive-get-queue-max
                                      参数可以指定预取WAL的大小:pgbackrest
                                      将在后台处理目录中提取和存储的WAL段不超过指定数量。与推送配置不同,设置此参数并不意味着系统将丢弃WAL。


                                      结论

                                      异步模式可以通过批次和预取WAL段来帮助提高性能。但是,您需要了解这样一个事实,即如果归档积累了太多的数据,异步推送的WAL流可能会产生漏洞。

                                      在我看来,这是一个好的特性,因为根据我的经验,PostgreSQL服务器会由于机器(或网络)故障而累积太多的WAL段(甚至消耗了所有存储)。毕竟,pgbackrest
                                      可以确保备份存在,至少可以确保您的PostgreSQL服务器不会因为archive_command
                                      失败而变成只读。


                                      文章转载自飞象数据,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                      评论