21.full page write(全页写)

全页写

  在数据库发生一次 checkpoint 检查点后,需要往数据库的一个数据块里面插入数据,数据库在修改前需要把这个数据块从磁盘读到内存中数据缓冲区 (shared buffer pool) 里,然后再内存中进行数据块的修改插入。当我们执行 insert 语句时,对数据块进行插入数据 A,内存中的数据块里面就会新增一条数据 A。在 commit 提交后,PG 数据块就会将这整个块写到 WAL buffer 日志缓冲区,然后再写到 WAL 日志文件中。然后我们再次对数据块进行插入数据 B,内存中的数据缓冲区同样会再次新增一条数据 B。在 commit 提交后,这个时候 PG 数据库就会将新插入数据 B 的事务日志条目写到 WAL buffer 日志缓冲区,最后再将这条数据库 B 的事务日志条目写到 WAL 日志文件中。

  全页写就是把整个数据库块的内容写到 WAL buffer 日志缓冲区和 WAL 日志文件中。一个 WAL 记录长度是 8 字节,每个 WAL 段文件默认为 16MB。一个 WAL 段可以记录将近 200 万事务。而如果存储 8KB 大小的数据块,只能储存 2048 个。就会导致 WAL 的写入量是非常大的。

 

全页写特点

  • 全页写的概念

    将整个数据块写入到 WAL 日志文件中。

  • 全页写的优点

    提高数据库的安全性,解决块不一致问题。

  • 全页写的缺点

    导致 WAL 日志膨胀;

    增加额外的磁盘 I/O,影响数据库整体性能;

    导致主备延迟变大。

  • 全页写的控制

    full_page_writes(默认 on)。

 

全页写的模式

1)非强制模式

对于修改操作,当启用全页写时,pg 会在每个检查点之后、每个页面第一次发生变更时,将头数据和整个页面作为一条 WAL 记录写入 WAL 缓冲区。

  • 最近一次检查点之后,第一次修改的数据块会进行全页写,后续再修改时不会进行全页写,直到下一次检查点发生。

2)强制模式

对于备份操作,强制启用全页写,只要块发生变化,就会被整块写入 WAL 文件(不管是不是第一次,也不管有没有检查点)。因此,它写入的量是更大的。

  • 当用 pg_basebackup 对数据库进行备份时,会自动执行强制模式,在备份期间被修改的数据块会全部写入 WAL 当中。

  • pg_start_backup 命令,对应函数 do_pg_start_backup(xlog.c 文件),其中开启强制全页写。

pg_stop_backup 对应的函数 do_pg_stop_backup,有一句关闭强制全页写。

因此手动执行 pg_start_backup 命令之后,备份完一定要执行 pg_stop_backup,避免 WAL 暴增

建议数据库备份时间点选在业务空闲时间段进行。

块不一致的场景

对 PostgreSQL 来说,块不一致可以发生在两种场景:

  • PG 异常宕机(或者出现磁盘错误)时,数据文件中的页只写入了一部分。

  • 使用操作系统命令备份正在运行的数据库,备份途中源数据库可能被修改,此时得到的备份数据状态就是不一致的

无论是崩溃恢复还是备份还原的恢复,都无法基于不一致的数据块进行。

块不一致的原因

  • 操作系统进行 I/O 操作时,总是以块为单位,比如 512 字节、1KB 等等。

  • 数据库块一般是操作系统块的整数倍,比如 2k、4k、8k 等等。

  • 块是数据库最小的 I/O 单位,当数据库写一个数据块时,操作系统需要 I/O 多次,可能在 I/O 过程中系统断电、磁盘故障等等原因导致一个数据块没有完整的写入,导致块不一致。

 

块不一致恢复

崩溃恢复

  • 通过 checksum 发现 “部分写” 的数据页,并将 wal 中保存的这个完整数据页覆盖当前损坏的数据页,然后再继续 redo 恢复整个数据库。

备份恢复

  • restore 阶段,会直接还原不一致的块;但在 recover 阶段,会直接用 WAL 中一致的块对其进行覆盖,然后开始应用日志。

 

参考:postgresql源码学习(34)—— 事务日志⑩ - 全页写机制_postgresql源码数据页学习-CSDN博客

 

posted on 2024-04-22 15:55  太白金星有点烦  阅读(23)  评论(0编辑  收藏  举报

导航