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

历史由此展开:WAL(Write-Ahead Logging)历史文件的调查

321

作者简介

Brian Pace 

crunchydata工程师

译者简介

王志斌

PostgreSQL爱好者

校对者简介

崔鹏

PostgreSQL爱好者


PostgreSQL使用时间轴的概念来识别空间和时间中一系列的WAL记录。每个时间轴都由一个数字标识,有时是十进制,有时是十六进制。每次使用时间点恢复数据库,有时在备用/副本升级期间,都会生成一个新的时间轴。

一个常见的错误是认为更高的时间轴编号意味着最新的数据。虽然最高的时间轴指向数据库的最新版本,但这并不保证数据库确实持有从应用程序角度来看最有用的数据。为了辨别这种说法的有效性,有必要对(WAL)历史文件进行更仔细的审查,解开它们传达的信息。

在本讨论中,我们将探索一个恢复的数据库,并追踪嵌入在历史文件中的记录 。通过结论,您将更深入地了解这些历史文件在Postgres中的功能,从而使您能够解决与恢复过程和数据库历史旅程(或我是否可以称之为家谱)相关的查询。

评估当前状态

让我们首先通过获得对数据库当前状态的洞察来开始。从pg_controldata输出获取的信息表明,数据库当前处于时间轴11上。请注意最新的检查点(WAL)文件,标识为'0000000B0000000100000039'。请参阅我之前关于WAL文件命名和编号的帖子。 值得注意的是,时间轴有时以十进制形式表示,如11,而有时以十六进制形式表示,如'0000000B'。虽然这种双重表示可能会在开始时令人困惑,但对于这些不同形式何时何地使用的熟悉将有助于更清晰地理解。

    $ pg_controldata
    ...
    pg_control last modified: Tue 06 Feb 2024 03:10:53 PM EST
    Latest checkpoint location: 1/39000060
    Latest checkpoint's REDO location: 1/39000028
    Latest checkpoint's REDO WAL file: 0000000B0000000100000039
    Latest checkpoint's TimeLineID: 11
    ...
    复制

    另一个需要考虑的关键方面是检查pg_wal目录的内容,以识别现有的历史文件。如果当前数据库在创建时间轴11时不是主数据库,那么它可能只有最新的历史文件。在这种情况下,我们正在调查的服务器是主Postgres实例。

      $ ls -1 $PGDATA/pg_wal/*.history
      00000003.history
      0000000A.history
      0000000B.history
      复制

      乍一看,人们可能会假设时间轴11(记住历史文件和段文件使用十六进制)的谱系源自时间轴100000000A)和300000003)。就任何假设而言,我们必须在确认这个假设为事实之前进行验证。为了做到这一点,让我们来查看时间轴11的历史文件的内容。

        $ cat 0000000B.history


        1 0/710000A0 no recovery target specified
        2 0/72000000 no recovery target specified
        3 1/22000CE0 before 2024-02-03 00:37:49.381764-05
        10  1/230000A0  no recovery target specified
        复制

        查看历史文件的内容,我们看到了时间轴11家谱。时间轴11是从LSN 1/230000A0的时间轴10创建的。时间轴10是从LSN 1/22000CE0的时间轴3创建的。等等!那么时间轴49呢?没有指定恢复目标2024-02-03 00:37:49.381764-05之前是什么意思?这些是应该问的正确问题。让我们继续我们的探索。

        历史文件内容

        从时间轴11的历史文件顶部开始,我们沿着列表向下阅读,以查看其家谱没有指定恢复目标告诉我们,该时间轴很可能是通过升级(例如选择pg_promote())创建的。另一方面,时间轴10是使用针对时间轴3执行的时间点恢复创建的。时间戳是从哪里来的?那是最后一笔交易的时间戳吗?这是更好的问题。让我们探讨一下。

        我们需要做的第一件事是检查时间轴10所创建的WAL段的内容。在这种情况下,时间轴10是从时间轴3LSN 1/22000CE0创建的。将LSN转换为准确的WAL段,我们得到000000030000000100000022。斜杠前面的数字是高位数字 ,而斜杠后面的前几个字符是低位数字 。这两个数字与时间轴前缀在一起给出了WAL段的名称(记住是十六进制)。下面是该段的pg_waldump摘录。

          $ pg_waldump 000000030000000100000022
          rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 1/22000028, prev 1/21000138, desc: RUNNING_XACTS nextXid 1035 latestCompletedXid 1034 oldestRunningXid 1035
          rmgr: Heap len (rec/tot): 61/ 1666, tx: 1035, lsn: 1/22000060, prev 1/22000028, desc: DELETE xmax: 1035, off: 4, infobits: [KEYS_UPDATED], flags: 0x00, blkref #0: rel 1663/5/16684 blk 0 FPW
          rmgr: Heap2 len (rec/tot): 1460/ 1460, tx: 1035, lsn: 1/220006E8, prev 1/22000060, desc: MULTI_INSERT ntuples: 1, flags: 0x02, offsets: [5], blkref #0: rel 1663/5/16684 blk 0
          rmgr: Heap2 len (rec/tot): 63/ 63, tx: 1035, lsn: 1/22000CA0, prev 1/220006E8, desc: PRUNE snapshotConflictHorizon: 1034, nredirected: 0, ndead: 4, nunused: 0, redirected: [], dead: [1, 2, 3, 12], unused: [], blkref #0: rel 1663/5/16684 blk 0
          rmgr: Transaction len (rec/tot): 34/ 34, tx: 1035, lsn: 1/22000CE0, prev 1/22000CA0, desc: COMMIT 2024-02-03 00:37:49.381764 EST
          rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 1/22000D08, prev 1/22000CE0, desc: RUNNING_XACTS nextXid 1036 latestCompletedXid 1035 oldestRunningXid 1036
          rmgr: XLOG        len (rec/tot):     24/    24, tx:          0, lsn: 1/22000D40, prev 1/22000D08, descSWITCH
          复制

          LSN 1/22000CE0处创建了时间轴10。从上面的内容可以看出,该位置有一个带有时间戳“2024-02-03 00:37:49.381764 EST”的提交(LSN的最后一组字符是WAL段内的偏移量)。WAL历史文件告诉我们,时间轴10是在这个提交之前创建的(...之前)。在CE0处提交的任何事务都不会出现在时间轴10中。 那么这个时间戳为什么相关呢?为了理解这一点,让我提供一些背景知识。传递给pgBackRest进行时间点恢复的时间戳是“2024-02-03 00:30:10 EST”CE0处的提交是我们恢复目标时间之后的第一个事务。因此,历史文件显示2024-02-03 00:37:49.381764 EST之前

          在我们继续之前,最后要提一点。历史文件为我们提供的最后一条信息是时间轴11是从时间轴10创建的。根据没有指定恢复目标的说明,我们可以安全地假设这是来自一种升级类型的事件,或者进行了恢复并且没有更多的WAL段被识别或可用。

          丢失的时间线

          关于时间轴49怎么办?别担心,我没有忘记这个问题。为了获取这些时间轴的历史文件,我们需要去pgBackRest存储库。为了检索它们,我将执行类似于下面的语句来从pgBackRest中恢复它们:

            $ pgbackrest archive-get 00000004.history --stanza=rhino app/pgdata/rhino.16/pg_wal/00000004.history
            复制

            上述过程将重复进行时间轴49。我们将从时间轴9的历史文件开始我们的调查。以下是内容:

              $ cat 00000009.history
              1 0/710000A0 no recovery target specified


              2 0/72000000 no recovery target specified


              3 3/DA0000A0 no recovery target specified


              4 3/DB0000A0 no recovery target specified


              5 3/DC000000 no recovery target specified


              6 5/2E0000A0 no recovery target specified


              7 5/300000A0 no recovery target specified


              8   5/570000A0  no recovery target specified
              复制

              从上面可以看出,从时间轴19有一个正常的进展(意味着没有恢复)。这并不意味着,例如时间轴4LSN 3/DB0000A0之后就没有任何更新。这是另一篇博客文章的不同主题。如果我们能够绘制时间轴,它会是这样的样子:


              我们的旅程已经进行到了这一点。然而,我们需要回答最初的问题,即哪个时间轴具有最新的数据。首先,我们需要知道时间轴1011存在了多久。为此,我们将再次使用pg_waldump对时间轴10的起始WAL段进行转储(提示,将使用相同的段名称,但具有不同的时间轴前缀)。看一下这个段的内容:

                $ pg_waldump 0000000A0000000100000022
                rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 1/22000028, prev 1/21000138, desc: RUNNING_XACTS nextXid 1035 latestCompletedXid 1034 oldestRunningXid 1035
                rmgr: Heap len (rec/tot): 61/ 1666, tx: 1035, lsn: 1/22000060, prev 1/22000028, desc: DELETE xmax: 1035, off: 4, infobits: [KEYS_UPDATED], flags: 0x00, blkref #0: rel 1663/5/16684 blk 0 FPW
                rmgr: Heap2 len (rec/tot): 1460/ 1460, tx: 1035, lsn: 1/220006E8, prev 1/22000060, desc: MULTI_INSERT ntuples: 1, flags: 0x02, offsets: [5], blkref #0: rel 1663/5/16684 blk 0
                rmgr: Heap2 len (rec/tot): 63/ 63, tx: 1035, lsn: 1/22000CA0, prev 1/220006E8, desc: PRUNE snapshotConflictHorizon: 1034, nredirected: 0, ndead: 4, nunused: 0, redirected: [], dead: [1, 2, 3, 12], unused: [], blkref #0: rel 1663/5/16684 blk 0
                rmgr: XLOG len (rec/tot): 42/ 42, tx: 0, lsn: 1/22000CE0, prev 1/22000CA0, desc: END_OF_RECOVERY tli 10; prev tli 3; time 2024-02-06 13:25:33.877840 EST
                ...
                复制

                根据以上内容,数据库的恢复在东部标准时间26日下午1:25完成。这意味着数据库(时间轴1011)现在包含了2小时的应用程序更改(假设应用程序在恢复后立即恢复)。现在,让我们将其与时间轴9中的最后一个WAL段进行比较:

                  $ pg_waldump 000000090000000500000057
                  ...
                  rmgr: Transaction len (rec/tot): 34/ 34, tx: 1661, lsn: 5/570032B0, prev 5/57002B28, desc: COMMIT 2024-02-06 13:23:51.110938 EST
                  rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 5/570032D8, prev 5/570032B0, desc: RUNNING_XACTS nextXid 1662 latestCompletedXid 1661 oldestRunningXid 1662
                  ...
                  复制

                  们可以通过查看Postgres日志和/pgBackRest存储库来确定最新的WAL段。在这个示例中,WAL000000090000000500000057是最新的。该段已经恢复,并且上面的pg_waldump显示最后一个提交的事务是在2426日下午1:23:51 EST。这意味着时间轴984个小时和一些变化的应用程序更改。这是通过测量时间轴11的历史文件中“before”时间戳(它是从时间轴3派生的时间)和时间轴9中的最后一个事务之间的差异来确定的。

                  回到我们的问题。时间轴11是否具有最新的数据?也许,它可能拥有一些稍晚处理的数据,但接受这一点意味着丢失84个小时的数据。

                  结论

                  时间轴历史文件以及一些方便的调查工作可以告诉我们数据库家族树的故事。如果您被要求恢复数据库,您现在可以在哪个时间轴可能包含对业务最有用的数据上做出明智的选择。

                  在执行恢复、重新初始化备用或副本之前,以下是一些有用的步骤,可以帮助您进行调查,以确定从业务角度来看哪个时间轴包含最有用的数据.


                  点击文章底部“阅读原文”,查看原文内容。



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

                  评论