本节概述如何在 1 个或多个数据库副本上设置异步流复制。

在 Timescale 上免费试用

Timescale 是一款完全托管的服务,提供自动备份和恢复、复制的高可用性、无缝扩展和调整大小等等。您可以免费试用 Timescale 30 天。

免费试用

在开始之前,请确保您至少运行了 2 个独立的 TimescaleDB 实例。如果您使用 Docker 容器安装了 TimescaleDB,请使用 PostgreSQL 入口脚本 运行配置。有关更高级的示例,请参见 Timescale Helm Charts 存储库

要配置自托管 TimescaleDB 上的复制,您需要执行以下步骤

  1. 配置主数据库
  2. 配置复制参数
  3. 创建复制槽
  4. 配置基于主机的身份验证参数
  5. 在副本上创建基本备份
  6. 配置复制和恢复设置
  7. 验证副本是否正常工作

要配置主数据库,您需要一个具有允许其初始化流复制的角色的 PostgreSQL 用户。每个副本使用此用户从主数据库进行流式传输。

  1. 在主数据库上,以具有超级用户权限的用户(例如 postgres 用户)的身份,将密码加密级别设置为 scram-sha-256

    SET password_encryption = 'scram-sha-256';
  2. 创建一个名为 repuser 的新用户

    CREATE ROLE repuser WITH REPLICATION PASSWORD '<PASSWORD>' LOGIN;
重要

scram-sha-256 密码加密级别是 PostgreSQL 中最安全的基于密码的身份验证方式。它仅在 PostgreSQL 10 及更高版本中可用。

postgresql.conf 配置文件中,需要添加或编辑多个复制设置。

  1. synchronous_commit 参数设置为 off
  2. max_wal_senders 参数设置为来自副本或备份客户端的并发连接总数。至少,这应该等于您打算拥有的副本数量。
  3. wal_level 参数设置为写入 PostgreSQL 预写日志 (WAL) 的信息量。要使复制正常工作,WAL 中需要有足够的数据来支持归档和复制。默认值通常是合适的。
  4. max_replication_slots 参数设置为主数据库可以支持的复制槽总数。
  5. listen_addresses 参数设置为主数据库的地址。不要将此参数保留为本地环回地址,因为远程副本必须能够连接到主服务器才能流式传输 WAL。
  6. 重新启动 PostgreSQL 以获取更改。这必须在您创建复制槽之前完成。

最常见的流复制用例是使用一个或多个副本进行异步复制。在此示例中,WAL 会流式传输到副本,但主服务器不会等待确认 WAL 是否已写入副本上的磁盘。这是性能最高的复制配置,但它确实存在系统故障时可能丢失少量数据的风险。它也不能保证副本与主服务器完全同步,这会导致主服务器和副本上的读取查询之间出现不一致。此用例的示例配置

listen_addresses = '*'
wal_level = replica
max_wal_senders = 2
max_replication_slots = 2
synchronous_commit = off

如果您需要在副本上获得更强的一致性,或者您的查询负载过重,导致异步模式下主节点和副本节点之间出现明显的延迟,请考虑使用同步复制配置。有关不同复制模式的更多信息,请参见 复制模式部分

配置完 postgresql.conf 并重新启动 PostgreSQL 后,您可以为每个副本创建 复制槽。复制槽可确保主服务器不会在副本接收到 WAL 段之前将其从 WAL 中删除。如果副本长时间停机,这很重要。主服务器需要验证 WAL 段是否已被副本使用,以便可以安全地删除数据。您可以使用 归档 来实现此目的,但复制槽为流复制提供了最强的保护。

  1. psql 槽中,创建第一个复制槽。槽的名称是任意的。在此示例中,它被称为 replica_1_slot

    SELECT * FROM pg_create_physical_replication_slot('replica_1_slot');
  2. 对每个所需的复制槽重复此操作。

pg_hba.conf 配置文件中,需要添加或编辑多个复制设置。在此示例中,这些设置将复制连接限制为来自 REPLICATION_HOST_IP 的流量,作为具有有效密码的 PostgreSQL 用户 repuserREPLICATION_HOST_IP 可以从该机器发起流复制,无需其他凭据。您可以更改 addressmethod 值以匹配您的安全和网络设置。

有关 pg_hba.conf 的更多信息,请参见 pg_hba 文档

  1. 打开 pg_hba.conf 配置文件并添加或编辑以下行

    TYPE DATABASE USER ADDRESS METHOD AUTH_METHOD
    host replication repuser <REPLICATION_HOST_IP>/32 scram-sha-256
  2. 重新启动 PostgreSQL 以获取更改。

副本通过流式传输主服务器的 WAL 日志并在 PostgreSQL 恢复模式下重放其事务来工作。为此,副本需要处于可以重放日志的状态。您可以通过从主实例的基本备份中恢复副本来实现此目的。

  1. 停止 PostgreSQL 服务。

  2. 如果副本数据库中已经包含数据,请在运行备份之前将其删除,方法是删除 PostgreSQL 数据目录

    rm -rf <DATA_DIRECTORY>/*

    如果您不知道数据目录的位置,请使用 show data_directory; 命令找到它。

  3. 使用主数据库的 IP 地址和复制用户名从基本备份中恢复

    pg_basebackup -h <PRIMARY_IP> \
    -D <DATA_DIRECTORY> \
    -U repuser -vP -W

    -W 标志会提示您输入密码。如果您在自动化设置中使用此命令,您可能需要使用 pgpass 文件

  4. 备份完成后,在您的数据目录中创建一个 standby.signal 文件。当 PostgreSQL 在其数据目录中找到 standby.signal 文件时,它将在恢复模式下启动并通过复制协议流式传输 WAL

    touch <DATA_DIRECTORY>/standby.signal

成功创建基本备份和 standby.signal 文件后,您可以配置复制和恢复设置。

  1. 在副本的 postgresql.conf 文件中,添加与主服务器通信的详细信息。如果您使用的是流复制,primary_conninfo 中的 application_name 应与主服务器的 synchronous_standby_names 设置中使用的名称相同

    primary_conninfo = 'host=<PRIMARY_IP> port=5432 user=repuser
    password=<POSTGRES_USER_PASSWORD> application_name=r1'
    primary_slot_name = 'replica_1_slot'
  2. 添加详细信息以镜像主数据库的配置。如果您使用的是异步复制,请使用以下设置

    hot_standby = on
    wal_level = replica
    max_wal_senders = 2
    max_replication_slots = 2
    synchronous_commit = off

    hot_standby 参数必须设置为 on,以允许在副本上执行只读查询。在 PostgreSQL 10 及更高版本中,此设置默认情况下为 on

  3. 重新启动 PostgreSQL 以获取更改。

此时,您的副本应与主数据库完全同步并准备好从中进行流式传输。您可以通过检查副本上的日志来验证它是否正常工作,日志应类似于以下内容

LOG: database system was shut down in recovery at 2018-03-09 18:36:23 UTC
LOG: entering standby mode
LOG: redo starts at 0/2000028
LOG: consistent recovery state reached at 0/3000000
LOG: database system is ready to accept read only connections
LOG: started streaming WAL from primary at 0/3000000 on timeline 1

任何客户端都可以在副本上执行读取操作。您可以通过在主数据库上运行插入、更新或其他修改来验证这一点,然后查询副本以确保它们已正确复制。

在大多数情况下,异步流复制就足够了。但是,您可能需要在主服务器和副本之间获得更高的一致性,尤其是在工作负载较重的情况下。在工作负载过重的情况下,副本可能会远远落后于主服务器,从而向从副本读取的客户端提供陈旧的数据。此外,在任何数据丢失都是致命的的情况下,异步复制可能无法提供足够的持久性保证。PostgreSQL 的 synchronous_commit 功能具有多个选项,具有不同的性能和一致性权衡。

postgresql.conf 文件中,将 synchronous_commit 参数设置为

  • on:这是默认值。在 WAL 事务写入主服务器上的磁盘以及任何副本上的磁盘之前,服务器不会返回 success
  • off:当 WAL 事务已发送到操作系统以写入主服务器上的磁盘上的 WAL 时,服务器将返回 success,但不会等待操作系统实际写入它。如果服务器在某些数据尚未写入时崩溃,这会导致少量数据丢失,但不会导致数据损坏。关闭 synchronous_commit 是 PostgreSQL 的一个众所周知的优化,适用于能够承受系统崩溃时某些数据丢失的工作负载。
  • local:仅在主服务器上强制执行 on 行为。
  • remote_write:当 WAL 记录已发送到操作系统以写入副本上的 WAL 时,数据库将向客户端返回 success,但在确认记录已实际持久保存到磁盘之前。这类似于异步提交,但它还会等待副本以及主服务器。实际上,等待副本而产生的额外等待时间会显著减少复制延迟。
  • remote_apply:要求确认 WAL 记录已写入 WAL 并应用到所有副本上的数据库。这提供了所有 synchronous_commit 选项中最强的持久性。在此模式下,副本始终反映主服务器的最新状态,复制延迟几乎不存在。
重要

如果 synchronous_standby_names 为空,则设置 onremote_applyremote_writelocal 都提供相同的同步级别,并且事务提交将等待本地刷新到磁盘。

此矩阵显示了每种模式提供的的一致性级别

模式WAL 发送到操作系统(主服务器)WAL 持久化(主服务器)WAL 发送到操作系统(主服务器和副本)WAL 持久化(主服务器和副本)事务应用(主服务器和副本)
关闭
本地
远程写入
开启
远程应用

synchronous_standby_names 设置是 synchronous_commit 的补充设置。它列出了主数据库支持用于同步复制的所有副本的名称,并配置了主数据库如何等待它们。synchronous_standby_names 设置支持以下格式

  • FIRST num_sync (replica_name_1, replica_name_2):这将等待来自前 num_sync 个副本的确认,然后返回 successreplica_names 列表决定了副本的优先级。副本名称由副本上的 application_name 设置决定。
  • ANY num_sync (replica_name_1, replica_name_2):这将等待来自提供的列表中 num_sync 个副本的确认,无论它们的优先级或在列表中的位置如何。这可以用作仲裁函数。

同步复制模式强制主服务器等待所有必需的副本写入 WAL 或应用数据库事务,具体取决于 synchronous_commit 级别。如果必需的副本崩溃,这可能会导致主服务器无限期挂起。当副本重新连接时,它会重播任何需要赶上的 WAL。只有这样,主服务器才能恢复写入。为了缓解这种情况,请在 synchronous_standby_names 设置下所需的节点数量之外配置更多节点,并将它们列在 FIRSTANY 子句中。这允许主服务器只要大多数副本已写入最新的 WAL 事务即可继续运行。不在服务的副本能够重新连接并异步重播错过的 WAL 事务。

PostgreSQL pg_stat_replication 视图提供了有关每个副本的信息。此视图对于计算复制延迟特别有用,复制延迟衡量的是副本当前状态落后于主服务器的程度。replay_lag 字段衡量了主服务器上的最新 WAL 事务与副本上最后报告的数据库提交之间的秒数。结合 write_lagflush_lag,这提供了对副本落后程度的洞察。*_lsn 字段也提供了有用的信息。它们允许您比较主服务器和副本之间的 WAL 位置。state 字段对于确定每个副本当前正在执行的操作非常有用;可用的模式包括 startupcatchupstreamingbackupstopping

要在主数据库上查看数据,请运行以下命令

SELECT * FROM pg_stat_replication;

输出如下所示

-[ RECORD 1 ]----+------------------------------
pid | 52343
usesysid | 16384
usename | repuser
application_name | r2
client_addr | 10.0.13.6
client_hostname |
client_port | 59610
backend_start | 2018-02-07 19:07:15.261213+00
backend_xmin |
state | streaming
sent_lsn | 16B/43DB36A8
write_lsn | 16B/43DB36A8
flush_lsn | 16B/43DB36A8
replay_lsn | 16B/43107C28
write_lag | 00:00:00.009966
flush_lag | 00:00:00.03208
replay_lag | 00:00:00.43537
sync_priority | 2
sync_state | sync
-[ RECORD 2 ]----+------------------------------
pid | 54498
usesysid | 16384
usename | repuser
application_name | r1
client_addr | 10.0.13.5
client_hostname |
client_port | 43402
backend_start | 2018-02-07 19:45:41.410929+00
backend_xmin |
state | streaming
sent_lsn | 16B/43DB36A8
write_lsn | 16B/43DB36A8
flush_lsn | 16B/43DB36A8
replay_lsn | 16B/42C3B9C8
write_lag | 00:00:00.019736
flush_lag | 00:00:00.044073
replay_lag | 00:00:00.644004
sync_priority | 1
sync_state | sync

PostgreSQL 提供了一些故障转移功能,在发生故障时,副本将被提升为主服务器。这是使用 pg_ctl 命令或 trigger_file 提供的。但是,PostgreSQL 不支持自动故障转移。有关更多信息,请参见 PostgreSQL 故障转移文档。如果您需要具有自动故障转移功能的可配置高可用性解决方案,请查看 Patroni

关键字

在本页上发现问题?报告问题 或 编辑此页面 在 GitHub 上。