26.3. WAL 配置

有几个与 WAL 相关的参数会影响数据库性能。 本节讨论它们的使用。参阅 Chapter 17 获取有关服务器配置参数的一般信息。

检查点(Checkpoints) 是事务序列中的点, 我们保证在该点之前的所有信息都写到数据文件中去了。 在检查点时,所有脏数据页都冲刷到磁盘并且向日志文件中写入一条特殊的检查点记录。 在发生崩溃的时候,崩溃恢复过程查找最后的检查点记录,判断应该从日志中的哪个点(称做 redo 记录)开始做 REDO 操作, 该记录前对数据文件的任何修改都被认为已经在磁盘上了。 因此,在检查点完成之后,任何在包含 redo 记录点之前的日志段都不再需要, 因此可以循环使用或者删除。(在进行 WAL 归档的时候, 这些日志在循环利用或者删除之前必须先归档。)

服务器的后端写进程将每隔这段时间就自动执行一个检查点。 每隔 checkpoint_segments 个日志段就创建一个检查点, 或者每隔 checkpoint_timeout 秒创建一个。 以先到为准。缺省设置分别是 3 个段和 300 秒。 我们也可以用 SQL 命令 CHECKPOINT 强制一个检查点。

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

检查点开销相当高,首先是因为它需要写出所有当前脏的缓冲区,其实是因为他们导致上面讨论的额外的后继 WAL 流量。 因此把检查点参数设置得足够高,让检查点发生的频率降低是明智的。要对你的检查点参数的一个简单自检,可以设置 checkpoint_warning 参数。如果检查点发生的间隔接近 checkpoint_warning 秒, 那么将向服务器日志输出一条消息,建议你增加 checkpoint_segments 的数值。 偶尔出现的这样的警告并不会导致警告,但是如果它出现得太频繁,那么就应该增加检查点控制参数。 如果你没有把 checkpoint_segments 设置得足够大, 那么批量操作的时候,比如大批的 COPY 传输会导致出现大量类似的警告消息。

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

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

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

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

打开 wal_debug 配置参数(前提是 PostgreSQL编译的时候打开了这个支持) 将导致每次 LogInsertLogFlush WAL 调用都被记录到服务器日志。这个选项以后可能会被更通用的机制取代。