选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0
历史版本PostgreSQL 9.1 已于 2016 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

29.4. WAL 配置 #

有若干与 WAL 相关的配置参数会影响数据库性能。本节解释它们 的用法。有关设置服务器配置参数的一般信息,请参见 第 18 章

检查点 是事务序列中的一些点,在这些点上可以保证堆和索引数据文件已经用检查点之前写入 的全部信息进行了更新。执行检查点时,所有脏数据页都会刷盘,并向 WAL 文件写入一条特殊的检查点记录。(更改记录此前已写入 WAL 文件并刷盘。)如果发生崩溃,崩溃恢复过程会查看最新的检查点记录,以确定应该从 WAL 的哪个位置(称为重做记录)开始执行 REDO。该点之前对数据文件所做的任何更改 都保证已经在磁盘上。因此,检查点之后,位于包含重做记录的段之前的 WAL 段不再需要, 可以被回收或删除。(若正在执行 WAL 归档,则这些 WAL 段必 须先归档,随后才能回收或删除。)

检查点要求将所有脏数据页刷盘,这可能造成可观的 I/O 负载。因此,检查点活动会 被节流,使 I/O 从检查点开始时就启动,并在下一个检查点预计开始前完成;这样可 将检查点期间的性能下降降到最低。

服务器的后台写进程会自动定期执行检查点。每写入 checkpoint_segments 个日志段,或者每经过 checkpoint_timeout 秒,就会开始一个检查点,以先到者为 准。默认设置分别是 3 个段和 300 秒(5 分钟)。也可以使用 SQL 命令 CHECKPOINT 强制执行检查点。

减小 checkpoint_segments 和/或 checkpoint_timeout 会让检查点更频繁地发生。这样可以加快崩溃后 恢复,因为需要重做的工作更少。不过,这必须与更频繁地将脏数据页刷盘所增加的成本 权衡。如果设置了 full_page_writes(默认就是如此), 还要考虑另一个因素。为了保证数据页一致性,每个检查点之后对某个数据页的首次 修改,都会导致把整页内容写入日志。在这种情况下,更短的检查点间隔会增加输出到 WAL 的数据量,部分抵消缩短间隔的目的,并且无论如何都会带来更多磁盘 I/O。

检查点的代价相当高,首先是因为它要求写出当前所有脏缓冲区,其次是因为它还会像 上文所述那样带来额外的后续 WAL 流量。因此,明智的做法是将检查点参数设得足够 高,避免检查点发生得过于频繁。作为对检查点参数的一种简单合理性检查,你可以 设置参数 checkpoint_warning。如果检查点之间的间隔 小于 checkpoint_warning 秒,服务器日志就会输出一条消息, 建议增大 checkpoint_segments。偶尔出现这样的消息无需惊慌,但如果 它频繁出现,就应当增大检查点控制参数。大型 COPY 传输之类的 批量操作,如果 checkpoint_segments 设得不够高,也可能导致出现 多次此类警告。

为了避免大量页面写出在短时间内淹没 I/O 系统,检查点期间对脏缓冲区的写出会被 分散到一段时间内。这段时间由 checkpoint_completion_target 控制,它表示为检查点间隔的一个分数。系统会调节 I/O 速率,使检查点在自检查点开始以来已消耗给定比例的 checkpoint_segments 个 WAL 段、或者已过去给定比例的 checkpoint_timeout 秒时完成,以较早者为准。使用默认值 0.5 时,可以预期 PostgreSQL 会在下一次检查点开始前的这段时间约过一半时完成每个检查点。 在正常运行时已非常接近最大 I/O 吞吐量的系统上,你可能希望增大 checkpoint_completion_target,以降低检查点带来的 I/O 负载。 这样做的缺点是,延长检查点会影响恢复时间,因为需要保留更多 WAL 段以备恢复时 使用。虽然 checkpoint_completion_target 可以设到 1.0,但最好 保持在该值以下(或许最多为 0.9),因为检查点除了写出脏缓冲区之外还包含其他活动。 设置为 1.0 很可能导致检查点不能按时完成,从而因为所需 WAL 段数量的意外波动而 损失性能。

WAL 段文件至少会有一个,通常不会多于 (2 + checkpoint_completion_target) * checkpoint_segments + 1 或 checkpoint_segments + wal_keep_segments + 1 个文件。每个段文件通常是 16 MB(不过在构建服务器时可以更改这个大小)。 可以据此估算 WAL 的空间需求。通常,当旧的日志段文件不再 需要时,它们会被回收(也就是重命名为编号序列中的未来段文件)。如果由于日志 输出速率的短期突增,段文件数量超过了 3 * checkpoint_segments + 1, 那么不再需要的段文件就会被删除而不是回收,直到系统重新回到该限制之下。

在归档恢复或备库模式下,服务器会周期性地执行 重启点, 其行为类似于正常运行时的检查点:服务器会强制将其所有状态刷盘,更新 pg_control 文件,以表明已经处理过的 WAL 数据无需再次 扫描,然后回收 pg_xlog 目录中的旧 WAL 段文件。重启点的 执行频率不会高于主库上的检查点,因为重启点只能在检查点记录处执行。重启点总是会等待至少 checkpoint_segments 个日志段或 checkpoint_timeout 秒(以较长者为准)。

有两个常用的内部 WAL 函数: LogInsertXLogFlushLogInsert 用于把新记录放入共享内存中的 WAL 缓冲区。如果新记录没有可用空间, LogInsert 就不得不把 若干已满的 WAL 缓冲区写出(移入内核缓存)。这并不理想,因为 LogInsert 会在每一次数据库底层修改(例如插入行) 时被调用,而在调用它时,受影响数据页上正持有排他锁,因此这一操作必须尽可能 快。更糟的是,写 WAL 缓冲区还可能迫使系统创建新的 WAL 段, 这会花费更多时间。正常情况下,WAL 缓冲区应由 XLogFlush 请求负责写出并刷盘; 该请求大多发生在事务提交时,以确保事务记录已刷盘至持久存储。在 WAL 输出量很高 的系统上,XLogFlush 请求可能不够频繁,无法避免 LogInsert 自己去执行写出。在这种系统上,应增加 WAL 缓冲区的数量,具体做法是修改参数 wal_buffers。当设置了 full_page_writes 且系统非常繁忙时,把该值设置得更高 有助于平滑每次检查点后紧接着那段时期的响应时间。

commit_delay 参数定义了服务器进程在用 LogInsert 把一条提交记录写入日志之后、执行 XLogFlush 之前会睡眠多少微秒。这一延迟允许其他服务器进程把它们的提交记录追加到日志中,从而让所有这些记录通过一次日志同步一起刷盘。如果未启用 fsync,或者当前处于活动事务中的其他会话少于 commit_siblings 个,则不会发生睡眠;这避免了在不太可能有其他会话很快提交时进行睡眠。注意,在大多数平台上,睡眠请求的分辨率是十毫秒,因此 1 到 10000 微秒之间的任何非零 commit_delay 设置效果都相同。这些参数的理想取值目前尚不明确;鼓励进行实验。

参数 wal_sync_method 决定 PostgreSQL 将如何请求内核把 WAL 更新强制刷盘。就可靠性而言,所有选项应当都是相同 的;例外是 fsync_writethrough,它有时能够在其他选项做不 到时强制将磁盘缓存中的数据刷盘。不过,具体哪个选项速度最快则高度依赖平台。可以使用 pg_test_fsync 模块测试不同选项的速度。请注意,如果 fsync 已被关闭,那么这个参数就没有意义。

启用配置参数 wal_debug(前提是 PostgreSQL 编译时支持它)会导致每一次 LogInsertXLogFlushWAL 调用都被记录到服务器日志中。将来,这个选项可能会 被更通用的机制所取代。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。