四月 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 文件。