PostgreSQL的WAL基本原理

背景:

        1:任何数据库都不允许数据丢失。

        2:事务日志:记录数据库所有变更与行为的历史记录。

        3:数据库通过事务日志回放来保证数据库故障恢复后数据不丢失。

概念:

        WAL(Wrioter Ahead Logging 预写式日志),是一种规则或协议,指的是将变更和行为写入事务日志的规则。

应用:

        DB故障恢复后数据不丢失;

        时间点恢复(PITR);

       流复制(Streaming Replication, SR)

重要性:

        如果没有WAL。当发起insert操作,从数据库集簇文件中加载数据(表或索引)的页面--->到共享内存缓冲池(shared buffer pool)的槽中--->insert语句修改此页面--->此页面没有持久化,为脏页--->再次update更新次页面--->该页面继续被修改--->仍为脏页,没有刷盘---->此时数据库宕机--->数据库恢复后,内存中的修改页面不存在--->数据丢失。

标识  xlog:

        xlog: 首部数据和完整元组组成的一对值。

        历史修改数据<==>xlog记录(或WAL数据);

        lsn 唯一标识一条xlog记录。(xlog记录的lsn标识这个xlog在事务日志中的位置

xlog的持久化:

        Pg将所有历史数据写入持久化存储中。

        具体的,当插入、删除、提交变更动作发生时、Pg会把xlog记录写入内存的wal缓冲区。当事务提交或终止,会立即被写入持久存储的WAL段文件。

表lsn与页lsn:

        表的lsn是表页面首部pd_lsn数据字段、与页面的LSN是一回事。

重做点

        1:数据库故障恢复从哪一个时间点恢复:重做点(redo 点)

        2:重做点: 当前最新的检查点开始时xlog记录写入的(写入wal段文件)位置。(检查点: chekpoint进程启动时,检查点xlog写入wal段文件,检查点xlog记录中包含最新的重做点位置)

xlog持久化:

        0:检查点进程启动(这个后台进程是定期执行的),检查点进程负责下面步骤中将xlog记录写入wal段文件的任务。

        1:页面加载到共享缓冲池中,当sql语句对数据页面修改,lsn位置创建并记录一条xlog,更新页面lsn.

        2:事务提交,wal缓冲区创建并写该提交行为的xlog记录。

        3:再将wal缓冲区中所有xlog记录(1, 2的xlog记录?)写入WAL段文件中(进行持久化)。

        4:重复1,2,3步骤,所有页面修改,都被当做历史修改记录在wal段文件中

        5:数据库故障恢复后,直接wal段文件中恢复。

利用xlog进行数据库恢复(xlog回放):

        从redo点开始,依序读取正确的WAL段文件并回放xlog记录。  按照时间顺序。

        1:从redo点开始,读取WAL段文件中第一条语句的xlog记录

        2:从数据库集簇文件中加载表A的页到内存中的共享缓冲区中

        3:回放xlog: 比较当前页面的lsn和xlog的lsn:

                (1): xlog lsn > 页 lsn, xlog的数据就会被插入到当前页面中去。

                (2): xlog lsn < 页 lsn, 不会做任何事情,直接读取后面wal数据

         4:按照时间顺序读取,重复按照3方式回放其他xlog记录

Pg的xlog整页写入机制:

        备机:为啥整页写入:当pg_writer进程将脏页刷到磁盘过程中,磁盘上页面损坏,此时xlog无法回放损坏的页面。因此需要完整页面及其首部元信息作为一条xlog记录写入(整页写入)。

        包含完整页面的xlog记录称为备份区块或整页镜像。

        什么时候写:每个页面在最近的检查带点之后第一次发生变更时,进行一次xlog的整页写入。

xlog整页写入和回放:

        1:checkpoint进程启动,(检查点开始)

        2:当insert语句导致数据页面发生修改,写一条xlog,这个xlog记录当前的备份区块(即包含了完整的页面)。注意:之所以xlog整页记录,是因为最近的一次检查点之后该页面第一次写入。

        3:当这个事务提交,wal缓冲区创建并记录xlog。之后写入WAL段文件。

        4:当再来一条insert语句,不再是第一次修改该数据页面,xlog不再整页写入,正常在lsn位置创建并写xlog记录。

        5:当这个事务提交,wal缓冲区创建并记录xlog。之后写入WAL段文件。

       6:此时数据库发生crash.

        7: 等到数据库恢复。

        8:从redo点开始,读取WAL段文件中第一条语句的xlog记录。从数据库集簇目录加载表的页面到共享缓冲池。进行回放xlog。

        这里的回放规则:

                (1): 当第一条xlog是备份区块,回放规则为:xlog记录是一个备份区块时,直接覆盖当前页面,无视页面或xlog记录的lsn,然后将页面的lsn更新为xlog lsn。

                (2): xlog lsn > 页 lsn, xlog的数据就会被插入到当前页面中去。

                (3): xlog lsn < 页 lsn, 不会做任何事情,直接读取后面wal数据

        9:按照时间顺序,重复上诉步骤8。

WAL段文件:

        Pg中事务日志默认被分成大小为16MB的文件。这些文件被称为WAL段文件

        事务日志pg_xlog(目录)中包含多个wal段文件。

        WAL段文件命名:24个16进制数(一个数占4位)组成。  每个wal段文件大小为16MB。

        命名规则:https://blog.csdn.net/m15217321304/article/details/81152555

               PostgreSQL的WAL基本原理_第1张图片

                PostgreSQL的WAL基本原理_第2张图片

                PostgreSQL的WAL基本原理_第3张图片

WAL段文件的内部布局:

        段文件大小为16MB,内部划分为多个8KB的页面。

        每个8KB的页面:包括多个XLOG record.

        XLOG record : 包括首部 Header 和 数据部分 Data

        数据部分 Data: 分为两类,备份区块和非备份区块。

WAL记录的写入流程(xlog写入wal段文件的过程)

        伪代码流程:

        (1)insert into table1 values(1); 

        (2)exec_simple_query() // 执行sql语句

        (3)ExtendClog()    // 记录当前事务状态为in_progress, 写入内存的clog中。

        (4)heap_insert()   // 向共享缓冲池的目标页面上插入元组,创建一条当前页面的xlog记录,调用XLogInsert()。

         (5)XlogInsert()   // 将插入元组的xlog记录写入到WAL缓冲区LSN_1处,更新被修改页面pd_lsn从LSN_0为LSN_1。

         (6)finish_xact_command()  // 执行事务提交,创建提交动作的xlog

           (7)  XLogInsert()   //将该提交行为的xlog记录写入到WAL缓冲区LSN_2处

         (8)XLogWrite()    //将WAL缓冲区所有的xlog记录写入WAL段文件中

         (9)TransactionIdCommitTree()    // 在Clog中将当前事务的状态由"in_progress"修改为"commit".

           (10)以下场景,wal缓冲区的xlog记录都会被写入wal文件

                        1:运行中的事务提交或终止

                         2:wal缓冲区被元组xlog记录写满(wal_buffer满了)

                         3:wal写入进程周期性的执行写入操作。

什么操作会写xlog?

        (1) DML

        (2) Commit操作,包含提交id的xlog记录

        (3) checkpoint进程会写关于该检查点概述信息的xlog记录。检查点xlog记录也会写入WAL缓冲区。

检查点进程(负责脏页刷盘和数据库恢复工作准备):

        (1):检查点进程启动时,会将重做点存储在内存中。(这里的重做点是上一次检查点开始时刻XLOG记录的写入位置,也是数据库恢复的开始位置)

        (2):该检查点相应的XLOG记录(即检查点xlog记录)会被写入WAL缓冲区。该XLOG记录是由checkpoint结构体定义的,包含一些变量,如(1)中的重做点的位置。

        (3):会将共享内存中的所有数据,如CLOG的内容,都会被刷入磁盘中。

        (4):共享缓冲池中的所有脏页都会被刷写到存储中。

        (5):更新pg_control文件。该文件包含上一次检查点的位置。检查点进程会创建包含重做点的检查点,并将检查点位置与其他信息存储到pg_control文件中。

Pg的重做点是从检查点中获取的。检查点存储在pg_control文件。由检查点进程写入的。

Pg的数据库恢复:

        (1):读取pg_control文件中的所有项:(in production 数据库正在运行,进入恢复模式,意味着数据库没有正常停止)

        (2):Pg从合适的WAL段文件中读取最近(最新)的检查点记录(检查点相应的xlog),该xlog记录的位置(检查点)写在pg_control文件中。从这个检查点中获取redo点。如果这个最新的检查点是无效的,就会读取前一个检查点。

        (3):基于读取的redo点回放xlog记录,直到最新的WAL段文件的最后位置。

        (4):具体的回放机制,见上面所讲。

WAL段文件管理(wal的回收利用机制):

        1:Pg中xlog记录写入在pg_xlog子目录的WAL段文件中。当旧的段文件写满,就会切换到新的段文件。

        2:单检查点进程启动时,pg都会估计并准备一个检查点周期所需的WAL段文件。

             估计的准则,是依据当前检查点周期消耗的文件数量。这个文件数量从重做点的段文件开始计数,计数的值在min_wal_size到max_wal_size之间。

        3:实例:假设检查点开始之前共有6个wal段文件,wal_3包含上一个检查点周期的redo点。Pg估计需要5个文件,这种情况wal_1-->回收利用为wal_7,wal_2被移除。任何一个比redo点老的段文件理论上都可以被移除。

你可能感兴趣的:(数据库,postgresql)