【云+社区年度征文】PG WAL归档速度慢,为什么

前言

WAL目录下(pg_wal)存了大量WAL段文件,由于来不及删除,占用磁盘空间突然暴增。这种现象很常见。那么为什么PG不删除呢?最常见的原因:1)归档失败;2)slot持有老的WAL。

最近又出现另一种案例,即本文标题。很明显,“慢”是主观的,是相对于WAL段文件的生成。最近这种情况出现主要是由于每台服务器处理能力提供、PG可伸缩性不断提高、更快的新一代存储介质。每台服务器要做更多工作,大量的WAL产生已成为新的常态。这也是WAL压缩成为迫切需求的原因。

本文也讨论了像WAL-G和pgBackRest内置压缩特性的备份解决方案。同时,与昂贵的备份设备相比,远程云存储具有价格优势。用户/组织对云存储也越来越熟悉,这些都是云存储作为存储WAL的主要介质的原因。但是,这种WAL段文件快速生成+慢速/远程存储对于WAL归档过程来说是致命的组合,除非监控和处理得当,否则可能导致灾难。

这个博客中,也将了解archiver进程是如何工作的,以及如何以同步方式处理archive_command中指定的外部shell命令。此外,还将研究WAL的同步归档处理,以及如何影响归档速度从而成为性能挑战。

同步WAL归档

PG的归档很灵活,archive_command指定外部shell命令来进行归档。首先来看WAL归档如何初始化。通常情况下,归档的事件链从WAL写开始XLogWrite()。当写满一个WAL段文件,通过向archive_status目录插入一个.ready文件来通知归档进程需要处理这个段文件了(XLogArchiveNotifySeg->XLogArchiveNotify)。例如,如果0000000100000001000000C6文件需要归档,那么.ready文件为0000000100000001000000C6.ready。这个.ready文件作为归档进程的通知文件。创建这个文件的同时,也会向归档进程发起一个信号来唤醒它。此时归档进程唤醒了开始处理所有.ready文件。

归档进程的通信通过信号。一旦归档进程接收到SIGUSR1信号,他就知道要开始干活了。归档进程开始遍历所有的.ready文件,找到需要复制的最老的段文件。先归档最老的段文件,这点很重要:1)回放时按照这个顺序进行回放,一旦中间少个文件,那么回放就会出错;2)当checkpoint发生时,最老的段文件被回收的几率也较高,因此更容易丢失。

接着看下整个操作过程中主要瓶颈在哪。

案例1

首先看第一个问题。一个接一个地找出最老WAL文件并将其逐个归档,这种方法效率不高。每次迭代,归档进程都需要遍历所有.ready文件从而找到最老文件。通常,这不是个大问题,然而,在业务繁忙的机器和缓慢的备份存储下,会有成千上百万个WAL文件归档滞后。这种情况下,遍历所有.ready文件就会不高效。如不加以注意,会导致严重问题。

案例2

第二个问题从这里开始。一旦确定了一个段文件,就要将其归档。内部函数pgarch_archiveXlog()调用system()系统调用来调用执行外部命令/脚本,这些命令由archive_command指定。这个参数中通常由两个参数:%p为源段文件的相对路径,%f为指定的源段文件名。一旦外部shell命令被system()执行,会调查其返回值以了解是否执行成功。归档进程会等待外部命令执行返回,如果外部脚本由于某种原因延迟执行,那么所有的延迟都将包括这个时间。

案例3

如果archive_command执行时出错,归档进程在重试前会等待1秒。通过WAN连接存储器会由更多等待时间。只有前一个归档成功,后面一个归档文件才会开始。外部shell命令执行成功pgarch_archiveXlog(),pgarch_archiveDone函数将.ready文件修改为.done文件。

这里就会被问“我们是否需要编写脚本删除已经归档的WAL段文件和.done文件?”答案是否定的。Checkpoint会做这些工作。如果archive_status目录中还有.ready文件,而相应的WAL段文件已被回收或删除,那么这些.ready文件将由归档进程删除。

正如上述讨论,只有两种通知状态:.ready和.done,没有中间in-progress状态。如果WAL归档时.ready文件还没被修改为.done就发生故障,PG将再次尝试归档,可能会多次复制同一个文件。

解决方案

高级备份解决方案如pgBackRest具有异步备份特性,允许多个后台工作进程执行压缩和归档推送。

总结

一旦WAL段文件生成速度远大于归档速度,那么就会在pg_wal目录下产生堆积,随着.ready文件的增加问题变得更加严重。收到SIGUSR1开始归档,收到SIGUSR2为止。没有内置操作可以异步。可以通过外部命令使操作变成异步。这就需要一个备份工具,以异步方式推送WAL文件。

原文

https://www.percona.com/blog/2020/09/09/why-postgresql-wal-archival-is-slow/