PostgreSQL 9.4.4 中文手册
上一页 | 上一级 | 章 25. 高可用性与负载均衡，复制 | 下一页

# 25.2. 日志传送备份服务器

连续归档可以配合随时准备取代失效主服务器的一个或多个备份服务器， 用于创建一个高可用性(HA)集群。 这个能力通常被称为热备份或日志传送。

虽然主服务器和备份服务器只是松散的耦合在一起， 但它们必须同时运行。主服务器以连续归档模式运行， 备份服务器以连续恢复模式运行并从主服务器不停的读取WAL文件。 因为数据库的表无需为此进行任何改变，所以与其它复制方法相比， 额外的管理开销很小。并且这种方法对主服务器的性能影响也很小。

直接从一个数据库服务器移动WAL到另一个服务器通常被称为日志传送(LogShipping)。 PostgreSQL实现了基于文件的日志传送， 意思是WAL记录每次移动一个完整的文件(WAL段)。 WAL文件（16MB）可以被轻易的在任意两个地点之间传送， 不管是与邻近的系统还是地球另一面的系统。 所需带宽取决于主服务器的事务发生速度。 基于记录的日志传送更加细粒度，并且WAL流在网络连接中增量改变。

日志传送是异步的，也就是WAL记录在事务提交之后才被传送。 也就是说主服务器遭遇致命故障后尚未传送的事务数据将会丢失。 数据丢失的长度可以使用`archive_timeout`加以限制，比如限制为几秒钟。 当然这么小的设置也导致了传送带宽的大幅增长。 流复制（参阅第 25.2.5 节）允许数据丢失的更小窗口。

恢复性能足够好，备份服务器一旦被激活通常只有很短的时间不能使用。 因此，我们认为这个方案可以作为热备份来提供高可用性。 将服务器从一个已归档的基础备份中恢复将可能耗费大量时间， 所以这个方案只能用于灾难恢复而不能用于提供高可用性。 备用服务器还可以用于只读查询，在这种情况下它被称为热备份服务器。 参见第 25.5 节获取更多信息。

## 25.2.1. 规划

至少从数据库服务器的角度看， 创建主服务器和备份服务器并令两者尽可能完全相同是非常明智的。 特别是表空间的路径名必须保持完全一致， 这样主服务器和备份服务器就必须拥有同样的表空间挂载路径(如果使用了表空间的话)。 需要记住的是如果在主服务器上执行了CREATE TABLESPACE命令， 那么该命令需要的任何新挂载点必须在执行该命令之前同时在主服务器和备份服务器 上创建。 硬件不必完全相同，但是经验显示维护两个完全相同的系统比维护两 个不同的系统要少许多麻烦。 无论如何，应尽量保持体系结构相同— 比如一个是32-bit系统另一个是64-bit系统将不能正常工作。

通常，在主PostgreSQL版本不同的服务器之间传送日志是不可能的， 它是PostgreSQL全球开发组在次要版本升级中不能改变磁盘格式的一种策略。 在主服务器和备份服务器上运行不同的次要版本可能成功。 但是，没有正式支持，建议你尽可能的保持主服务器和备用服务器在同一个级别上。 在进行版本升级的时候，正确的做法是首先升级备份服务器— 因为新版本的服务器通常可以读取老版本的WAL文件，但反之则不然。

## 25.2.2. 备用服务器操作

在备用模式，该服务器连续应用从主服务器收取的WAL。 备服务器可以从一个WAL归档（参阅restore_command） 或直接通过一个TCP连接（流复制）从主服务器上读取WAL。 备服务器也可以在备用集群`pg_xlog`尝试查找恢复任何WAL。 这通常发生在服务器重启后，当备服务器重播，在备服务器重启前， 从主服务器流复制的WAL，但是你也可以手工复制文件到`pg_xlog`， 在任何时候可以重播它们。

在启动，备服务器恢复可用在所有的WAL开始存档位置,调用`restore_command`。 一旦它到达可用WAL的结束，`restore_command`失败， 将尝试恢复`pg_xlog`目录下任何可用的WAL。 如果那也失败了，并且已经配置了流复制，则尝试连接到主服务器， 从在归档或`pg_xlog`找到最后一条有效的记录开始WAL流。如果那也失败了， 或没有配置流复制，或连接断开，备服务器再次回到步骤1，循环尝试从归档里恢复文件。 从归档，`pg_xlog`，通过连续流复制直到服务器停止或有触发器文件触发的失效切换时。

当运行`pg_ctl promote`时，或者找到一个触发文件（`trigger_file`）时， 退出备用模式并且服务器切换到正常运行。 在失效切换前，将立即恢复归档或`pg_xlog`任何可用的WAL， 但不做尝试连接主服务器。

## 25.2.3. 为备用服务器准备主服务器

在主服务器上设置连续归档到一个备服务器可访问的存档目录， 正如第 24.3 节所描述的。即使主服务器关掉， 从备服务器应该可以访问这个归档位置。 即它应该驻留在备用服务器自身或其它可信赖的服务器上， 而不是主服务器。

如果你想使用流复制，在主服务器上设置认证，允许从备用服务器复制连接； 在`pg_hba.conf`提供一个或多个合适项使用数据库字段设置`replication`。 还要在主服务器的配置文件确保设置`max_wal_senders`足够大。 如果要使用复制槽，也要确保`max_replication_slots`设置的足够高。

启动备用服务器做一个基准备份，参见第 24.3.2 节。

## 25.2.4. 建立备用服务器

要建立备用服务器，从主服务器恢复基准备份（参阅第 24.3.4 节）。 在备用服务器的集群数据目录，创建一个恢复命令文件`recovery.conf`, 开启`standby_mode`。设置`restore_command` 为一条从WAL归档复制文件的简单命令。如果为了高可用性目的计划有多个备用服务器， 设置`recovery_target_timeline`为`latest`， 使得备用服务器按照发生故障转移到另一个备用服务器的时间变化。

> 注意: 不要使用内置在这里描述的备用模式pg_standby或类似的工具。 如果该文件不存在，`restore_command`应该立即返回。 如果必要服务器将再次尝试这个命令。 关于使用工具像pg_standby的详情参阅第 25.4 节。

如果你想使用流复制，在`primary_conninfo`填写一个libpq连接串， 其包括主机名（或IP地址）和连接到主服务器需要的其它详细信息。 如果主服务器需要个密码验证，也要在`primary_conninfo`指定所需要的密码。

如果你要建立高可用目的备服务器，设置WAL归档， 像主服务器的连接和身份验证，因为在失效切换后， 备服务器要作为主服务器运行。

如果你使用WAL归档，其大小可以使用archive_cleanup_command这个参数设置最小 ，用来删除那些备服务器不再需要的文件。 专门设计的pg_archivecleanup这个实用程序就是在通常的单备配置里， 使用`archive_cleanup_command`的。参阅pg_archivecleanup。 请注意，如果你使用备份目的归档， 你仍要保留需要恢复的至少最新的基准备份文件， 即使备服务器不再需要。

`recovery.conf`的一个简单例子：

    standby_mode = 'on'
    primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
    restore_command = 'cp /path/to/archive/%f %p'
    archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'

你可能有任何数目的备服务器，但是如果你用流复制， 确保你在主服务器上设置的`max_wal_senders`足够大允许它们同时连接。

## 25.2.5. 流复制

与基于文件日志传送相比，流复制允许保持备服务器更新。 备服务器连接主服务器，其产生的流WAL记录到备服务器， 而不需要等待填写WAL文件。

流复制是异步的，参阅第 25.2.8 节， 在主服务器上提交事务和备用服务器上变化可见之间有一个小的延迟。 这个延迟远小于基于文件日志传送，通常1秒内足够与负载保持。 使用流复制，为减少数据丢失窗口`archive_timeout`不是必要的。

如果使用流复制而不是基于文件连续归档，主服务器可能在备服务器接收到它们之前回收老的WAL段。 如果发生了这种情况，备用服务器将需要从新的基础备份中重新初始化。 你可以通过设置`wal_keep_segments`为一个足够大的值， 确保WAL段不那么早的回收或者通过为备用服务器配置一个复制槽来避免这种情况。 如果你设置一个备服务器可访问的WAL归档，那么就不需要这些解决方法了， 因为保持供给备用服务器足够的WAL段，那么它总是可以使用这些归档来赶上主服务器的变化。

要使用流复制，建立一个基于文件的日志传送备服务器描述在第 25.2 节。 该步将一个基于文件的日志传送备服务器转为流复制备服务器， 在`recovery.conf`文件中设置`primary_conninfo`指向主服务器。 在主服务器上设置listen_addresses和身份验证选项 （参阅`pg_hba.conf`）， 因此备用服务器可以连接到在主服务器的`replication`伪数据库 （参阅第 25.2.5.1 节）。

系统上支持保持活动的套接字选项， 设置tcp_keepalives_idle, tcp_keepalives_interval和 tcp_keepalives_count 帮助主机及时发现断开的连接。

设置备用服务器的最大并发连接数。 （参阅max_wal_senders获取更多详细信息）。

当启动了备服务器并且正确设置了`primary_conninfo`, 该备服务器在回放所有可用的WAL文件后，将连接到主服务器。如果成功建立了该连接， 你将在备服务器中看到WAL接收进程，并且在主服务器相应的一个WAL发送进程。

### 25.2.5.1. 身份验证

复制的访问权限设置是很重要的，所以只有受信任的用户可以读取WAL流， 因为很容易从中提取权限信息。备服务器必须验证作为主服务器的超级用户或者有 `REPLICATION`权限的用户。 建议为复制创建一个带有`REPLICATION`和`LOGIN`权限的专有用户账号。 当`REPLICATION`权限有很高权限时，不允许用户修改主服务器上的任何数据， 其中`SUPERUSER`就是这样的。

由一条`pg_hba.conf`记录指定`replication`在`database`字段， 控制客户端的复制验证。例如，如果备服务器是运行在主机IP `192.168.1.100`和复制时超级用户名为`foo`， 管理员可以在主服务器`pg_hba.conf`文件里添加下面行：

    # Allow the user "foo" from host 192.168.1.100 to connect to the primary
    # as a replication standby if the user's password is correctly supplied.
    #
    # TYPE  DATABASE        USER            ADDRESS                 METHOD
    host    replication     foo             192.168.1.100/32        md5

主服务器的主机名和端口号，连接用户名，和在`recovery.conf`文件指定的密码。 该密码也可以在备服务器的`~/.pgpass`文件里设置。 （在`database`字段指定`replication`）。例如， 如果主服务器是运行的主机IP `192.168.1.50`,端口号`5432`, 复制时用户名为`foo`，和密码为`foopass`， 管理员可以在备服务的`recovery.conf`文件里添加下面行：

    # The standby connects to the primary that is running on host 192.168.1.50
    # and port 5432 as the user "foo" whose password is "foopass".
    primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'

### 25.2.5.2. 监控

流复制的一个重要的健康指标是在主服务器生成的WAL记录数， 而不是在备服务器应用的数量。通过比较在主服务器当前WAL写的位置和备服务器收到 的最后一个WAL位置，就可以计算出这种滞后。 在主服务器上使用`pg_current_xlog_location`和在备服务器上使用 `pg_last_xlog_receive_location`可以分别检索到它们 （参阅表 9-65和 表 9-66关于详细信息）。 在备服务器收到最后的WAL位置也会进程状态的WAL接收进程显示， 使用`ps`命令显示（参阅第 27.1 节关于详细信息）。

你可以通过 `pg_stat_replication`视图回收WAL发送程序列表。 在`pg_current_xlog_location`和`sent_location`字段之间的不同可能表明 主服务器在大负载下，而备库上`sent_location`和 `pg_last_xlog_receive_location`的不同可能表明网络延迟，或者备库也处于重大负载之下。

## 25.2.6. 复制槽

复制槽提供一种自动的方式确保主服务器不删除WAL段，直到所有备用服务器都接收到了这些WAL段， 并且确保主服务器不删除会导致恢复冲突 的行，即使备用服务器是断开连接的。

为了替代使用复制槽，通过使用wal_keep_segments， 或使用archive_command存储WAL段在一个归档中都有可能阻止删除老的WAL段。 不过，这些方法经常导致保持比需要的更多的WAL段，而复制槽仅保持那些已知需要的WAL段数量。 这些方法的一个好处是，它们绑定`pg_xlog`所需的空间； 这是复制槽目前无法做到的。

相似的，hot_standby_feedback和 vacuum_defer_cleanup_age保护那些被vacuum删除的行的相关行， 但是前者在备用服务器没有连接之前的任意时间段都不提供保护， 后者经常需要设置为一个高值以提供足够的保护。复制槽克服了这些缺点。

### 25.2.6.1. 查询和操作复制槽

每个复制槽都有一个名字，名字可以包含小写字母、数字和下划线。

现有的复制槽和它们的状态可以在 `pg_replication_slots` 视图中看到。

可以通过流复制协议（参阅第 49.3 节）， 或者通过SQL函数（参阅第 9.26.6 节） 创建和删除复制槽。

### 25.2.6.2. 配置示例

你可以像下面这样创建一个复制槽：

    postgres=# SELECT * FROM pg_create_physical_replication_slot('node_a_slot');
      slot_name  | xlog_position
    -------------+---------------
     node_a_slot |

    postgres=# SELECT * FROM pg_replication_slots;
      slot_name  | slot_type | datoid | database | active | xmin | restart_lsn
    -------------+-----------+--------+----------+--------+------+-------------
     node_a_slot | physical  |        |          | f      |      |
    (1 row)

要配置备用服务器使用这个槽，应该在该备用服务器的`recovery.conf` 中配置`primary_slot_name`。下面是一个简单的示例：

    standby_mode = 'on'
    primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
    primary_slot_name = 'node_a_slot'

## 25.2.7. 级联复制

级联复制功能允许备用服务器接受复制连接和到其他备库的流WAL记录，充当延迟。 这可以用来降低直接连接主库的数量，同时也尽量减少站点间的带宽开销。

同时充当接收器和发送器的待机称为级联 待机状态。更直接地连接到主库的备库作为上游服务器已知， 而备用服务器较远的下游服务器。级联复制不放在数量限制或 下游服务器的安排，虽然每个备库连接到一个上流服务器， 而最终链接到一个单一的主/主服务器。

级联备库不仅仅发送来自主库的WAL记录，而且来自归档的记录。 因此即使一些上流连接的复制连接终止， 连接复制继续往下只要有新的WAL记录可用。

级联复制当前是异步的，同步复制（参阅第 25.2.8 节）设置当前不影响级联复制。

热备用反馈传播到上游，无论级联配置。

如果上游备用服务器上升成为新主库，下游服务器将继续流向新主库， 如果`recovery_target_timeline`设置为`'latest'`。

使用级联复制，建立连锁备库从而接受复制连接（即设置 max_wal_senders和hot_standby， 以及配置host-based authentication）。 在下游备库指向级联备库中你还需要设定`primary_conninfo`。

## 25.2.8. 同步复制

PostgreSQL流复制缺省是异步的。如果主服务器崩溃，然后一些事务承诺不得不 复制到备用服务器，造成数据丢失。数据丢失量是与故障转移时的复制延迟是成比例的。

同步复制提供确认所有变化已经由事务转移到一个同步备用服务器的能力。 这延伸一个事务提交的耐久性标准。 这种级别的保护是指2-安全复制的计算机科学理论。

当请求同步复制，每次提交的写事务将等待直到确认收到提交已被写入到主库和备用服务器磁盘上的事务日志。 这些数据丢失的可能性是如果主库和备库同一时间遭受崩溃。 这可以提供一个更高层次的耐久性，但如果系统管理员对两个服务器的安置和管理非常谨慎。 等待确认增加用户的信心，在服务器崩溃的情况下更改将不会丢失，而是增加请求事务的响应时间。 最小等待时间是主库到备库的往返时间。

只读事务和事务回滚不需要等待从备用服务器的回复。 子事务提交不等待从备用服务器的响应，只有顶级提交。 长时间运行动作如加载数据或索引建立不等待直到最后提交信息。 所有的两阶段提交的行动需要提交等待，包括准备和提交。

### 25.2.8.1. 基础配置

一旦流复制已配置，配置同步复制仅需要一个额外的配置步骤： synchronous_standby_names必须设置为 一个非空值。`synchronous_commit`也必须设置为`on`， 但因为这是默认值，通常是没有改变的。 （参见第 18.5.1 节和 第 18.6.2 节）。 这种配置将导致每次提交会等待确认备库书面提交记录到持久存储。 `synchronous_commit`可以由个人用户设置， 所以它可以被配置在配置文件中，特别是 用户或数据库中，或动态的应用程序中， 以保证每个事务的基础上控制耐久性。

一个提交记录已被写入到主库磁盘上，WAL记录随后被发送到待机状态。 每次一批新的WAL数据被写入磁盘时待机发送答复消息， 除非`wal_receiver_status_interval`在待机状态设置为零。 如果待机是第一个匹配的待机， 在主库上指定`synchronous_standby_names`， 从待机状态得到的答复信息将被用于唤醒用户的提交记录已被接收的等待确认。 这些参数允许管理员指定哪些备用服务器应同步备用。 注意，同步的配置复制主要针对主服务器。 命名的备用服务器必须直接连接到主库上;主库并不了解下游待机使用级联复制的服务器。

设置`synchronous_commit`到`remote_write`将 导致每个提交等待确认备库已经收到提交记录并且写入到自己的操作系统， 但不是为了该数据被刷新到磁盘上的备份。 这个设置提供了耐用性较弱保证对比`on`： 在待机状态下可能会失去操作系统崩溃时的数据， 虽然不是PostgreSQL崩溃。 然而，这是在实践中有用的设置，因为它可以减少事务响应时间。 如果主库和备库崩溃，并且主库的数据库同时被破坏了，只能发生数据丢失。

如果要求快速关机，用户将停止等待。然而，作为使用异步复制的时候，服务器将不完全 关闭直到所有WAL记录转移到目前连接的备用服务器。

### 25.2.8.2. 规划性能

同步复制通常需要仔细规划并且放置备用服务器，确保应用程序执行性能。等待 没有充分利用系统资源，但事务锁继续直到确认转移。作为一个结果， 不小心的使用同步复制会降低数据库应用性能，由于响应时间的增加和更高的竞争。

PostgreSQL允许应用程序开发人员通过复制来指定所需的耐久性水平。这可以 对系统的总体说明，虽然它也可以被指定为特定用户或连接，甚至个别交易。

例如，一个应用程序的任务可能包括：10%的变化是重要的客户资料，而 90%的变化是不太重要的数据，如果它丢失，企业还可以更好生存，比如用户之间的聊天信息。

在应用水平（主库）指定同步复制选项，我们可以为大多数重要的变化提供同步复制 ，没有放缓总工作量体积。对于允许同步复制的高性能应用的效益来说， 应用程序级别的选项是一个重要而实用的工具。

你应该考虑到网络带宽必须大于WAL数据生成率。

### 25.2.8.3. 高可用性规划

当`synchronous_commit`设置为`on` 或者`remote_write`将等待直到同步备用响应，则进行提交。 如果最后，或只发生待机崩溃，则响应不会发生。

为避免数据丢失最好的办法是确保你不会失去你最后的同步备份。 这可以通过使用`synchronous_standby_names`命名多个 潜在的同步备用实现。 第一个命名的备库将作为同步备库使用。如果第一个失败， 则备用列表将接管同步备用角色。

当一个备库首先依附在主库时，不能正确地同步。 这是`catchup`方式所描述的。 一旦备库和主库之间的滞后达到零，第一次我们将实时状态`流`。 备库被创建后，持续追赶时间可能长。如果备库关闭， 然后追赶时期将随着待机时间长度而增加。 一旦已经达到`流`状态，备库是唯一能够成为同步备用。

如果主库启动而提交等待确认，这些等待事务将被标记为完全提交，一旦主数据库恢复。 没有办法确保在主库崩溃的时候所有备库收到所有优秀的WAL数据。 一些事务可能不会在待机时显示提交，即使他们表现为主库已提交。 我们提供的保障是应用程序将不会接收事务成功提交的明确承认， 直到被备库安全接收WAL数据是已知的。

如果你真的失去了你最后的备用服务器，你应该禁用 `synchronous_standby_names`并且在主服务器 重新加载配置文件。

如果主库是从剩余备用服务器分离的， 你应该故障转移到那些其他剩余备用服务器的最佳人选。

如果你需要重新创建备用服务器，当等待事务时，确保pg_start_backup()和 pg_stop_backup()在带有`synchronous_commit` = `off`的回话中运行， 否则这些请求将永远等待备库出现。

上一页 | 起始页 | 下一页
不同解决方案的比较 | 上一级 | 失效切换