PostgreSQL 教程: 设置 WAL 归档命令

四月 19, 2024

摘要:在本教程中,您将学习如何在 PostgreSQL 中设置 WAL 归档命令。

背景

如今,随着多核多线程处理器的出现越来越普遍,以及内存大小和总线速度的不断增加,存储访问速度很容易达到瓶颈。企业试图通过高端的 SAN 驱动器、带缓存的专用存储等来解决这个问题,但这个问题已经存在了很多年,即便现在企业开始越来越多地转向到 NVMe 驱动器。

最近,我们开始观察到一个新的瓶颈,它正在成为许多数据库用户的痛点。随着单机服务器处理能力的提高,它开始处理大量的事务。有些系统在几分钟内会产生数千个 WAL 文件,另外据反映在一些情况下,将 WAL 归档到廉价、慢速的磁盘系统时,会无法赶上 WAL 的生成速度。许多组织还喜欢在低带宽网络上存储 WAL 归档,这就更增加了问题的复杂性。

警告:在 PostgreSQL 归档中有一个固有的问题,如果归档滞后了,它往往会越来越滞后,因为归档过程需要在.ready文件中进行搜索。本文不作讨论。

WAL 归档命令

PostgreSQL 提供了一个 archive_command 配置参数,您可以指定 shell 命令用来归档 WAL 段。在archive_command中,%p会被将要归档的文件路径所替代,而%f只会被文件名所替代。路径名是相对于当前工作目录而言的,即数据库实例的数据目录。

那么,如何设置归档命令来满足各种场景的需求呢?

归档到远程服务器

我们可以在postgresql.conf中更改archive_command设置,并使用 shell 命令rsync设置archive_command,该命令可将归档文件复制到远程服务器中的安全位置。

archive_command = 'rsync -a %p postgres@backup::archive/%f'

接下来,我们将使用rsyncd.conf文件,来设置backup服务器:

[db_sync]
    path = /db/pgdata
    comment = DB Backup Server
    uid = postgres
    gid = postgres
    read only = false
    use chroot = true
 [archive]
    path = /db/archive
    comment = Archived Transaction Logs
    uid = postgres
    gid = postgres
    read only = false
    use chroot = true

请确保两台服务器上分别存在目录/db/pgdata/db/archive,并且已重新启动rsync守护程序。

当然,您也可以使用 shell 命令scp来设置archive_command,以将 WAL 段归档到远程服务器。

archive_command = 'scp %p postgres@backup:/db/archive/%f'

归档到对象存储服务

首先,下载并安装公有云供应商提供的命令行工具。

使用命令行工具设置archive_command,将归档复制到对象存储服务中。让我们以阿里云为例:

archive_command = 'ossutil64 cp %p oss://examplebucket/desfolder/'

您还可以使用 WAL 归档工具,如 WAL-G。要设置 PostgreSQL 连续归档到 AWS S3(或类似 S3 的存储),您可以将有效的 AWS 凭据放入文件.aws/credentials中。它看起来应该像下面这样:

[default]
aws_access_key_id = AKIDblahblah
aws_secret_access_key = acc3ssk3yyblahblah

创建一个归档脚本,将 WAL 段归档到远程 S3 服务器。文件wal-g-archive.sh

#!/bin/bash

# Connect using Unix socket
export PGHOST=/var/run/postgresql

export WALG_S3_PREFIX=s3://postgres-archive-bucket/production-db
export AWS_REGION=us-east-2
export AWS_SHARED_CREDENTIALS_FILE=/var/lib/postgresql/.aws/credentials

# Optional for AWS S3 (just comment out the code). But necessary for SeaweedFS or MinIO.
export AWS_ENDPOINT=http://192.168.1.182:8333 # SeaweedFS or MinIO server address.
export AWS_S3_FORCE_PATH_STYLE=true

wal-g wal-push $1

使用该归档脚本设置archive_command,以使用wal-g将 WAL 文件发送到 S3 存储的桶中。

archive_command = 'wal-g-archive.sh /db/pgdata/%p'

压缩并归档

要在归档之前压缩 WAL,您可以创建一个归档脚本,如下所示。文件archive-script.sh

#!/bin/bash

walname = `basename $1`
gzip < $1 > /tmp/archive/$walname.gz
rsync -a /tmp/archive/$walname.gz postgres@backup::archive/$walname.gz
rm /tmp/archive/$walname.gz

使用该归档脚本设置archive_command,以归档 WAL 文件。

archive_command = 'archive-script.sh /db/pgdata/%p'

如果您想在发送 WAL 文件到类似 S3 的存储之前压缩 WAL,也许您也可以使用 AWS 提供的 Python 开发工具包,编写像下面这样的 Python 脚本。

#!/usr/bin/python3

import gzip
import boto3

walname = sys.argv[1]

# Let's use Amazon S3
s3 = boto3.client('s3')

# read and compress the wal data
wal = open(walname, 'rb')
data = gzip.compress(wal.read())
wal.close()

# ship the compressed WAL to the S3 bucket
s3.put_object(Body=data, Bucket='my-bucket', Key='objectkey')

这样,我们可以绕过中间压缩文件,将压缩后的 WAL 数据直接放入 S3 存储桶中。

然后,您可以使用该 python 脚本设置archive_command,以归档 WAL 文件。