PostgreSQL检查点(checkpoint)详解

checkpoint简单点说就是一个数据库事件,用来保证数据一致性和完整性。
当我们在数据库中执行checkpoint时,就会将其之前的脏数据刷到磁盘,从而实现数据缩短数据库崩溃恢复时间的目的。

例如当我们更新任何数据的时候,对应于包含该数据的块将在shared buffers中更新。所做更改的记录保存在wal缓冲区中。提交后,我们所做的更改将被写入磁盘上的wal文件,从而使它们永久生效。如果实例立即崩溃,则将清除数据库共享缓冲区,但是在重新启动数据库时,PostgreSQL将把WAL文件中记录的更改应用于相应的数据文件。

那么当我们提交事务的时候,为什么不直接将数据写到磁盘呢?

原因很简单:
1、如果直接写入数据文件,那么必须要先在数据文件中定位到该数据块,然后才能进行数据的更新,这就意味着当用户提交后需要一直等待,这会对性能产生很大影响;
2、WAL日志的写入是顺序的,而数据文件的写入是随机的,磁盘的随机IO性能更差。

而在实际应用中,执行checkpoint往往是个漫长的过程。因为做检查点时,需要将执行命令前已提交事务的事务状态和脏数据都写入持久化存储,这个需要一个过程,这些刷脏页面和CLOG的动作同样会产生XLOG,那么又该如何保证数据的一致性呢?

其实这个过程对于数据恢复来说并不影响,在做数据恢复时,先找到检查点结束的XLOG位置,然后根据这里的结束检查点时写入的XLOG信息找到开始的位置,然后读取XLOG并实施xlog replay恢复,至少要恢复到检查点结束的XLOG位置才能保证数据的一致性和完整性。
在这里插入图片描述
说了这么多,那么什么时候数据库才会进行checkpoint呢?
主要有以下情况:

  • 超级用户手动执行checkpoint命令
  • 参数checkpoint_timeout中指定的间隔(默认300秒)
  • 写入WAL的数据量已达到参数max_wal_size(默认值:1GB)
  • online backup开始的时候
  • 执行pg_start_backup函数时
  • 在实例关闭时(除了pg_ctl stop -m命令执行)
  • 在进行数据库配置时(例如CREATE DATABASE / DROP DATABASE语句)

当执行checkpoint时,数据库主要完成以下几个工作:
识别shared buffers中所有的脏页
将脏页写入相应的数据文件
确保修改后的文件通过fsync()写入到磁盘

注意:fsync()函数用于强制从缓冲区高速缓存中物理写入数据,并确保在系统崩溃或其他故障之后,直到fsync()调用时的所有数据都记录在磁盘上。

checkpoint相关的参数:

1、checkpoint_timeout:
这是自动WAL检查点之间的最长时间(默认为5分钟)。增加此参数可能会增加崩溃恢复所需的时间。

2、max_wal_size:
使WAL增长到自动WAL检查点之间的最大大小。默认值为1 GB。增大此参数可能会增加崩溃恢复所需的时间。

如果我们同时设置了这两个参数,则检查点将以先到者为准。

3、min_wal_size:
只要WAL磁盘使用率保持低于此设置,旧的WAL文件将始终在检查点被回收以备将来使用,而不是被删除。这可以用来确保保留足够的WAL空间来处理WAL使用率的峰值,例如在运行大型批处理作业时。 (默认为80 MB)

4、checkpoint_completion_target :
由于每5分钟或达到每个max_wal_size阈值都会发生一次检查点,因此在检查点时间内,共享缓冲区中存在的所有脏页将被刷新到磁盘,从而导致巨大的IO。
checkpoint_completion_target来这里进行救援。
这会使刷新速度变慢,这意味着PostgreSQL应该花费checkpoint_completion_target * checkpoint_timeout的时间来写入数据。
例如,如果我的checkpoint_completion_target为0.5,并且数据库将限制写入,以便最后写入在2.5分钟后完成。

5、wal_buffers :
用于尚未写入磁盘的WAL数据的共享内存量。默认设置为-1,选择的大小等于shared_buffers的1/32(大约3%),但不小于64kB,也不大于一个WAL段的大小,通常为16MB。

6、checkpoint_flush_after:
在执行检查点时,只要写入的字节数超过checkpoint_flush_after,则尝试强制OS将这些写入操作刷到存储中。这样做将限制内核页面缓存中的脏数据量,从而减少在检查点末尾发出fsync时停顿的可能性。
此设置在某些平台上可能无效。

checkpoint例子:
这里用一张表来演示checkpoint的过程。
查看该表:

pg13@cnndr4pptliot-> oid2name -d bill -t t1
From database "bill":
  Filenode  Table Name
----------------------
     16913          t1

更新表中数据:

bill@bill=>update t1 set c2='bill' where c1=2;
UPDATE 1

查看页面状态,发现被标记为脏页:

bill@bill=>SELECT reldatabase,relfilenode,isdirty FROM pg_buffercache WHERE relfilenode='16913';
 reldatabase | relfilenode | isdirty
-------------+-------------+---------
       16385 |       16913 | t
(1 row)

执行checkpoint,再次查看:

bill@bill=>checkpoint ;
CHECKPOINT
bill@bill=>SELECT reldatabase,relfilenode,isdirty FROM pg_buffercache WHERE relfilenode='16913';
 reldatabase | relfilenode | isdirty
-------------+-------------+---------
       16385 |       16913 | f
(1 row)

查看数据库日志:

 2020-11-11 16:07:04.128 CST,,,31666,,5f881bd9.7bb2,109,,2020-10-15 17:52:25 CST,,0,LOG,00000,"checkpoint starting: immediate force wait",,,,,,,,"LogC    heckpointStart, xlog.c:8548","","checkpointer"
 
 2020-11-11 16:07:04.139 CST,,,31666,,5f881bd9.7bb2,110,,2020-10-15 17:52:25 CST,,0,LOG,00000,"checkpoint complete: wrote 1 buffers (0.0%); 0 WAL file    (s) added, 0 removed, 0 recycled; write=0.002 s, sync=0.001 s, total=0.010 s; sync files=1, longest=0.001 s, average=0.001 s; distance=0 kB, estimate    =775 kB",,,,,,,,"LogCheckpointEnd, xlog.c:8630","","checkpointer"

总结:
1、Checkpointer进程会定期根据配置将共享缓冲区中的脏缓冲区写入相应的数据文件。
2、checkpoint_timeout和max_wal_size是配置检查点时必须注意的两个重要方面

参考链接:
https://postgreshelp.com/postgresql-checkpoint/

猜你喜欢

转载自blog.csdn.net/weixin_39540651/article/details/109625252