作为一个开发者,我们知道一个网站如果数据丢失和停机,即使是很少、很短暂,也可能是灾难性的,并且降低生产力、可访问性和产品信心。
为保护站点的完整性,建立防范停机或数据丢失的措施至关重要。
数据复制是一种自动备份过程,数据会从其主数据库复制到另一个远程位置以进行妥善保管。对于运行数据库服务器的任何站点或应用程序来说,它都是一项不可或缺的技术。我们还可以利用复制的数据库来处理只读 SQL,从而允许在系统内运行更多进程。
在两个数据库之间设置复制是很有必要了,它提供了针对意外事故的容错能力,这也是在灾难期间实现高可用性的最佳策略。
在本文中,我们将深入探讨 PostgreSQL 复制的不同策略。
PostgreSQL 复制是将数据从PostgreSQL 数据库服务器复制到另一台服务器的过程。源数据库服务器也称为“主”服务器,而接收复制数据的数据库服务器称为“副本”服务器。
PostgreSQL 数据库遵循简单的复制模型,其中所有写入都转到主节点。然后主节点可以应用这些更改并将它们广播到辅助节点。
故障转移是一种在主服务器因一些原因失效时恢复数据的方法。不过只要你配置了 PostreSQL 来进行物理流复制,就不会因主服务器故障而停机。
请注意,故障转移过程可能需要一些时间来设置和启动。PostgreSQL 中没有用于监视和确定服务器故障范围的内置工具,因此需要我们自行发挥。
不过幸运的是,我们需要依赖 PostgreSQL 进行故障转移。有专用工具来进行自动故障转移和自动切换到备用数据库,从而减少数据库停机时间。
通过设置故障转移复制,即使主服务器崩溃时,也可以通过备用服务器切换来保证高可用性。
以下是利用 PostgreSQL 复制的一些主要优势:
通常,一般的机构中只有一种方法可以设置备份和复制。然而,PostgreSQL 可以有三种,分别如下:
PostgreSQL 流复制也称为 WAL 复制,可以在服务器上安装 PostgreSQL 后无缝设置。这种复制方法基于将 WAL 文件从主数据库复制到目标数据库来完成的。
通过使用主从配置来实现 PostgreSQL 流式复制。主服务器是处理主数据库及其所有操作的主要实例。辅助服务器充当补充实例并执行复制对主数据库所做的所有更改,并在此过程中生成相同的副本。主服务器是读/写服务器,而辅助服务器只是只读的。
这种方法需要同时配置主节点和备节点。以下部分将阐明配置所涉及的步骤。
通过执行以下步骤来配置主节点:
我们可以利用 initdb 程序命令来初始化数据库。接下来,使用命令创建具有复制权限的新用户:
CREATE USER 'example_username' REPLICATION LOGIN ENCRYPTED PASSword 'example_password';
用户在查询时,必须提供密码和用户名。REPLICATION 关键字用于为用户提供所需的权限。示例如下:
CREATE USER 'rep_username' REPLICATION LOGIN ENCRYPTED PASSWORD 'rep_password';
第二步:配置流属性
接下来,使用 PostgreSQL 配置文件 ( postgresql.conf )配置流媒体属性,如下:
wal_level = logical
wal_log_hints = on
max_wal_senders = 8
max_wal_size = 1GB
hot_standby = on
配置解析:
修改 postgresql.conf 文件中的参数后, pg_hba.conf 文件中的新 replication 条目可以允许服务器相互建立连接以进行复制。
可以在 PostgreSQL 的数据目录中找到这个文件,配置条目如下:
host replication rep_user IPaddress md5
执行以下代码片段后,主服务器就允许调用的用户(rep_user)通过使用指定的 IP 进行连接并充当备用服务器进行复制。示例:
host replication rep_user 192.168.0.22/32 md5
要配置备用节点,需要用 pg_basebackup 程序生成主节点的备份,这将作为备用节点的起点。命令如下:
pg_basebackp -D -h -X stream -c fast -U rep_user -W
上述语法中使用的参数如下:
接下来,我们需要检查复制配置文件是否存在。如果没有,生成复制配置文件,名称为:recovery.conf。
在 PostgreSQL 安装的数据目录中创建此文件,也可以用 pg_basebackup 程序-R 选项自动生成。
recovery.conf文件应包含以下命令:
standby_mode = 'on'
primary_conninfo = 'host=<master_host> port=<postgres_port> user=<replication_user> password=<password> Application_name="host_name"'
recovery_target_timeline = 'latest'
上述命令中使用的参数如下:
要建立连接,需要提供用户名、IP 地址和密码作为 primary_conninfo 参数的值。示例:
primary_conninfo = 'host=192.168.0.26 port=5432 user=rep_user password=rep_pass'
最后,重新启动备份服务器以完成配置过程。
然而,流复制会带来一些挑战,例如:
RBD 方法依赖于磁盘镜像(也称为卷复制)。在这种方法中,更改被写入一个持久卷,该卷被同步镜像到另一个卷。
RBD 是一个基于Ceph分布式存储系统的块设备复制方案,用于在PostgreSQL数据库中实现高可用性和容错性。它通过将主服务器上的数据块实时复制到备用服务器上,以确保在主服务器出现故障或宕机时,备用服务器可以立即接管其职责。
RBD是一个基于网络块设备的复制方案,它可以在多个Ceph节点之间实现数据复制,并通过Ceph的故障转移机制来保证数据的可用性和一致性。在RBD中,主服务器和备用服务器之间通过Ceph集群的网络通信,实现数据块的实时复制和同步。
与其他流复制方案相比,RBD具有以下优点:
WAL 由段文件组成(默认为 16 MB)。每个段都有一个或多个记录。日志序列记录 (LSN) 是指向 WAL 中记录的指针,用于记录在日志文件中保存的位置(position/location)。
备份服务器利用 WAL 段(在 PostgreSQL 术语中也称为 XLOGS)从其主服务器不断复制更改。你可以通过在DBMS中使用预写日志(write-ahead logging)来为数据提供持久性和原子性,具体做法是在将字节数组数据块(每个块都带有唯一的LSN)应用到数据库之前,将它们序列化并写入稳定的存储介质
将变更应用到数据库可能会引起各种文件系统操作。一个相关的问题是,在文件系统更新过程中,如果服务器由于停电而发生故障,数据库如何确保原子性。具体做法是当数据库启动时,它会开始一个启动或重放过程,该过程可以读取可用的WAL段,并将它们与存储在每个数据页上的LSN进行比较(每个数据页都标记有影响该页的最新WAL记录的LSN)。
流复制改进了日志发送的过程。与等待WAL切换不同,记录在创建时就被发送,从而减少了复制延迟。
流复制也胜过日志发送,因为备份服务器通过复制协议在网络上与主服务器建立连接。主服务器可以直接通过这个连接发送WAL记录,而不必依赖于用户提供的脚本。
日志发送是将日志文件复制到另一台PostgreSQL服务器,通过重放WAL文件生成另一台备用服务器。且此服务器被配置为在恢复模式下工作,目的是为了在监听新的 WAL 文件,并进行应用。
备份服务器将成为主 PostgreSQL 服务器的热备份。它还可以配置为只读副本,可以提供只读查询。
在创建 WAL 文件时将其复制到除pg_wal子目录以外的任何位置以将其归档称为 WAL 归档。每次创建 WAL 文件时,PostgreSQL 都会调用用户提供的脚本进行归档。
该脚本可以利用该scp命令将文件复制到一个或多个位置,例如 NFS 。存档后,可以利用 WAL 段文件恢复数据库到任何给定时间点。
其他基于日志的配置如下:
WAL接收器的进程运行在备用服务器上,利用recovery.conf中提供的primary_conninfo参数中的连接详细信息,通过TCP/IP连接到主服务器。
开始流式复制时,前端可以在启动消息中发送复制参数。值为true、yes、1或ON的布尔值让后端知道它需要进入物理复制walsender模式。
WAL发送器是在主服务器上运行的另一个进程,负责在生成WAL记录时将其发送到备用服务器。WAL接收器将WAL记录保存在WAL中,就像本地的客户端连接一样。
一旦WAL记录到达WAL段文件,备用服务器就不断地重放WAL,以使主服务器和备用服务器保持最新同步状态。
接下来我们将更深入地了解 PostgreSQL 复制的常用模型(单主复制和多主复制)、类型(物理复制和逻辑复制)以及模式(同步和异步)。
可扩展性是指向现有节点添加更多资源/硬件,以增强数据库存储和处理更多数据的能力,可以进行水平和垂直扩展。PostgreSQL 复制是水平可伸缩性的一个例子,它比垂直可伸缩性更难实现。主要通过单主复制(SMR)和多主复制(MMR)来实现水平扩展。
单主复制仅允许在单个节点上修改数据,并将这些修改复制到一个或多个节点。副本数据库中的复制表不允许接受任何更改,但来自主服务器的更改除外。
大多数时候,SMR 足以满足应用程序的需求,因为它的配置和管理不那么复杂,而且不会发生冲突。单主复制也是单向的,因为复制数据主要在一个方向上流动,从主数据库到副本数据库。
在某些情况下,单靠 SMR 可能不够,你可能需要实施 MMR。MMR 允许多个节点充当主节点。对多个指定主数据库中表行的更改将复制到每个其他主数据库中的对应表。在这个模型中,经常采用冲突解决方案来避免重复主键等问题。
使用 MMR 有几个优点,即:
然而,实施 MMR 的缺点是复杂性和冲突难以解决。
一些机构和应用程序提供 MMR 解决方案,因为 PostgreSQL 本身并不支持。这些解决方案可能是开源的、免费的或付费的。如双向复制 (BDR),它是异步的并且基于 PostgreSQL 逻辑解码功能。
由于 BDR 应用程序在其他节点上重放事务,如果正在应用的事务与在接收节点上提交的事务之间存在冲突,重放操作可能会失败。
PostgreSQL 复制有两种类型:逻辑复制和物理复制。
一个简单的 initdb 逻辑操作,将会执行为集群创建基准目录的物理操作。同样,一个简单的逻辑操作(CREATE DATABASE)将执行为在基准目录中创建子目录的物理操作。
物理复制通常处理文件和目录。它不知道这些文件和目录代表什么。物理复制方法用于在另一台机器上维护单个集群的完整数据副本,并且在文件系统级别或磁盘级别进行,并使用精确的块地址。
逻辑复制是一种根据复制标识(通常是主键)复制数据实体及其修改的方法。与物理复制不同,它处理数据库、表和 DML 操作,并在数据库集群级别完成。它使用发布和订阅模型,一个订阅者可以订阅发布者节点上的一个或多个发布。
复制过程首先对发布者数据库上的数据进行快照,然后将其复制到订阅者。订阅者从他们订阅的发布中提取数据,并可能稍后重新发布数据,以允许级联复制或更复杂的配置。订阅者以与发布者相同的顺序应用数据,以便保证单个订阅内的发布的事务一致性,也称为事务复制。
逻辑复制的典型场景如下:
订阅者数据库的行为方式与任何其他 PostgreSQL 实例相同,并且可以通过定义其发布来用作其他数据库的发布者。
当订阅者被应用程序配置成只读时,单个订阅不会发生冲突。不过,如果应用程序或其他订阅者对同一组表进行了写入,则可能会出现冲突。
PostgreSQL 同时支持这两种机制。逻辑复制允许对数据复制和安全性进行细粒度控制。
PostgreSQL 复制主要有两种模式:同步和异步。同步复制允许同时将数据写入主服务器和从服务器,而异步复制确保数据先写入主服务器,然后再复制到从服务器。
在同步模式复制中,只有当这些更改已复制到所有副本时,主数据库上的事务才被视为完成。副本服务器必须始终可用,以便在主服务器上完成事务。同步复制模式用于具有即时故障转移要求的高端事务环境。
在异步模式下,当只在主服务器上完成更改时,可以声明主服务器上的事务已完成。这些更改随后会及时复制到副本中。副本服务器可以在一段时间内保持不同步,称为复制滞后。在崩溃的情况下,可能会发生数据丢失,但异步复制提供的开销很小,因此在大多数情况下是可以接受的(不会使主服务器负担过重)。
接下来,我们将演示如何在 linux 操作系统上设置 PostgreSQL 复制过程。对于本例,我们将使用 Ubuntu 18.04 LTS 和 PostgreSQL 10。
通过以下步骤在 Linux 上安装 PostgreSQL:
wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt/ bionic-pgdg mAIn" | sudo tee /etc/apt/sources.list.d/postgresql.list
sudo apt-get update
sudo apt-get install -y postgresql-10
sudo passwd postgres
在进行 PostgreSQL 复制过程之前,主服务器和备份服务器都必须安装 PostgreSQL。
在两台服务器上设置 PostgreSQL 后,可以继续进行主服务器和备份服务器的复制设置。
su - postgres
psql -c "CREATEUSER replication REPLICATION LOGIN CONNECTION LIMIT 1 ENCRYPTED PASSWORD'YOUR_PASSWORD';"
nano /etc/postgresql/10/main/pg_hba.conf
host replication replication MasterIP/24 md5
nano /etc/postgresql/10/main/postgresql.conf
配置如下:
listen_addresses = 'localhost,MasterIP'
wal_level = replica
wal_keep_segments = 64
max_wal_senders = 10
systemctl restart postgresql
至此,主服务器配置已经完成。
su - postgres
systemctl stop postgresql
nano /etc/postgresql/10/main/pg_hba.conf
host replication replication MasterIP/24 md5
nano /etc/postgresql/10/main/postgresql.conf
listen_addresses = 'localhost,SecondaryIP'
wal_keep_segments = 64
wal_level = replica
hot_standby = on
max_wal_senders = 10
SecondaryIP是从服务器的地址。
cd /var/lib/postgresql/10/main
rm -rfv *
pg_basebackup -h MasterIP -D /var/lib/postgresql/11/main/ -P -U
replication --wal-method=fetch
// "Edit" Command
nano /var/lib/postgresql/10/main/recovery.conf
// Configuration
standby_mode = 'on'
primary_conninfo = 'host=MasterIP port=5432 user=replication password=YOUR_PASSWORD'
trigger_file = '/tmp/MasterNow'
这里YOUR_PASSWORD是主服务器 PostgreSQL 创建的复制用户的密码。
systemctl start postgresql
现在已经执行完了这些配置,让我们测试复制过程并观察从服务器数据库是否正常。
首先,我们在主服务器中创建一个表,并观察它是否反映在备份服务器上。
su - postgres
psql
CREATE TABLE testtable (websites varchar(100));
INSERT INTO testtable VALUES ('section.com');
INSERT INTO testtable VALUES ('google.com');
INSERT INTO testtable VALUES ('Github.com');
su - postgres psql
select * from testtable;
查询结果如下:
| websites |
-------------------
| section.com |
| google.com |
| github.com |
--------------------
那么测试成功,主服务器数据已经同步到从服务器上了。
让我们回顾一下 PostgreSQL 手动故障转移的步骤:
./pg_ctl promote -D ../sb_data/
server promoting
-bash-4.2$ ./edb-psql -p 5432 edb
Password:
psql.bin (10.7)
Type "help" for help.
edb=# insert into abc values(4,'Four');
如果插入正常,则从服务(以前是只读服务)已提升为新的主服务。
设置自动故障转移很容易,需要使用到 EDB PostgreSQL 故障转移管理器 (EFM)。在每个主节点和备用节点上下载并安装 EFM 后,你可以创建一个 EFM 集群,该集群由一个主节点、一个或多个备用节点以及一个可选的 Witness 节点组成,该节点在发生故障时确认断言。
EFM 持续监控系统运行状况并根据系统事件发送电子邮件警报。当发生故障时,它会自动切换到最新的备用服务并重新配置所有其他备用服务以识别新的主节点。
它还会重新配置负载平衡器(例如 pgPool)并防止发生“裂脑”(当两个节点都认为它们是主节点时)。
由于存储数据量大,可伸缩性和安全性已成为数据库管理中最重要的两个标准,尤其是在事务环境中。虽然我们可以通过向现有节点添加更多资源/硬件来垂直提高可扩展性,但这并不总是可行的,因为添加新硬件是需要成本的。
因此,就需要 PostgreSQL 复制发挥作用了,它实现了水平可扩展,即向现有网络节点添加更多节点,而不是增加现有节点的硬件配置。