代码改变世界

【PostgreSQL】PostgreSQL的WAL日志归档的压缩

2022-07-06 13:20  abce  阅读(576)  评论(0编辑  收藏  举报

随着硬件和软件的发展,数据库的瓶颈也发生了转移。很多老的问题可能消失了,也有新的问题出来了。

老的限制

以前是CPU和内存受到限制。十多年前,4核服务器是“高端”服务器,作为DBA,我最担心的是管理可用资源。Oracle尝试使用RAC架构为单个数据库从多个主机集中CPU和内存是解决这个问题的一个很好的尝试。

然后是存储速度限制的日子。它是由多核多线程处理器变得普遍引发的,以及内存大小和总线速度的增加。企业试图通过复杂的SAN驱动器、带有缓存的专用存储等来解决它。但它已经存在很多年了,即使是现在企业开始越来越多地转向NVMe驱动器。

最近我们开始观察到一个新的瓶颈,它正在成为许多数据库用户的痛点。随着单主机服务器能力的提高,它开始处理大量事务。有些系统可以在几分钟内生成数千个WAL文件,并且有一些案例,其中WAL归档到更便宜、更慢的磁盘系统无法赶上WAL生成。许多组织更喜欢在低带宽网络上存储WAL档案,更增加了复杂性。(Postgres Archiving 有一个固有的问题,如果它落后,它往往会滞后更多,因为归档过程需要在.ready 文件中搜索。这里不讨论)

在本文中,我想提请你注意一个事实,如果还没有压缩 WAL的话,WAL压缩是很容易实现的。以及一个用于监控归档gap的查询。

压缩PostgreSQL WALs

归档前压缩WAL的需求与日俱增。幸运的是,大多数PostgreSQL备份工具(如pgbackrest/wal-g等)已经实现了。archive_command调用这些工具,为用户静默存档。

例如,在pg_backrest 中,我们可以指定archive_command,它在后台使用gzip进行压缩:

ALTER SYSTEM SET archive_command = 'pgbackrest --stanza=mystanza archive-push %p';

 

或者WAL-G工具,使用lz4进行压缩:

ALTER SYSTEM SET archive_command = 'WALG_FILE_PREFIX=/path/to/archive /usr/local/bin/wal-g wal-push  %p';

 

如果我们没有使用任何备份工具,而想压缩归档呢?

我们仍然可以使用Linux提供的如gzip、bzip等进行压缩。比如:

alter system set archive_command = '/usr/bin/gzip -c %p > /home/postgres/archived/%f.gz';

  

然而,7za是所有WAL压缩选项中最有趣的,它尽可能快地提供最高压缩比。可以显式安装7za,它是来自7zip包的一部分。

 

在centos7上:

sudo yum install epel-releasesudo yum install p7zip

在ubuntu上:

sudo apt install p7zip-full

安装后就可以使用了:

postgres=# alter system set archive_command = '7za a -bd -mx2 -bsp0 -bso0 /home/postgres/archived/%f.7z %p';
ALTER SYSTEM

在我的测试系统中,可以看到小于200kb的归档WAL文件。大小根据WAL的内容而有所不同,这取决于数据库上的事务类型。

-rw-------. 1 postgres postgres 197K Feb  6 12:13 0000000100000000000000AA.7z
-rw-------. 1 postgres postgres 197K Feb  6 12:13 0000000100000000000000AB.7z
-rw-------. 1 postgres postgres 198K Feb  6 12:13 0000000100000000000000AC.7z
-rw-------. 1 postgres postgres 196K Feb  6 12:13 0000000100000000000000AD.7z
-rw-------. 1 postgres postgres 197K Feb  6 12:13 0000000100000000000000AE.7z

将16MB文件压缩到千字节范围内肯定会节省网络带宽和存储空间,同时解决归档落后的问题。

还原WALs

归档和获得最高压缩只是其中的一部分,但我们也应该能够在需要时恢复它们。备份工具提供自己的恢复命令选项。例如,pgbackrest可以使用 archive-get :

restore_command = 'pgbackrest --stanza=demo archive-get %f "%p"'

WAL-G提供了wal-fetch选项来执行相同的工作。

如果选择使用gzip手动压缩归档,我们可以在restore_command中使用gunzip程序,如下所示:

gunzip -c /home/postgres/archived/%f.gz > %p

从postgresql12开始,可以使用alter system命令修改:

postgres=# alter system set restore_command = 'gunzip -c /home/postgres/archived/%f.gz > %p';
ALTER SYSTEM

对于7za,可以这样:

postgres=# alter system set restore_command = '7za x -so /home/postgres/archived/%f.7z > %p';
ALTER SYSTEM

但是,与archive_command更改不同,restore_command更改需要重新启动standby数据库。

监控归档进程活动

当前WAL归档可从pg_stat_archiver.status获得,但使用WAL文件名找出gap有点棘手。我用来找出WAL归档滞后的示例查询是这样的:

select pg_walfile_name(pg_current_wal_lsn()),last_archived_wal,last_failed_wal, 
  ('x'||substring(pg_walfile_name(pg_current_wal_lsn()),9,8))::bit(32)::int*256 + 
  ('x'||substring(pg_walfile_name(pg_current_wal_lsn()),17))::bit(32)::int  -
  ('x'||substring(last_archived_wal,9,8))::bit(32)::int*256 -
  ('x'||substring(last_archived_wal,17))::bit(32)::int
  as diff from pg_stat_archiver;

这里需要注意的是,当前的WAL和要归档的WAL具有相同的时间线,以便此查询能够正常工作,这是常见的情况。我们很少会遇到与生产中不同的情况。因此,在监视PostgreSQL服务器的WAL归档时,此查询可能会有很好的帮助。