读了很多PostgreSQL的FullPageWrite过程,结果思考时把自己绕进去了。每次感觉读懂了,但是都没能理解,其实是一个很简单的逻辑。
全页写发生在PG的Checkpoint时候,不要过于考虑全页写在checkpoint中的过程,而是单纯思考其作用,其实很好解。
假设没开启全页写的场景下,在checkpoint完成之后,后续数据库持续读写,然后bgwriter的向底层刷脏,某个时刻刷脏异常断电,导致磁盘的页只写了部分,数据页异常不完整了。然后数据库重启之后,从redo点开始回放wal,从上次redo点开始回放,但是磁盘上的数据页本身就不完整,如何能回放成功呢?所以在每次checkpoint成功之后,第一次数据页的修改的wal日志中,对整个数据页进行备份,写到wal中。这样后续即便数据库运行过程中出现部分页写,数据页不完整的情况,那么后续起来后,反正从redo点开始回放,而回放的同时,会发现wal中有备份块,那么就会覆盖页面内容,这样也就能保证数据一致了。
问:如果checkpoint过程中崩溃了怎么办?
这也不是问题,因为redo点只有在checkpoint成功后才会记录到pg_controldata文件中,在checkpoint过程中崩溃了,下次启动时,从上次checkpoint生成的redo点开始回放,因为上次的checkpoint完成redo点之后针对数据页第一次的修改都保存了全量数据,所以用wal中的数据页块直接覆盖本地的数据页,然后一步步回放至最近的wal记录,这样保证了数据库的一致性。