PgSQL · 特性分析 · checkpoint机制浅析

背景

上期月报PgSQL · 特性分析 · Write-Ahead Logging机制浅析中简单介绍了PostgreSQL中WAL机制,其中讲到如果是创建checkpoint会触发刷新xlog日志页到磁盘,本文主要分析下PostgreSQL中checkpoint机制。

checkpoint又名检查点,一般checkpoint会将某个时间点之前的脏数据全部刷新到磁盘,以实现数据的一致性与完整性。目前各个流行的关系型数据库都具备checkpoint功能,其主要目的是为了缩短崩溃恢复时间,以Oracle为例,在进行数据恢复时,会以最近的checkpoint为参考点执行事务前滚。而在WAL机制的浅析中,也提过PostgreSQL在崩溃恢复时会以最近的checkpoint为基础,不断应用这之后的WAL日志。

检查点发生时机

在xlog.h文件中,有如下代码对checkpoint进行了相应的分类:

/*
 * OR-able request flag bits for checkpoints.  The "cause" bits are used only
 * for logging purposes.  Note: the flags must be defined so that it's
 * sensible to OR together request flags arising from different requestors.
 */

/* These directly affect the behavior of CreateCheckPoint and subsidiaries */
#define CHECKPOINT_IS_SHUTDOWN	0x0001	/* Checkpoint is for shutdown */
#define CHECKPOINT_END_OF_RECOVERY	0x0002		/* Like shutdown checkpoint,
												 * but issued at end of WAL
												 * recovery */
#define CHECKPOINT_IMMEDIATE	0x0004	/* Do it without delays */
#define CHECKPOINT_FORCE		0x0008	/* Force even if no activity */
/* These are important to RequestCheckpoint */
#define CHECKPOINT_WAIT			0x0010	/* Wait for completion */
/* These indicate the cause of a checkpoint request */
#define CHECKPOINT_CAUSE_XLOG	0x0020	/* XLOG consumption */
#define CHECKPOINT_CAUSE_TIME	0x0040	/* Elapsed time */
#define CHECKPOINT_FLUSH_ALL	0x0080	/* Flush all pages, including those
										 * belonging to unlogged tables */

也就是说,以下几种情况会触发数据库操作系统做检查点操作:

  1. 超级用户(其他用户不可)执行CHECKPOINT命令
  2. 数据库shutdown
  3. 数据库recovery完成
  4. XLOG日志量达到了触发checkpoint阈值
  5. 周期性地进行checkpoint
  6. 需要刷新所有脏页

为了能够周期性的创建检查点,减少崩溃恢复时间,同时合并I/O,PostgreSQL提供了辅助进程checkpointer。它会对不断检测周期时间以及上面的XLOG日志量阈值是否达到,而周期时间以及XLOG日志量阈值可以通过参数来设置大小,接下来介绍下与checkpoints相关的参数。

与检查点相关参数

  • checkpoint_segments

    • WAL log的最大数量,系统默认值是3。超过该数量的WAL日志,会自动触发checkpoint。
  • checkpoint_timeout
    • 系统自动执行checkpoint之间的最大时间间隔。系统默认值是5分钟。
  • checkpoint_completion_target
    • 该参数表示checkpoint的完成时间占两次checkpoint时间间隔的比例,系统默认值是0.5,也就是说每个checkpoint需要在checkpoints间隔时间的50%内完成。
  • checkpoint_warning
    • 系统默认值是30秒,如果checkpoints的实际发生间隔小于该参数,将会在server log中写入写入一条相关信息。可以通过设置为0禁用。

创建检查点具体过程

CreateCheckPoint具体过程

当PostgreSQL触发checkpoint发生的条件后,会调用CreateCheckPoint函数创建具体的检查点,具体过程如下:

  1. 遍历所有的数据buffer,将脏页块状态从BM_DIRTY改为BM_CHECKPOINT_NEEDED,表示这些脏页将要被checkpoint刷新到磁盘
  2. 调用CheckPointGuts函数将共享内存中的脏页刷出到磁盘
  3. 生成新的Checkpoint 记录写入到XLOG中
  4. 更新控制文件、共享内存里XlogCtl的检查点相关成员、检查点的统计信息结构

PostgreSQL 控制文件pg_control里存储的数据是一个ControlFileData结构,具体如下:

typedefstruct ControlFileData
{
    uint64    system_identifier;
    uint32    pg_control_version;     /*PG_CONTROL_VERSION */
    uint32    catalog_version_no;     /* seecatversion.h */
    DBState      state;       /* see enum above */
    pg_time_t time;        /* time stamp of last pg_control update */

        XLogRecPtr	checkPoint;		/* 最近一次创建checkpoint的LSN*/
        XLogRecPtr	prevCheckPoint; /* 最近一次之前创建checkpoint的LSN */
        /*由于一个检查点的时间比较长,所以有可能系统在所有页面写完之前崩溃,这样磁盘上的检查点可能是不完全的,因此将最后一个完全检查点位置写在prevCheckPoint上*/

	CheckPoint	checkPointCopy; /* 最近一次checkpoint对应的CheckPoint对象 */

	XLogRecPtr	minRecoveryPoint;
	TimeLineID	minRecoveryPointTLI;
	XLogRecPtr	backupStartPoint;
	XLogRecPtr	backupEndPoint;
	bool		backupEndRequired;
   ......

其中,minRecoveryPoint和minRecoveryPointTLI确定数据库启动前,如果做归档恢复,我们必须恢复到的最小检查点。其中minRecoveryPoint指向该检查点对应的LSN位置,minRecoveryPointTLI指向该检查点对应的时间线。其具体的用法,我们将在之后的PostgreSQL崩溃恢复中分析,这里我们主要分析下PostgreSQL中的时间线概念。

PostgreSQL中WAL日志段名称,由时间线ID、日志ID、段ID的八位16进制数依次构成。例如:

00000001 00000001 0000008F
时间线TimeLineID 逻辑日志ID 段ID

其中时间线是作为日志段名称的一部分,用来标识数据库归档恢复后产生的一系列新的WAL记录。在每次归档恢复完成后,都会产生一个新的时间线和新的WAL日志段。时间线可以理解为平行时空中的各个平行宇宙,我们完全可以恢复到某个时间点,重开一条时间线,继续进行数据操作,这样就可以实现完全的PTIR。

在PostgreSQL中,一个新的时间线产生,系统伴随它会建立一个以“新TimeLineID+.history”命名的“时间线历史”文件(timeline history),它是一个类似于txt的文件,其中包含所有在当前时间线以前的时间线,同时记录了每个时间线开始时的第一个WAL段,这样数据库恢复时,通过读取时间线历史文件文件,根据目标时间点可以快速找到正确的日志段文件。如果上一次恢复是恢复到具体某时刻,在时间线历史文件中还会记录该时间线对应的具体时刻。

在PITR恢复时,无需扫描所有WAL日志文件,而是通过时间线直接定位某个WAL段,再从该WAL段中找到符合该时间点的日志记录,这样就大大提高了效率。同时数据库恢复时,默认是沿着基备份开始时的时间点进行,即利用从基备份完成后产生的第一个日志段文件做恢复,如果想恢复到指定时间点(时间线),需要在recovery.conf配置文件中设置目标时间线(target timeline ID),但是target timeline ID不能指定为基备份以前的时间线。

CheckPointGuts函数

CheckPointGuts函数将共享内存里的数据刷出并文件同步到磁盘,具体定义如下:

staticvoid
CheckPointGuts(XLogRecPtrcheckPointRedo,int flags)
{
   CheckPointCLOG();
   CheckPointSUBTRANS();
   CheckPointMultiXact();
   CheckPointPredicate();
   CheckPointRelationMap();
   CheckPointBuffers(flags);   /* performs all required fsyncs */
   /* We deliberately delay 2PC checkpointingas long as possible */
   CheckPointTwoPhase(checkPointRedo);
}

可以看出,CheckPointGuts根据不同的缓存类型,把clog、subtrans、multixact、predicate、relationmap、buffer(数据文件)和twophase相应缓存分别调用不同的方法,将缓存刷到磁盘中:

  • 提交事务日志管理器的方法CheckPointClog
  • 子事务日志管理器的方法CheckPointSUBTRANS
  • 多事务日志管理器的方法CheckPointMultiXact
  • 支持序列化事务隔离级别的谓词锁模块的方法CheckPointPredicate
  • 目录/系统表到文件节点映射模块的方法CheckPointRelationMap
  • 缓存管理器的方法CheckPointBuffers
  • 两阶段提交模块的方法CheckPointTwoPhase

其中,前四个函数最后都调用了SLRU模块的SimpleLruFlush(简单最近最少使用)方法,把相应的共享内存数据写到磁盘,并通过调用pg_fsync方法把相应文件刷到磁盘上对应文件。

后二个函数没有使用SLRU算法,直接调用pg_fsync方法把相应文件刷到磁盘上对应文件。

而目录/系统表到文件节点映射模块的方法CheckPointRelationMap,会将共享内存里系统表和对应物理文件映射的map文件刷到磁盘。

总结

至此,我们大体了解了checkpoint的用法和整个实现过程,但是还需要对一些特别的地方做出说明。

  • 每个检查点后,第一次数据页的变化会导致整个页面会被记录在XLOG日志中
  • 检查点的开销比较高,可以用checkpoint_warning自检,相应调大checkpoint_segments
  • 检查点的位置保存在文件 pg_control,pg_control文件被损坏可能会导致数据库不可用

其中,如果pg_control文件损坏,在数据库崩溃恢复时可能出现一些问题,这些问题我们将在分析PostgreSQL数据库崩溃恢复时具体分析。

时间: 2024-05-19 10:49:37

PgSQL · 特性分析 · checkpoint机制浅析的相关文章

PgSQL · 特性分析 · MVCC机制浅析

背景 我们在使用PostgreSQL的时候,可能会碰到表膨胀的问题(关于表膨胀可以参考之前的月报),即表的数据量并不大,但是占用的磁盘空间比较大,查询比较慢.为什么PostgreSQL有可能发生表膨胀呢?这是因为PostgreSQL引入了MVCC机制来保证事务的隔离性,实现数据库的隔离级别. 在数据库中,并发的数据库操作会面临脏读(Dirty Read).不可重复读(Nonrepeatable Read).幻读(Phantom Read)和串行化异常等问题,为了解决这些问题,在标准的SQL规范中

PgSQL · 特性分析 · 数据库崩溃恢复(上)

背景 为了合并I/O提高性能,PostgreSQL数据库引入了共享缓冲区,当数据库非正常关闭,比如服务器断电时,共享缓冲区即内存中的数据就会丢失,这个时候数据库操作系统重启时就需要从非正常状态中恢复过来,继续提供服务.本文将具体分析在这种情况下,PostgreSQL数据库如何从崩溃状态中恢复. 上期月报PgSQL · 特性分析 · checkpoint机制浅析中介绍了PostgreSQL中的checkpoint机制.其中提到,当PostgreSQL数据库崩溃恢复时,会以最近的checkpoint

PgSQL · 特性分析 · 数据库崩溃恢复(下)

背景 在上期月报PgSQL · 特性分析 · 数据库崩溃恢复(上),我们分析了PostgreSQL在数据库非正常退出后(包括通过recovery.conf用户主动恢复)的处理,概括起来分为以下几步: 1.如果满足以下条件之一,则进行非正常退出恢复 pg_control文件中的数据库状态不正常(非DB_SHUTDOWNED) pg_control文件中记录的最新检查点读取不到XLOG日志文件 2.用户指定recovery.conf文件主动恢复3.根据pg_control.backup_label确

PgSQL · 特性分析 · Write-Ahead Logging机制浅析

WAL机制简介 WAL即 Write-Ahead Logging,是一种实现事务日志的标准方法.WAL 的中心思想是先写日志,再写数据,数据文件的修改必须发生在这些修改已经记录在日志文件中之后.采用WAL日志的数据库系统在事务提交时,WAL机制可以从两个方面来提高性能: 多个client写日志文件可以通过一次 fsync()来完成 日志文件是顺序写的,同步日志的开销要远比同步数据页的开销要小 总体来说,使用了WAL机制之后,磁盘写操作只有传统的回滚日志的一半左右,大大提高了数据库磁盘I/O操作的

PgSQL · 特性分析 · full page write 机制

PG默认每个page的大小为8K,PG数据页写入是以page为单位,但是在断电等情况下,操作系统往往不能保证单个page原子地写入磁盘,这样就极有可能导致部分数据块只写到4K(操作系统是一般以4K为单位),这些"部分写"的页面包含新旧数据的混合.在崩溃后的恢复期间,xlog 里面存储的记录变化信息不够完整,无法完全恢复该页.PG为了解决这类问题,full_page_write机制孕育而生. 什么是full_page_write? PostgreSQL 在 checkpoint 之后在对

PgSQL · 特性分析 · 备库激活过程分析

前言 PostgreSQL standby 可以通过两种方法来激活成为主库: trigger file,配置在recovery.conf中. pg_ctl promote发送SIGUSR1信号给postmaster进程. 同时,PostgreSQL支持快速激活(fast promote)和非快速激活(fallback promote): fast promote 开启数据库读写前,不需要做检查点.而是推到开启读写之后执行一个CHECKPOINT_FORCE检查点. fallback_promot

PgSQL · 特性分析· JIT 在数据仓库中的应用价值

背景 近几年,分析型数据库中有项技术得到了广泛的应用.它就是 JIT(Just-in-time compilation)动态编译.还有一些相关名词 LLVM codegen 和这项技术相关.本文把这项技术做一个简单的分析,和大家分享. 一.JIT 是什么 长久以来数据仓库都是以高效的处理量数据的能力著称.随着硬件的发展,他们使用大量相关技术充分挖掘硬件的能力提高数据的吞吐量和处理效率.例如 SMP MPP mapreduce 列存储 压缩 等等.这么多年开源生态的活跃,使得我们对这类技术的实现细

PgSQL · 特性分析 · 时间线解析

"时间线"(Timeline)是PG一个很有特色的概念,在备份恢复方面的文档里面时有出现.但针对这个概念的详细解释却很少,也让人不太好理解,我们在此仔细解析一下. 时间线的引入 为了理解引入时间线的背景,我们来分析一下,如果没有时间线,会有什么问题?先举个将数据库恢复到以前时间点的例子.假设在一个数据库的运行过程中,DBA在周三12:00AM删掉了一个关键的表,但是直到周五中午才发现这个问题.这个时候DBA拿出最初的数据库备份,加上存在归档目录的日志文件,将数据库恢复到周三11:00A

PgSQL · 特性分析 · PostgreSQL 9.6 如何把你的机器掏空

背景 PostgreSQL 在向和纵向的扩展能力在开源数据库中一直处于非常领先的地位,例如今年推出的9.6,内置了sharding的功能,同时在scale-up的能力也有非常明显的提升,特别是在多核与高并发处理这块. 社区有同学在128核的机器上测试tpc-b的select only模式可以达到几百万的qps,机器的CPU资源被吃光光. 天下大势,分久必合,合久必分.谈了这么多年的sharding,业务也妥协了这么多年(比如不允许跨shard JOIN,忍受分片不平衡的痛楚,必须要有分区键值,分