PostgreSQL full_page_writes与checkpoint

245 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路


我们都知道数据库中出现故障时都会去从最近一次的checkpoint开始应用wal日志进行恢复。那么checkpoin越频繁我们恢复就会越快,当然checkpoint也会对IO产生一些影响,不过一般在磁盘性能允许的情况下,还是建议checkpoint越频繁越好。

但是在PostgreSQL中却并不如此,相较于其它的一些数据库,PG中会更希望checkpoint越晚越好,这是为什么呢?主要还是和pg中的full_page_writes机制有关了。

full_page_writes是什么呢?简单点来说,因为pg中数据页最小是8k,而操作系统一般默认一个数据块是4k,那么当我们数据刷盘的时候可能会出现一个数据页8k只刷了一半到磁盘中然后数据库出现了故障,从而导致数据文件损坏。

我们可以从下图中来看看什么是full_page_writes(图片摘自The Internals of PostgreSQL)

在这里插入图片描述

所谓full_page_writes,即在checkpoint后,每个页面第一次发生变更时,会将整个页面写入到wal日志中。为什么这样就能避免前面说的页面损坏情况呢?我们从数据恢复的步骤来分析下:

1、执行checkpoint;
2、PageA中插入一条数据,wal日志将整个页面全部写入;
3、事务提交,wal日志写入磁盘;
4、PageA中再插入另一条数据,wal日志写入该记录;
5、事务提交,wal日志写入磁盘;
6、数据刷盘,但是PageA写入一半后数据库出现故障,PageA损坏。

接下来我们便需要通过wal日志来进行恢复,有了full_page_writes,那么恢复步骤大致如下:

1、读取PageA中写入第一条数据时的wal日志,发现整个页面都在,
2、通过wal日志将整个PageA覆盖原来已损坏的PageA,注意该步骤不会去比较PageA的LSN和wal日志中的LSN;
3、进行读取接下来的wal日志进行数据恢复。

从上面我们可以看出,有了full_page_writes自然就不会出现page损坏的情况了,但是缺点很明显,每次checkpoint后发生变化的页面都会全部写到wal日志中,如果在事务频繁的库中wal日志的产生量将会相当巨大,因此pg中会尽可能的希望checkpoint更晚。

除此之外,开启full_page_writes也会对性能产生一定的影响(大致在10%~30%),不过大多数情况下我们的系统还没必要追求完美的性能,而多了一层数据保护总不是坏事。

当然,如果操作系统本身支持文件系统的原子写,例如ZFS文件系统,那么也不太需要通过数据库来对数据块进行保护了,自然可以关闭full_page_writes。