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

在 Timescale 上免费试用

Timescale 是一项完全托管的服务,具有自动备份和恢复、具有复制功能的高可用性、无缝扩展和调整大小等等。您可以免费试用 Timescale 三十天。

免费试用

在开始之前,请确保您至少运行了两个独立的 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 段是否已被副本使用,以便它可以安全地删除数据。您可以使用归档来实现此目的,但复制槽为流复制提供了最强的保护。

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

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

需要在 pg_hba.conf 配置文件中添加或编辑几个复制设置。在此示例中,这些设置将复制连接限制为来自 REPLICATION_HOST_IP 的流量,作为 PostgreSQL 用户 repuser 并使用有效密码。REPLICATION_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 上编辑此页面