25.3. WAL 配置

有几个与 WAL 相关的参数会影响数据库性能。 本节讨论它们的使用。参阅 Section 16.4 获取配置参数的细节。

检查点(Checkpoints) 是事务序列中的点, 我们保证在该点之前的所有日志信息都更新到数据文件中去了。 在检查点时,所有脏数据页都冲刷到磁盘并且向日志文件中写入一条特殊的检查点记录。 结果是,在发生崩溃的时候,恢复器就知道应该从日志中的哪条记录(称做 redo 记录)开始做 REDO 操作, 因为在该记录前的对数据文件的任何修改都已经在磁盘上了。 在完成检查点处理之后,任何在 redo 记录之前写的日志段都不再需要, 因此可以循环使用或者删除。(到基于 WALBAR (备份和恢复)实现的时候, 这些日志在循环利用或者删除之前将先归档。)

服务器每隔一段时间就派生一个特殊的进程以创建下一个检查点。 每隔 checkpoint_segments 个日志段就创建一个检查点, 或者每隔 checkpoint_timeout 秒创建一个。 以先到为准。缺省设置分别是 3 个段和 300 秒。 我们也可以用 SQL 命令 CHECKPOINT 强制一个检查点。

减少 checkpoint_segments 和/或 checkpoint_timeout 会令检查点更频繁一些。 这样就允许更快的崩溃后恢复(因为需要重做的工作更少)。不过, 我们必须在这个目的和更频繁地冲刷脏数据页所带来的额外开销之间取得平衡。 另外,为了保证数据页的一致性,在每个检查点之后的第一次数据页的变化会导致对整个页面内容的日志记录。 因此,检查点时间间隔短了会导致输出到日志中的数据的增加,会抵销一部分缩短间隔的目标, 并且怎么着都会产生更多的磁盘 I/O。

至少会有一个 16MB 的段文件,而且通常不会超过 2 * checkpoint_segments + 1 个文件。你可以用这些信息来估计 WAL 需要的空间。 通常,如果一个旧的日志段文件不再需要了,那么它将得到循环使用(重命名为顺序的下一个可用段)。 如果由于短期的日志输出峰值,导致了超过 2 * checkpoint_segments + 1 个段文件, 那么到系统再次回到这个限制之内的时候,多于的段文件会被删除,而不是循环使用。

有两个常用的 WAL 函数: LogInsertLogFlushLogInsert 用于向共享内存中的 WAL 缓冲区里加一条新的记录。如果没有空间存放新记录, 那么LogInsert 就不得不写出(向内核缓存里写)一些填满了的WAL缓冲。 我们可不想这样,因为 LogInsert 用于每次数据库低层修改(比如,记录插入), 都要花在受影响的数据页上持有一个排它锁的时间,因为该操作需要越快越好;更糟糕的是, 写 WAL 缓冲可能还会强制创建新的日志段, 它花的时间甚至更多。通常,WAL 缓冲区应该由一个 LogFlush 请求来写和冲刷, 在大部分时候它都是发生在事务提交的时候以确保事务记录被冲刷到永久存储器上去了。在那些日志输入量比较大的系统上, LogFlush 请求可能不够频繁,这样就不能避免 WAL 缓冲区被 LogInsert 写。在这样的系统上,我们应该通过修改配置参数 wal_buffers 的值来增加 WAL 缓冲区的数量。缺省的 WAL 缓冲区数量是 8。 增加这个数值将有对应的共享内存使用量的增加。

检查点是开销相当昂贵的操作,因为它们用操作系统的 sync() 调用强制所有脏的内核缓冲刷新到硬盘上。 繁忙的服务器可能会很快就把检查点段文件填满, 导致额外的检查点。如果这样的强制检查点发生的频率比 checkpoint_warning 秒要频繁,那么将在服务器日志里输出一条信息,建议你增加 checkpoint_segments

commit_delay 定义了后端在使用 LogInsert 向日志中写了一条已提交的记录之后, 在执行一次 LogFlush 之前休眠的毫秒数。 这样的延迟可以允许其它的后端把它们提交的记录追加到日志中,这样就可以用一次日志同步把所有日志冲刷到日志中。 如果没有打开fsync或者当前少于 commit_siblings 个其它后端处于活跃事务状态的时候则不会发生休眠; 这样就避免了在其它事务一时半会不会提交的情况下睡眠。 请注意在大多数平台上,休眠要求的分辩率是十毫秒, 所以任何介于 1 和 10000 微秒之间的非零 commit_delay 的作用都是一样的。 适用这些参数的比较好的数值还不太清楚;我们鼓励你多做试验。

wal_sync_method 参数决定PostgreSQL 如何请求内核强制将 WAL 更新输出到磁盘。只要满足可靠性,那么所有选项应该都是一样的,但是哪个最快则可能和平台密切相关。 请注意如果你关闭了 fsync,那么这个参数就无所谓了。

wal_debug 参数设置为任何非零值都会导致每次 LogInsertLogFlush WAL 调用都被记录到服务器日志。目前,这个非零值是多少没有什么区别。这个选项以后可能会被更通用的机制取代。