每个提交的事务都会记录 WAL,以确保持久性。这可确保您的 PostgreSQL 实例可以执行崩溃恢复,并避免丢失任何已提交的事务。当 full_page_writes 设置为 ON 时,PostgreSQL 会将每个磁盘页面的全部内容以及行级更改写入 WAL。这对于安全的崩溃恢复非常重要。但是,这可能会将更多数据写入 WAL。
将 WAL 写入和包含表/索引的数据目录相同的磁盘,可能会给繁忙的事务数据库带来 I/O 瓶颈。因此,如果您观察到有大量 WAL 生成(由于大量 DML)导致服务器中的 I/O 等待,我们始终建议您将 WAL 目录移动到一个新的磁盘。
准备工作
要将 WAL 移动到一个其他目录,我们必须重新启动 PostgreSQL 服务器。这可能会导致停机,因此需要适当规划。此外,请确保在新的 pg_wal 目录中规划有足够的存储空间,用于存储启用复制槽时给备用数据库应用的所有 WAL 段。我们必须这样做,因为当使用复制槽时,尚未确认为备用数据库已应用的 WAL 段,不会从主数据库的 pg_wal 目录中删除。如果长时间未注意到这种情况,这可能会累积多个 GB 的 WAL 段。
操作步骤
以下步骤可用于将 pg_wal 移动到新位置:
1. 在新磁盘上创建一个新目录,并将所有权分配给 Postgres:
# mkdir -p /wals
# chown postgres:postgres /wals
2. 停止 PostgreSQL 实例(如果该实例已在运行):
$ pg_ctl -D $PGDATA stop -mf
3. 如果您想避免由于大量 WAL 而导致的更长停机时间,请跳过步骤 2 继续执行步骤 3b。否则,请继续执行步骤 3a:
3a. 将 pg_wal 中的所有现有 WAL 和 archive_status 目录,移动到另一个磁盘上的新目录。确保 pg_wal 为空,并且所有内容都移动到了新目录:
$ mv $PGDATA/pg_wal/* /wals
3b. 使用 rsync 避免在将大量 WAL 段复制到其他磁盘时出现超长的停机时间:
$ rsync -avzh $PGDATA/pg_wal/ /wals
$ pg_ctl -D $PGDATA stop -mf
$ rsync -avzh $PGDATA/pg_wal/ /wals
4. 删除旧的 WAL 目录后,创建一个符号链接:
$ rmdir $PGDATA/pg_wal
$ ln -s /wals pg_wal
$ ls -alrth pg_wal
lrwxrwxrwx. 1 postgres postgres 5 Nov 10 00:16 pg_wal -> /wals
5. 立即启动 PostgreSQL 实例:
$ pg_ctl -D $PGDATA start
这样,您就成功地将 WAL 目录移动到了另一个位置。
怎么做到的...
要移动 pg_wal,我们必须向服务器添加一个新磁盘,并创建将在其中存储 WAL 段的新目录。我们还需要确保为目录授予适当的权限,如步骤 1 所示。由于这需要您关闭 Postgres 服务器以移动 WAL 目录,因此我们可以使用类似于步骤 2 中所示的命令,来关闭 Postgres。
如果您有大量的 WAL 段,则可以通过跳过此步骤继续执行步骤 3b,来避免更长的停机时间。如果没有,您可以使用步骤 3a,简单地将现有 pg_wal 目录的所有内容移动到新的目录。
如果您希望避免超长的停机时间,并希望跳过步骤 2 和 3a,则只需使用步骤 3b,它使用 rsync 将所有现有的 WAL 段从 pg_wal 复制到新的 WAL 目录。完成后,我们可以简单地关闭 Postgres,并再次使用 rsync 来复制新生成的 WAL 段。 移动完所有 WAL 段后,删除旧的 WAL 目录,并创建指向新目录的符号链接,如步骤 4 所示。
正如我们所看到的,pg_wal 不会从数据目录中永久删除。相反,一个指向我们要将 WAL 移动到的新目录的符号链接会创建出来。创建符号链接后,我们可以启动 PostgreSQL,如步骤 5 所示,开始将新生成的 WAL 段写入新的 WAL 目录。
如果您有一个具有 1 个主节点和 1 个或多个备节点的高可用集群,则可以以滚动方式或一次性执行所有步骤。在复制集群的每个服务器中具有不同的位置,一直是可以的。 因此,您可以停止所有服务器并执行这些步骤,或者在一台又一台服务器上执行这些步骤。