ITPub博客

首页 > 数据库 > 数据库开发技术 > 为什么WAL日志归档这么慢

为什么WAL日志归档这么慢

原创 数据库开发技术 作者:u_a9af4a561c3b 时间:2021-10-09 23:48:06 0 删除 编辑

为什么WAL日志归档这么慢

许多客户案例显示,大量的WAL日志撑满了 pg_wal 目录,导致磁盘空间使用量突然增加。恐慌的客户通常会问为什么PostgreSQL不会删除它们?我们发现最常见的原因是:

1.WAL日志归档失败2.复制槽限制了WAL日志的回收

然而近年来,另一种类型的案例开始出现,这也是这篇文章的标题。显然,慢是主观的,大多数用户指的是与WAL日志的生成速度相比较的慢。最近这种情况的增加主要是由于每台主机服务器处理能力的增加、PostgreSQL不断增加的可伸缩性(例如,最近在分区特性方面的改进、批量数据加载方面的改进等)以及更快的新一代存储引起的。基本上,每台服务器都完成了更多的工作,因此,WAL日志的生成量增多也成为了一种新常态,另外《为什么WAL日志压缩成为迫切需要的原因》也是一样的。

在那篇博客中还讨论了像 WAL-G 和 pgBackRest 这样的备份解决方案是如何通过内置压缩特性来解决这个问题的。

同时,由于相对昂贵的备份设备,远程云存储由于其价格优势和久经考验的可靠性,成为存储归档 WAL日志的更有吸引力的选择。此外,用户/组织对云存储也越来越熟悉,这种舒适度的提高是决定云存储备份的主要驱动力。

但是,WAL日志的急剧生成再加上缓慢的远程存储去作为归档路径,这样的组合对于整个归档过程来说是致命的。除非得到适当的监控和处理,否则可能会导致灾难。

在这篇博客中,我们将了解一些关于归档进程如何工作的内部原理,以及它是如何以同步方式处理archive_command中指定的外部shell命令。此外,我们也会尝试查看WAL日志的同步归档处理过程中的具体领域,以及它是如何影响归档速度并成为一个棘手问题的。

原生的同步归档

PostgresSQL中的WAL归档十分灵活,因为它可以使用一个外部shell命令作为archive_command的参数。正如上一篇博客中所述,该特性可用于执行任何自定义归档脚本。让我们看看WAL的归档是如何启动的。

通常情况下,归档的整个事件链起始于WAL日志写入( XLogWrite() )的一部分。当一个WAL日志文件完成时,它通过在pg_wal目录下的archive_status子目录中插入一个.ready文件来通知归档进程它与这个WAL日志有关系(内部函数是XLogArchiveNotifySeg -> XLogArchiveNotify)。例如,如果要归档的WAL日志是0000000100000001000000C6,那么.ready文件就是0000000100000001000000C6.ready。这个.ready文件便是用于通知归档进程。除了创建这个文件之外,还会向归档进程发送一个信号以唤醒它(向归档进程发送一个SIGUSR1的信号)。现在,归档进程便可以启动并开始处理所有的.ready文件。

所有与归档进程的直接通信都是通过信号进行的。一旦归档进程接收到了信号(SIGUSR1),它便知道了有一些工作要做。然后,归档进程开始遍历每个带有.ready后缀的文件,并找到需要复制的最老的段文件。有一点很重要,那就是最老的WAL日志应该是第一个被归档的,因为:

1.这在需要执行恢复时会有所帮助,因为归档中的 WAL日志是按顺序进行回放的。如果中间缺失了任何的WAL日志,都会影响可恢复性。2.当检查点发生时,最老的WAL日志更有可能被回收。所以它丢失的几率更大。

现在让我们看看整个操作中的主要瓶颈。

原因1

我们来看第一个问题。逐个查找最老的WAL日志并逐个归档的方式效率并不高。对于每一次遍历,归档进程都需要遍历.ready文件,以找到最老的文件。在正常情况下,这不会是个大问题。然而,在许多高度活跃的服务器和较慢的备份存储中,我们正经历着归档落后了数千到数百万个WAL日志的情况。在这些情况下,列出目录项并遍历.ready文件会非常低效,这使得WAL日志的归档变得更加缓慢,因为它本身已经滞后了。如果不注意的话,累积的影响会导致危险的情况。

原因2

第二个慢的问题是,一旦确定了WAL日志,便需要将其归档。归档进程会调用一个内部函数 pgarch_archiveXlog(),该函数会调用 system() 的系统调用来执行 archive_command 所指定的外部命令/脚本。该命令通常含有2个参数,%p,表示源WAL日志文件的相对路径,%f,表示源WAL日志文件的文件名。一旦外部的shell命令被 system() 调用执行,就会检查它的返回值,以确认执行是否成功(WAL日志是否被成功归档)基本上,归档进程会等待外部命令的返回。如果由于某种原因外部脚本执行有延迟,那么所有的延迟都会累加起来。

原因3

如果在执行 archive_command 时底层系统出现故障/超时,归档进程会等待一秒钟再重新尝试。因此,通过广域网连接的存储速度较慢,那么有可能会等待更多的时间。WAL日志只有在前一个归档成功时才会被归档。一旦外部shell命令成功返回(如上所述,pgarch_archiveXlog()函数成功执行),那么这个.ready文件将被归档进程通过pgarch_archiveDone() 重命名为.done。

这里的常见问题之一是"我们是否需要编写脚本来删除已经归档的 WAL日志和 .done文件?"答案是否定的。checkpoint进程会替你完成,它会删除 .done文件和相应的WAL日志文件(会考虑是否回收 WAL日志文件)。如果相应的WAL日志已被回收或删除,那么archive_status 目录中对应的任何仍保留的.ready 文件都会被归档进程自己删除。

正如我们所讨论的,只有两种通知状态 .ready 或 .done,并没有归档正在进行中的状态,如果需要进行多个并发归档,这是必不可少的。所以根据设计,它并不存在。除非 WAL日志归档成功返回并且 .ready 文件被重命名为 .done,否则我们认为归档从未发生过。因此,如果中间发生了任何故障,PostgreSQL会再次尝试归档(有时会重新复制同一个文件)。

解决办法是什么

像 pgBackRest 这样的高级备份解决方案具有异步备份功能,这允许多个后台工作进程进行压缩和 WAL 日志归档推送,同时前端进程将向PostgreSQL发回确认信息。我们会在即将发布的博客中介绍这一点。

小结

WAL日志归档的同步操作最近变得越来越痛苦。WAL日志归档的整个操作流程是,在每次循环中,对每个未完成的 WAL日志一个接一个地进行,直到没有更多的 WAL日志要归档。如果 WAL日志的生成速率超过归档的速率,则 WAL日志很可能会堆积在 pg_wal 目录中,并且随着 .ready 文件数量的增加问题会继续恶化。一旦收到信号 (SIGUSR1),归档进程就会被唤醒并执行上面讨论的所有遍历,并且该过程将持续进行,直到接收到信号 SIGUSR2。没有内置机制使其异步化。但是,由于 PostgreSQL 使用的外部命令/脚本进行归档操作,因此智能程序/脚本可以将整个同步操作转换为异步操作。这强调了对能够以异步方式推送 WAL日志的备份工具的需求。

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


原文作者:PostgreSQL学徒;如有侵权,请联系管理员删除。

上一篇: 小问题大经验
请登录后发表评论 登录
全部评论

注册时间:2020-07-14

  • 博文量
    306
  • 访问量
    139304