25.3. WAL 配置 #
有若干影响数据库性能的与 WAL 相关的配置参数。本节说明它们的用法。设置配置参数的详情请查阅第 16.4 节。
检查点是事务序列中保证数据文件已用检查点之前记录的所有信息更新过的点。在检查点时刻,所有脏数据页被刷写到磁盘,并向日志文件写入一条特殊的检查点记录。结果是,一旦发生崩溃,恢复者就知道应从日志中的哪条记录(称为重做记录)开始 REDO 操作,因为在该记录之前对数据文件所做的任何更改都已在磁盘上。做完检查点之后,重做记录之前写入的任何日志段都不再需要并可被回收或删除。(当实现了基于 WAL 的 BAR 时,日志段在回收或删除之前会被归档。)
服务器每隔一段时间派生一个专门的进程来创建下一个检查点。每
checkpoint_segments 个日志段或每 checkpoint_timeout 秒(以先到者为准)创建一个检查点。默认设置分别是 3 段和 300 秒。也可以用 SQL 命令
CHECKPOINT 强制检查点。
减小 checkpoint_segments 和/或
checkpoint_timeout 会使检查点更频繁。这可以让崩溃后恢复更快(因为需要重做的工作更少)。但必须把这与更频繁地刷写脏数据页的增加的成本相权衡。此外,为确保数据页一致性,每个检查点后对数据页的第一次修改会导致记录整个页面内容。因此更小的检查点间隔会增加日志输出量,部分抵消了使用更小间隔的目的,而且无论如何都会造成更多磁盘 I/O。
至少会有一个 16 MB 的段文件,通常不会超过 2 * checkpoint_segments + 1
个文件。可以用这个来估算 WAL 的空间需求。通常,当旧的日志段文件不再需要时,它们会被回收(改名为编号序列中的下几个段)。如果由于日志输出率的短期峰值,段文件超过了 2 * checkpoint_segments + 1
个,不需要的段文件将被删除而不是回收,直到系统回到该限制之内。
有两个常用的 WAL 函数:LogInsert 和 LogFlush。LogInsert 用于把一条新记录放入共享内存中的 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 参数设为任何非零值将导致每次
LogInsert 和
LogFlush 的
WAL 调用都被记录到服务器日志。目前,非零值具体是什么没有区别。这个选项将来可能被更通用的机制取代。