作者:瀚高PG实验室 (Highgo PG Lab)
WAL的定义
PostgreSQL中事务被保存的记录叫做预写日志(WAL)。当内存中的数据页被修改时,相应的变化会被记录到WAL中。
WAL是一种确保数据完整性的标准方法。WAL的核心理念就是对数据文件的更改必须在相关更改被记录之后才能写入,也就是说,在日志记录描述这些更改已经被刷新到永久存储设备中之后。使用这种方式后,我们就不需要在每次事务提交的时候把数据页刷新到磁盘中。
使用WAL会使磁盘写入的数量显著下降,因为只有日志文件(而不是每个被事务更改的数据文件)需要被刷新到磁盘来保证一个事务被提交。日志文件是顺序写的,所以同步日志的开销比刷新数据页的开销少的多。
检查点的定义
检查点是在事务序列中的点,它保证了堆和索引数据文件在检查点之前被更新写入所有信息。发生检查点时,所有的脏数据页被刷新到磁盘中,一条特殊的检查点记录会被写入日志文件中。发生崩溃时,崩溃恢复进程查看最近的检查点记录,来决定从日志中的哪个点开始REDO操作。在这个点之前对数据文件的任何更改会被确保已写入磁盘。因此,在一个检查点之后,在包含REDO记录的日志段之前的日志段将不再被需要,可以回收或移除。当WAL归档完成时,日志段必须在被回收或移除之前进行归档。
把页面统一到磁盘上所需的时间是变化的,这是因为磁盘的刷新发生在以下这些特定的情况中:
1、当持有页面的缓冲区被缓冲区管理程序请求时。
2、当后台写进程写入页面时。
3、当发生一个检查点时。
PostgreSQL中WAL文件的大小固定为16MB。这些文件的管理必须是完全自动的,我们不能碰,除非你想破坏数据。
检查点是一个常见的进程,它几乎可以存在于任何数据库技术中。当检查点启动之后,进程扫描共享缓冲区,写入所有发现的脏页。最后提交的事务的WAL位置被保存在此文件中:$PGDATA/global/pg_control。通过这种方式,操作系统就会知道哪一个WAL文件是不被崩溃恢复所需要的,从而进行回收和删除。
在完成一个检查点和刷新日志之后,检查点的位置会被保存到pg_control中。因此,在恢复的开始,服务器首先读取pg_control,然后读取检查点记录,接着它通过从检查点记录中记录的日志的位置向前扫描执行REDO操作。因为整个数据页的内容被保存到一个检查点之后的第一个页更改日志中,从检查点以来所有改变的页面都会恢复到一个一致的状态。
pg_control这个文件在启动过程中被postgres进程用于确定集群是否需要进行恢复。如果要进行恢复,那么最后一个检查点的位置会被用于恢复的开端。在恢复的结尾和向连接打开数据库之前,操作系统会执行一个检查点来把所有重做的变化刷新到磁盘上。
Trade-off
频繁的出现检查点会导致不必要的I/O,而很少有检查点会导致如果发生crash,恢复所需的时间会很长。优化检查点的频率是在空间和时间这两方面之间的一种妥协。
PostgreSQL一直到9.4版本都是使用checkpoint_segments来表明在一个检查点被触发之前,新的事务生成的WAL segment的数量。此参数还控制着保存在WAL目录中最少的log文件的数量。但9.5版本开始,为了防止混淆,这个参数被替换为max_wal_size。
PostgreSQL的预写日志让检查点和正在运行的事务在最小的干扰下共处。WAL segments 被按顺序写入,他们的名字是不重复的。
By Kalath