PostgreSQL的full_page_writes

这篇具有很好参考价值的文章主要介绍了PostgreSQL的full_page_writes。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概念介绍

页断裂

页断裂也可以称为页折断或者半页写。PostgreSQL中,一个page默认为8kb,数据的写入是以page为单位的。而操作系统的一个page往往是4kb或者更小,这将导致PostgreSQL在写一个page到磁盘时,操作系统可能会将PG的一个page,分两次写入到磁盘。 如果系统出现故障,则会出现PG的一个page,操作系统只写了一半到磁盘上,这种现象称之为页折断。

当出现页折断后,页的操作可能只完成了一部分,导致磁盘上的页同时存在新旧数据,这个时候,仅通过wal的数据更改记录,并不足以恢复该页面。

目前市面上的数据库,解决页折断问题,一般有两种方法,一种是full_page_writes,一种是double write。

采用full_page_writes的数据库:

  • PostgreSQL

    采用double write的数据库:

  • openGauss

    • 需结合增量检查点使用;
  • MySQL

full_page_writes

full_page_write是PostgreSQL的GUC参数,如果启用了此参数,在PG执行了checkpoint后,会将Buffer Poll中首次修改的page,整个page连同DML修改语句,都存储到wal日志中。

PostgreSQL官网对其解释如下:
full_page_writes (boolean)
When this parameter is on, the PostgreSQL server writes the entire content of each disk page to WAL during the first modification of that page after a checkpoint. This is needed because a page write that is in process during an operating system crash might be only partially completed, leading to an on-disk page that contains a mix of old and new data. The row-level change data normally stored in WAL will not be enough to completely restore such a page during post-crash recovery. Storing the full page image guarantees that the page can be correctly restored, but at the price of increasing the amount of data that must be written to WAL. (Because WAL replay always starts from a checkpoint, it is sufficient to do this during the first change of each page after a checkpoint. Therefore, one way to reduce the cost of full-page writes is to increase the checkpoint interval parameters.)

Turning this parameter off speeds normal operation, but might lead to either unrecoverable data corruption, or silent data corruption, after a system failure. The risks are similar to turning off fsync, though smaller, and it should be turned off only based on the same circumstances recommended for that parameter.

Turning off this parameter does not affect use of WAL archiving for point-in-time recovery (PITR) (see Section 25.3).

This parameter can only be set in the postgresql.conf file or on the server command line. The default is on.

关键数据结构

XLogRecordBlockImageHeader

记录full-page image的相关信息,该image是否被压缩、在redo过程中,是否应该恢复整个image等信息。

typedef struct XLogRecordBlockImageHeader
{
    uint16        length;         /* number of page image bytes */
    uint16        hole_offset;    /* number of bytes before "hole" */
    uint8        bimg_info;      /* flag bits, see below */
} XLogRecordBlockImageHeader;

其中,bimg_info用于标识image的信息,其有如下取值:

#define BKPIMAGE_HAS_HOLE        0x01        /* page image has "hole" */
#define BKPIMAGE_IS_COMPRESSED        0x02    /* page image is compressed: image是否被压缩 */
#define BKPIMAGE_APPLY        0x04            /* page image should be restored during replay: 重放时,是否需要恢复整个image */

XLogRedoAction

枚举类型,XLogReadBufferForRedo函数的返回值为XLogRedoAction类型;

typedef enum
{
    BLK_NEEDS_REDO,     /* changes from WAL record need to be applied */
    BLK_DONE,           /* block is already up-to-date */
    BLK_RESTORED,       /* block was restored from a full-page image */
    BLK_NOTFOUND        /* block was not found (and hence does not need to be replayed) */
} XLogRedoAction;

DecodedBkpBlock

记录page相关的信息,该信息从xlog的record中解析出来,在redo该条record时,将根据has_image、apply_image等信息,决定是否恢复整个page;

typedef struct
{
    /* Is this block ref in use? */
    bool        in_use;

    /* Identify the block this refers to */
    RelFileNode rnode;
    ForkNumber    forknum;
    BlockNumber blkno;

    /* copy of the fork_flags field from the XLogRecordBlockHeader */
    uint8        flags;

    /* Information on full-page image, if any */
    bool        has_image;    /* has image, even for consistency checking */
    bool        apply_image;  /* has image that should be restored */
    char       *bkp_image;
    uint16        hole_offset;
    uint16        hole_length;
    uint16        bimg_len;
    uint8        bimg_info;

    /* Buffer holding the rmgr-specific data associated with this block */
    bool        has_data;
    char       *data;
    uint16        data_len;
    uint16        data_bufsz;
} DecodedBkpBlock;

full page的写入和恢复流程

数据块的写出和载入

在PostgreSQL数据库中,用户访问或者修改元组时,数据块的载入和写出的层次结构,如下所示:

整页写入

当PostgreSQL修改了内存块,调用XlogInsert接口,记录wal日志时,在XlogRecordAssemble函数中,会判断该page是否为checkpoint后的首次修改,如果是首次修改,则将该page存储到wal文件中。

关键代码如下:

static XLogRecData *
XLogRecordAssemble(RmgrId rmid, uint8 info, XLogRecPtr RedoRecPtr, bool doPageWrites, XLogRecPtr *fpw_lsn)
{
  ...

  /* Determine if this block needs to be backed up */
    if (regbuf->flags & REGBUF_FORCE_IMAGE)
        needs_backup = true;
    else if (regbuf->flags & REGBUF_NO_IMAGE)
        needs_backup = false;
    else if (!doPageWrites)
        needs_backup = false;
    else
    {
        /*
         * We assume page LSN is first data on *every* page that can be
         * passed to XLogInsert, whether it has the standard page layout
         * or not.
         */
        XLogRecPtr    page_lsn = PageGetLSN(regbuf->page);    //通过PageGetLSN函数,获取该page的LSN
        needs_backup = (page_lsn <= RedoRecPtr);             // 将page的LSN,与上次checkpoint的redo点进行比较,如果该page是首次修改,LSN应该小于等于RedoRecPtr
        if (!needs_backup)
        {
            if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
                *fpw_lsn = page_lsn;
        }
    }
  ...
}

整页恢复

从record中,解析出has_image、apply_image:

  1. 当PostgreSQL数据库异常关闭后,再重新启动PG,startup进程进入到故障恢复流程;
  2. 根据pg_control记录的checkpoint信息,结合xlog日志,获取redo点;
  3. 循环从redo点读取wal记录;
  4. 解析wal记录中,获取DecodedBkpBlock结构;
  5. 根据DecodedBkpBlock中的has_image、apply_image等参数,决定是否从WAL中读取image,恢复数据,使PostgreSQL重新达到数据一致性。

rmgr根据资源类型,调用不同的redo函数,重做wal日志:

  • 在redo的时候,资源管理器会根据资源的类型,调用该资源对应的redo函数进行重做;
  • 下面的流程,仅选取heap_redo做流程分析。

部分函数功能说明:文章来源地址https://www.toymoban.com/news/detail-823973.html

  bool DecodeXLogRecord(XLogReaderState *state, XLogRecord *record, char **errormsg)
  功能:从record中,解析出has_image、apply_image等信息;

  bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
  功能:从record中,解析出full-page image;

  #define XLogRecHasBlockImage(decoder, block_id) \    ((decoder)->blocks[block_id].has_image)
  功能:判断是否存储了image;

  #define XLogRecBlockImageApply(decoder, block_id) \    ((decoder)->blocks[block_id].apply_image)
  功能:判断是否需要重放该image;

小结

  • linux下,可使用getconf PAGE_SIZE指令,查看系统的块大小;
  • PostgreSQL的块大小,在编译pg时,可以通过–with-blocksize 参数修改;
  • 启用full_page_writes参数,必然带来性能的损耗,是否启用full_page_writes,需要看存储设备是否能避免半页写的问题,以及是否有其他手段恢复坏块等;

到了这里,关于PostgreSQL的full_page_writes的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM实战(18)——模拟Full GC

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月18日
    浏览(36)
  • JVM实战(15)——Full GC调优

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月17日
    浏览(28)
  • 深入浅出PaddlePaddle函数——paddle.full

    分类目录:《深入浅出PaddlePaddle函数》总目录 相关文章: · 深入浅出PaddlePaddle函数——paddle.Tensor · 深入浅出PaddlePaddle函数——paddle.ones · 深入浅出PaddlePaddle函数——paddle.zeros · 深入浅出PaddlePaddle函数——paddle.full · 深入浅出PaddlePaddle函数——paddle.ones_like · 深入浅出Paddl

    2024年02月06日
    浏览(28)
  • 深入浅出Pytorch函数——torch.full

    分类目录:《深入浅出Pytorch函数》总目录 相关文章: · 深入浅出Pytorch函数——torch.Tensor · 深入浅出Pytorch函数——torch.ones · 深入浅出Pytorch函数——torch.zeros · 深入浅出Pytorch函数——torch.full · 深入浅出Pytorch函数——torch.ones_like · 深入浅出Pytorch函数——torch.zeros_like · 深

    2024年02月07日
    浏览(40)
  • hive表的全关联full join用法

    背景:实际开发中需要用到全关联的用法,之前没遇到过,现在记录一下。需求是找到两张表的并集。 全关联的解释如下; 下面建两张表进行测试 test_a表的数据如下 test_b表的数据如下; 写第一个full join 的SQL进行查询测试 查询结果显示如下; 把两个表的结果拼在一行了,

    2024年02月11日
    浏览(26)
  • TCP Window Full 和 TCP ZeroWindow

    项目现场遇到车在地图上丢失/跳点问题,通过日志发现是OBU给车发送阻塞导致(OBU给车发数据发不动),这里OBU 是TCP Server,车和平板APP是Client。 通过抓包发现如下现象: 192.168.86.110 是OBU,TCP Server 会一直给车/APP发数据。 192.168.86.11 是车。 TCP Window Full :接收方接收缓冲区满

    2024年02月11日
    浏览(22)
  • 安装mmcv-full适配torch版本

    mmcv-full对于torch版本适配有一定的要求,查看链接如下: mmcv-full安装 比如我的cuda版本是10.1,torch版本是1.8.0,安装命令如下

    2024年02月14日
    浏览(23)
  • [SQL挖掘机] - 全连接: full join

    在sql中,join是将多个表中的数据按照一定条件进行关联的操作。全连接(full join)是一种连接类型,它会返回所有满足连接条件的行,同时还包括那些在左表和右表中没有匹配行的数据。 在进行全连接时,会将左表和右表中的所有行进行组合,不管它们是否有匹配的条件。

    2024年02月15日
    浏览(29)
  • Centos 7 出现 write error (disk full?)

    mysql 导入任务时,由于导出的 sql 文件是在很大 (30G),利用 SQLDumpSpliter 切割工具 切成几个 1G 大小的 sql 文件 结果在导入大半天,突然报错 (另一个服务器上更惨,都导入两天快完成的时候,也报错了,那个是 ubuntu 20.04 ,后续再写) 20191230_154230_03.sql: write error (disk full?

    2024年02月13日
    浏览(24)
  • webrtc的FULL ICE和Lite ICE

    分为FULL ICE和Lite ICE: FULL ICE:是双方都要进行连通性检查,完成的走一遍流程。 Lite ICE: 在FULL ICE和Lite ICE互通时,只需要FULL ICE一方进行连通性检查, Lite一方只需回应response消息。这种模式对于部署在公网的设备比较常用。

    2024年02月09日
    浏览(17)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包