PostgreSQL 复制的综合指南

641 阅读24分钟

正如任何网站所有者会告诉你的,数据丢失和停机,即使是最小的剂量,也可能是灾难性的。它们可以在任何时候袭击毫无准备的人,导致生产力、可访问性和产品信心的降低。

为了保护你的网站的完整性,建立保障措施以防止停机或数据丢失的可能性是至关重要的。

数据复制是一个自动化的备份过程,在这个过程中,你的数据被反复地从其主数据库复制到另一个远程位置进行安全保存。对于任何运行数据库服务器的网站或应用程序来说,这是一项不可或缺的技术。你也可以利用复制的数据库来处理只读的SQL,允许在系统内运行更多的进程。

在两个数据库之间设置复制提供了对意外事故的容错。它被认为是在灾难期间实现高可用性的最佳策略。

在这篇文章中,我们将深入探讨不同的策略,这些策略可以由后端开发人员实现无缝的PostgreSQL复制。

什么是PostgreSQL复制?

An illustration of PostgreSQL replication showing the flow of data from the primary server to the replica.

PostgreSQL复制的图解(图片来源:EnterpriseDB)

PostgreSQL复制被定义为从一个PostgreSQL数据库服务器复制数据到另一个服务器的过程。源数据库服务器也被称为 "主 "服务器,而接收复制数据的数据库服务器则被称为 "副本 "服务器。

PostgreSQL数据库遵循一个简单明了的复制模型,所有的写入数据都会进入一个主节点。然后,主节点可以应用这些变化,并将其广播给次要节点。

什么是自动故障转移?

一旦在PostgreSQL中配置了物理流复制,如果数据库的主服务器发生故障,可以进行故障转移。故障转移是用来定义恢复过程的,这可能需要一段时间,因为它没有提供内置的工具来确定服务器故障的范围。

你不必依赖PostgreSQL进行故障转移。有专门的工具可以实现自动故障转移和自动切换到备用机,减少了数据库的停机时间

通过设置故障转移复制,你可以确保在主服务器崩溃时,备用服务器是可用的,从而保证高可用性。

使用PostgreSQL复制的好处

下面是利用PostgreSQL复制的几个主要好处:

  • 数据迁移:你可以通过改变数据库服务器硬件或通过系统部署来利用PostgreSQL复制进行数据迁移。
  • 容错性:如果主服务器发生故障,备用服务器可以充当服务器,因为主服务器和备用服务器的包含数据是一样的。
  • 在线交易处理(OLTP)性能:你可以通过消除报告查询负载来改善OLTP系统的交易处理时间和查询时间。事务处理时间是指在一个事务完成之前执行一个给定的查询所需的时间。
  • 同时进行系统测试:在升级一个新的系统时,你需要确保该系统在现有的数据上表现良好,因此在部署前需要用生产数据库副本进行测试。

PostgreSQL复制是如何工作的

一般来说,人们认为当你涉足主、辅架构时,只有一种方法来设置备份和复制,但PostgreSQL的部署遵循以下三种方法之一。

  1. 卷级复制,在存储层从主节点复制到次节点,然后备份到blob/S3存储。
  2. PostgreSQL流复制,将数据从主节点复制到辅助节点,然后备份到blob/S3存储中。
  3. 从主节点到S3的增量备份,同时从S3重建一个新的二级节点。当辅助节点在主节点附近时,你可以从主节点开始流式传输。

方法1:流式传输

PostgreSQL的流式复制也被称为WAL复制,可以在所有服务器上安装PostgreSQL后无缝设置。这种复制的方法是基于将WAL文件从主数据库移动到目标数据库。

你可以通过使用主-副配置来实现PostgreSQL的流式复制。主服务器是处理主数据库和其所有操作的主实例。辅助服务器作为补充实例,在自己身上执行对主数据库的所有修改,在这个过程中产生一个相同的副本。主服务器是读/写服务器,而辅助服务器只是只读。

对于这种方法,你需要同时配置主节点和备用节点。下面几节将阐明轻松配置它们的步骤。

配置主节点

你可以通过执行以下步骤来配置主节点进行流式复制。

步骤1:初始化数据库

为了初始化数据库,你可以利用initidb utility 命令。接下来,你可以利用以下命令创建一个具有复制权限的新用户。

 CREATE USER  REPLICATION LOGIN ENCRYPTED PASSWORD '';

该用户必须为给定的查询提供一个密码和用户名。复制关键字用于赋予用户所需的权限。一个查询的例子是这样的。

 CREATE USER rep_user REPLICATION LOGIN ENCRYPTED PASSWORD 'rep_pass'
第2步:配置流媒体属性

接下来,你可以用PostgreSQL的配置文件**(postgresql.conf**)来配置流媒体属性,该文件可以按以下方式修改。

wal_level = logical
wal_log_hints = on
max_wal_senders = 8
max_wal_size = 1GB
hot_standby = on

下面是围绕前面片段中使用的参数的一些背景:

  • wal_log_hints:这个参数是pg_rewind ,当备用服务器与主服务器不同步的时候,这个参数就很有用了。
  • wal_level:你可以使用这个参数来启用PostgreSQL流式复制,可能的值包括minimalreplica 、或logical
  • max_wal_size:: 可以用这个参数来指定可以保留在日志文件中的WAL文件的大小。
  • hot_standby:当这个参数设置为ON时,你可以利用这个参数与辅助系统进行读入式连接。
  • max_wal_senders:你可以使用max_wal_senders ,指定可以与备用服务器建立的最大并发连接数。
第3步:创建新条目

在你修改了postgresql.conf文件中的参数后,pg_hba.conf文件中的一个新的复制条目可以让服务器互相建立连接,进行复制。

你通常可以在PostgreSQL的数据目录中找到这个文件。你可以使用下面的代码片断来实现。

 host replication rep_user IPaddress md5

一旦代码片断被执行,主服务器允许一个名为rep_user 的用户连接,并通过使用指定的IP作为备用服务器进行复制。例如。

 host replication rep_user 192.168.0.22/32 md5

配置备用节点

要配置用于流式复制的备用节点,请遵循以下步骤。

步骤1:备份主节点

为了配置备用节点,利用pg_basebackup 工具来生成主节点的备份。这将作为备用节点的一个起点。你可以用下面的语法来使用这个工具。

 pg_basebackp -D  -h  -X stream -c fast -U rep_user -W

上面提到的语法中使用的参数如下:

  • -h:: 你可以利用这个来提到主主机。
  • -D:这个参数表示你当前正在工作的目录。
  • -C:你可以用它来设置检查点。
  • -X:: 这个参数可以用来包括必要的事务性日志文件。
  • -W:: 你可以用这个参数在链接到数据库之前提示用户输入密码。
第2步:设置复制配置文件

接下来,你需要检查复制配置文件是否存在。如果不存在,你可以将复制的配置文件生成为recovery.conf。

你应该在PostgreSQL安装的数据目录下创建这个文件。你可以通过使用pg_basebackup 工具中的-R 选项来自动生成它。

上述命令中使用的参数如下:

  • primary_conninfo:: 你可以用它来利用连接字符串在主服务器和辅助服务器之间建立连接。
  • standby_mode:: 这个参数可以使主服务器在开启时作为备用服务器启动。
  • recovery_target_timeline:你可以用它来设置恢复时间。

要建立一个连接,你需要提供用户名、IP地址和密码作为primary_conninfo参数的值。比如说。

 primary_conninfo = 'host=192.168.0.26 port=5432 user=rep_user password=rep_pass'
第3步:重启二级服务器

最后,你可以重启辅助服务器来完成配置过程。

然而,流式复制伴随着几个挑战,例如:

  • 各种PostgreSQL客户端(用不同的编程语言编写)与一个端点进行交流。当主节点发生故障时,这些客户端将不断重试相同的DNS或IP名称。这使得故障转移对应用程序是可见的。
  • PostgreSQL复制没有内置的故障转移和监控。当主节点失败时,你需要推广一个辅助节点成为新的主节点。这种推广需要以客户只写到一个主节点的方式执行,而且他们不会观察到数据的不一致性。
  • PostgreSQL会复制其整个状态。当你需要开发一个新的二级节点时,二级节点需要从主节点上重现整个状态变化的历史,这是资源密集型的,并且使得消除头部的节点并创建新的节点的成本很高。

方法2:复制的块设备

复制块设备的方法依赖于磁盘镜像(也被称为卷复制)。在这种方法中,变化被写入一个持久的卷,它被同步地镜像到另一个卷。

这种方法的额外好处是它在云环境中与所有关系型数据库的兼容性和数据耐久性,包括PostgreSQL、MySQL和SQL Server等等。

然而,PostgreSQL复制的磁盘镜像方法需要你同时复制WAL日志和表数据。由于现在对数据库的每一次写入都需要通过网络同步进行,你不能失去一个字节,因为这可能会使你的数据库处于损坏状态。

这种方法通常是利用Azure PostgreSQL和Amazon RDS来实现的。

方法3:WAL

WAL由分段文件(默认为16MB)组成。每个段有一个或多个记录。日志序列记录(LSN)是一个指向WAL中的记录的指针,让你知道记录在日志文件中被保存的位置/地点。

备用服务器利用WAL段--在PostgreSQL术语中也被称为XLOGS--来持续复制来自主服务器的变化。你可以在DBMS中使用写前日志,通过将字节数组数据块(每个都有唯一的LSN)序列化到稳定的存储中,然后再应用到数据库中,来赋予数据库的耐久性和原子性。

将突变应用于数据库可能导致各种文件系统操作。一个相关的问题是,当一个数据库正在进行文件系统更新时,由于停电导致服务器故障,数据库如何保证原子性。当数据库启动时,它开始启动或重放进程,可以读取可用的WAL段,并将其与存储在每个数据页上的LSN进行比较(每个数据页都被标记为影响该页的最新WAL记录的LSN)。

基于日志运输的复制(块级)

流式复制完善了日志运输过程。相对于等待WAL切换,记录是在创建时发送的,因此减少了复制延迟。

流复制也胜过了日志运输,因为备用服务器通过网络与主服务器链接,利用了复制协议。主服务器可以通过这个连接直接发送WAL记录,而不需要依赖终端用户提供的脚本。

基于日志运输的复制(文件级)

日志运输被定义为将日志文件复制到另一个PostgreSQL服务器,通过重放WAL文件生成另一个备用服务器。这个服务器被配置为在恢复模式下工作,它的唯一目的是应用任何新的WAL文件,因为它们出现了。

这个备用服务器然后成为主PostgreSQL服务器的一个热备份。它也可以被配置为一个读副本,在那里它可以提供只读查询,也被称为热备用。

连续的WAL归档

将创建的WAL文件复制到pg_wal 子目录以外的任何位置来归档,这被称为WAL归档。在每次创建WAL文件时,PostgreSQL都会调用一个由用户提供的脚本进行存档。

该脚本可以利用scp 命令将文件复制到一个或多个位置,如NFS挂载。一旦归档,就可以利用WAL段文件来恢复任何给定时间点的数据库。

其他基于日志的配置包括:

  • 同步复制:在每个同步复制事务被提交之前,主服务器会等待,直到备用服务器确认他们得到了数据。这种配置的好处是,不会出现由于平行写入过程而引起的任何冲突。
  • 同步的多主机复制:在这里,每个服务器都可以接受写请求,在每个事务被提交之前,修改的数据会从原始服务器传输到其他每个服务器。它利用了2PC协议并遵守全有或全无的规则。

WAL流协议的细节

在备用服务器上运行的被称为WAL接收器的进程,利用recovery.confprimary_conninfo 参数中提供的连接细节,通过利用TCP/IP连接来连接到主服务器。

为了启动流式复制,前端可以在启动消息中发送复制参数。一个布尔值为true、yes、1或ON,让后端知道它需要进入物理复制的walsender模式。

WAL发送器是在主服务器上运行的另一个进程,负责在WAL记录生成时将其发送到备用服务器。WAL接收器将WAL记录保存在WAL中,就像它们是由本地连接的客户端活动创建的一样。

一旦WAL记录到达WAL段文件,备用服务器就会不断重放WAL,以便主用和备用都是最新的。

A flow diagram depicting the steps involved in the WAL Streaming Protocol process between the primary and standby servers.

WAL流协议流程图 (图片来源:EnterpriseDB)

PostgreSQL复制的要素

在本节中,你将对PostgreSQL复制的常用模型(单主和多主复制)、类型(物理和逻辑复制)和模式(同步和异步)有更深入的了解。

PostgreSQL数据库复制的模式

可扩展性是指在现有的节点上增加更多的资源/硬件,以提高数据库存储和处理更多数据的能力,这可以在水平和垂直方向上实现。PostgreSQL复制是水平扩展性的一个例子,它比垂直扩展性更难实现。我们主要可以通过单主复制(SMR)和多主复制(MMR)来实现水平扩展性。

单主复制允许只在单个节点上修改数据,而这些修改被复制到一个或多个节点上。复制数据库中的复制表不允许接受任何修改,除了来自主服务器的修改。即使他们这样做了,这些变化也不会被复制回主服务器。

大多数时候,SMR对应用来说已经足够了,因为它的配置和管理不那么复杂,也没有冲突的机会。单主复制也是单向的,因为复制数据主要在一个方向流动,从主数据库到复制数据库。

在某些情况下,仅靠SMR可能是不够的,你可能需要实施MMR。MMR允许一个以上的节点充当主节点。在一个以上的指定主数据库中对表行的改变会被复制到其他每个主数据库中的对应表。在这种模式下,经常采用冲突解决方案来避免重复主键等问题。

使用MMR有几个优点,即。

  • 在主机故障的情况下,其他主机仍然可以给予更新和插入服务。
  • 主节点分布在几个不同的地方,所以所有主节点发生故障的机会非常小。
  • 能够采用广域网络(WAN)的主数据库,在地理上可以接近客户群,但又能保持整个网络的数据一致性。

然而,实施MMR的缺点是复杂性和它难以解决冲突。

由于PostgreSQL不原生支持MMR,所以有几个分支和应用程序提供MMR解决方案。这些解决方案可能是开源的,免费的,或付费的。一个这样的扩展是双向复制(BDR),它是异步的,是基于PostgreSQL的逻辑解码功能。

由于BDR应用复制了其他节点上的事务,如果正在应用的事务和在接收节点上提交的事务之间有冲突,重放操作可能会失败。

PostgreSQL 复制的类型

有两种类型的PostgreSQL复制:逻辑复制和物理复制。

纠结于停机时间和WordPress问题?Kinsta是为节省你的时间而设计的托管解决方案!

一个简单的逻辑操作 "initdb "将进行物理操作,为一个集群创建一个基础目录。同样,一个简单的逻辑操作 "CREATE DATABASE "将执行在基础目录下创建一个子目录的物理操作。

物理复制通常处理的是文件和目录。它不知道这些文件和目录代表什么。这些方法用于维护单个集群的全部数据的完整副本,通常是在另一台机器上,在文件系统级或磁盘级进行,并使用精确的块地址。

逻辑复制是一种复制数据实体及其修改的方式,基于它们的复制身份(通常是一个主键)。与物理复制不同,它处理数据库、表和DML操作,并在数据库集群层面完成。它使用一个发布订阅模型,其中一个或多个订阅者被订阅到发布者节点上的一个或多个出版物

复制过程开始于对发布者数据库上的数据进行快照,然后将其复制到订阅者身上。订阅者从他们订阅的出版物中提取数据,并可能在以后重新发布数据,以允许级联复制或更复杂的配置。订阅者按照与发布者相同的顺序应用数据,这样就保证了单一订阅中的出版物的事务性一致性,也被称为事务性复制。

逻辑复制的典型用例是:

  • 在单个数据库(或数据库的一个子集)发生变化时,将其增量发送给订阅者。
  • 在多个数据库之间共享数据库的一个子集。
  • 当个别变化到达用户时,触发它们的启动。
  • 将多个数据库合并为一个数据库。
  • 为不同的用户组提供对复制的数据的访问。

用户数据库的行为与其他PostgreSQL实例相同,并且可以通过定义其出版物作为其他数据库的发布者使用。

当订阅者被应用视为只读时,不会有来自单一订阅的冲突。另一方面,如果有其他的写,无论是由应用程序还是由其他订阅者对同一组表进行的写,就会产生冲突。

PostgreSQL同时支持这两种机制。逻辑复制允许对数据复制和安全进行细粒度的控制。

复制模式

PostgreSQL的复制主要有两种模式:同步和异步。同步复制允许数据同时写入主服务器和辅助服务器,而异步复制则确保数据首先写入主机,然后再复制到辅助服务器。

在同步模式复制中,只有当这些变化被复制到所有的副本时,主数据库上的事务才被认为是完整的。复制服务器必须一直可用,才能使主数据库上的事务得以完成。复制的同步模式用于有即时故障转移要求的高端事务环境。

在异步模式下,主服务器上的事务在只在主服务器上做了更改后,就可以宣布完成。然后,这些变化会在稍后的时间里被复制到副本中。复制服务器可以在一定时间内保持不同步,称为复制滞后。在崩溃的情况下,可能会发生数据丢失,但异步复制提供的开销很小,所以在大多数情况下是可以接受的(它不会使主机负担过重)。从主数据库到辅助数据库的故障转移比同步复制要长。

如何设置PostgreSQL复制

在本节中,我们将演示如何在Linux操作系统上设置PostgreSQL的复制过程。在这个例子中,我们将使用Ubuntu 18.04 LTS和PostgreSQL 10。

重要提示

请确保你已经安装了Linux Ubuntu服务器。下面提到了在Linux服务器上安装PostgreSQL的步骤,接着是在主服务器和辅助服务器上设置复制。

让我们开始吧!

安装

你将通过以下步骤开始在Linux上安装PostgreSQL。

  1. 首先,你必须通过在终端输入以下命令来导入PostgreSQL的签名密钥。

     wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | sudo apt-key add -
    
  2. 然后,通过在终端键入下面的命令来添加PostgreSQL存储库。

     echo "deb http://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main" | sudo tee /etc/apt/sources.list.d/postgresql.list 
    
  3. 通过在终端键入下面的命令来更新存储库索引。

     sudo apt-get update 
    
  4. 使用 apt 命令安装 PostgreSQL 软件包。

     sudo apt-get install -y postgresql-10
    
  5. 最后,使用下面的命令为PostgreSQL用户设置密码。

     sudo passwd postgres
    

在开始PostgreSQL复制过程之前,主服务器和辅助服务器都必须安装PostgreSQL。

一旦你在两台服务器上都设置了PostgreSQL,你就可以继续进行主服务器和辅助服务器的复制设置。

在主服务器中设置复制

一旦你在主服务器和辅助服务器上都安装了PostgreSQL,就进行这些步骤。

  1. 首先,用下面的命令登录到PostgreSQL数据库。

     su - postgres
    
  2. 用下面的命令创建一个复制用户。

     psql -c "CREATEUSER replication REPLICATION LOGIN CONNECTION LIMIT 1 ENCRYPTED PASSWORD'YOUR_PASSWORD';"
    
  3. 用Ubuntu中的任何nano应用程序编辑pg_hba.cnf,并添加以下配置: 文件编辑 命令

     nano /etc/postgresql/10/main/pg_hba.conf
    

    要配置文件,使用下面的命令。

     host replication  replication  MasterIP/24  md5
    
  4. 打开并编辑postgresql.conf,在主服务器中放入以下配置。

     nano /etc/postgresql/10/main/postgresql.conf
    

    使用以下配置设置。

     listen_addresses = 'localhost,MasterIP'
    
     wal_level = replica
    
     wal_keep_segments = 64
    
     max_wal_senders = 10
    
  5. 最后,重新启动主服务器中的PostgreSQL。

 systemctl restart postgresql

现在你已经完成了主服务器中的设置。

在二级服务器中设置复制

按照这些步骤来设置辅助服务器中的复制。

  1. 用下面的命令登录到PostgreSQL RDMS。

     su - postgres
    
  2. 用下面的命令停止PostgreSQL服务的工作,使我们能够对它进行工作。

     systemctl stop postgresql
    
  3. 用这个命令编辑pg_hba.conf文件并添加以下配置。编辑命令

     nano /etc/postgresql/10/main/pg_hba.conf
    

    配置

     host replication  replication  MasterIP/24  md5
    
  4. 打开并编辑辅助服务器中的postgresql.conf,并放入以下配置,如果有注释则取消注释**:编辑命令**
    配置

     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是辅助服务器的地址

  5. 访问辅助服务器中的PostgreSQL数据目录,并删除一切。

     cd /var/lib/postgresql/10/main
    
     rm -rfv *
    
  6. 将PostgreSQL主服务器的数据目录文件复制到PostgreSQL副服务器的数据目录,并在副服务器上写下这个命令。

     pg_basebackup -h MasterIP -D /var/lib/postgresql/11/main/ -P -U
    
     replication --wal-method=fetch
    
  7. 输入主服务器的PostgreSQL密码并按回车键。接下来,为恢复配置添加以下命令。编辑命令

     nano /var/lib/postgresql/10/main/recovery.conf
    

    配置

     standby_mode   = 'on'
    primary_conninfo = 'host=MasterIP port=5432 user=replication password=YOUR_PASSWORD'
    trigger_file = '/tmp/MasterNow'
    

    这里,YOUR_PASSWORD是主服务器中PostgreSQL创建的复制用户的密码。

  8. 一旦设置了密码,你就必须重新启动二级PostgreSQL数据库,因为它被停止了。

systemctl start postgresql

测试你的设置

现在我们已经执行了这些步骤,让我们测试一下复制过程,观察一下次要服务器的数据库。为此,我们在主服务器上创建一个表,并观察是否同样反映在辅助服务器上。

让我们开始吧。

  1. 由于我们是在主服务器上创建表,你需要登录到主服务器。

     su - postgres
    psql
    
  2. 现在我们创建一个名为 "testtable "的简单表,并通过在终端运行以下PostgreSQL查询来向该表插入数据。

     CREATE TABLE testtable (websites varchar(100));
    INSERT INTO testtable VALUES ('section.com');
    INSERT INTO testtable VALUES ('google.com');
    INSERT INTO testtable VALUES ('github.com');
    
  3. 通过登录到辅助服务器观察辅助服务器的PostgreSQL数据库。

     su - postgres psql
    
  4. 现在,我们检查表'testtable'是否存在,并可以通过在终端运行以下PostgreSQL查询来返回数据。这个命令基本上可以显示整个表。

     select * from testtable;
    

这是测试表的输出。

|  websites  |

-------------------

| section.com |

| google.com |

| github.com  |

--------------------

你应该能够观察到与主服务器中的数据相同。

如果你看到上面的情况,那么你已经成功地进行了复制过程!

PostgreSQL手动故障转移的步骤是什么?

让我们来看看PostgreSQL手动故障转移的步骤。

  1. 使主服务器崩溃。

  2. 通过在备用服务器上运行下面的命令来促进备用服务器的发展。

    ./pg_ctl promote -D ../sb_data/
    server promoting
    
  3. 连接到升级后的备用服务器,并插入一条记录。

     -bash-4.2$ ./edb-psql -p 5432 edb
    
    Password:
    
    psql.bin (10.7)
    
    Type "help" for help.
    
    edb=# insert into abc values(4,'Four');
    

如果插入工作正常,那么备用服务器,以前是只读服务器,已经被提升为新的主服务器。

如何在PostgreSQL中自动进行故障转移

设置自动故障转移很容易。

你将需要EDB PostgreSQL故障转移管理器(EFM)。在每个主节点和备用节点上下载并安装EFM后,你可以创建一个EFM集群,它由一个主节点、一个或多个备用节点和一个可选的Witness节点组成,在故障时确认断言。

EFM持续监控系统健康状况,并根据系统事件发送电子邮件警报。当故障发生时,它会自动切换到最新的备用节点,并重新配置所有其他的备用服务器以识别新的主节点。

它还可以重新配置负载均衡器(如pgPool),并防止 "大脑分裂"(当两个节点都认为自己是主节点时)的发生。

总结

由于数据量大,可扩展性和安全性已经成为数据库管理中最重要的两个标准,特别是在交易环境中。虽然我们可以通过在现有的节点上增加更多的资源/硬件来提高纵向的可扩展性,但这并不总是可能的,往往是由于增加新硬件的成本或限制。

因此,需要横向可扩展性,这意味着在现有网络节点上增加更多的节点,而不是增强现有节点的功能。这就是PostgreSQL复制的作用。