共享磁盘故障转移通过仅保留一份数据库副本,来避免同步开销。其使用共享多个服务器的单一磁盘阵列。如果主数据库服务器发生故障,备用服务器能挂载并启动数据库,就像它刚从数据库奔溃中恢复一样。这可以快速故障转移,并且没有数据丢失。
网络存储设备上共享硬件功能很常见。使用网络文件系统也是可行的,但前提是要谨慎,确保文件系统拥有完全POSIX行为(参见 第 18.2.2.1 节)。这种方法有一个很大的限制就是,如果共享磁盘阵列发生故障或损坏,主服务器和备用服务器都会失效。另一个问题是,备用服务器在主服务器运行时永远不应访问共享存储。
共享硬件功能的一种修改版本就是文件系统复制,其中对文件系统的所有更改都将镜像到驻留在另一台计算机的文件系统上。唯一的限制是,复制必须以确保备用服务器拥有文件系统的一致副本的方式进行——具体而言,对备用副本的写入必须与主副本上的写入顺序相同。 DRBD 是一款针对 Linux 的热门文件系统复制解决方案。
热备用服务器和暖备用服务器可通过读取预写日志 ()WAL) 记录流来保持最新状态。如果主服务器发生故障,备用服务器会包含主服务器几乎所有数据,并且可以快速转变为新的主数据库服务器。这可以是同步或异步,并且只能对整个数据库服务器进行操作。
可以使用基于文件的日志传送 (第 26.2 节) 或流复制(参见 第 26.2.5 节),或同时采用这两种方式,来实现备用服务器。有关热备用的信息,请参见 第 26.4 节。
逻辑复制允许数据库服务器向另一台服务器发送数据修改流。
PostgreSQL 逻辑复制从 WAL 构建逻辑数据修改流。逻辑复制允许在按表为基础进行数据修改复制。此外,发布其自身更改的服务器还可订阅来自另一台服务器的更改,从而实现数据在多方向中的流动。有关逻辑复制的更多信息,请参阅第 29 章。通过逻辑解码接口 (第 47 章),第三方扩展也可以提供类似功能。基于触发器的复制设置通常会将数据修改查询集中到指定的专用服务器。执行对每个表的运算时,主服务器会(通常)异步地将数据更改发送到从属服务器。备用服务器可以在主服务器运行时回答查询,并且可能会允许某些本地数据更改或写入活动。这种形式的复制通常用于卸载大量分析或数据仓库查询。
Slony-I 是这种类型的复制示例,具有按表粒度,且支持多个从属服务器。因为它异步地(分批地)更新备用服务器,所以在故障转移期间可能会丢失数据。
使用基于 SQL 的复制中间件,程序会拦截每个 SQL 查询并将其发送到一台或所有服务器。每台服务器独立运行。读写查询必须发送到所有服务器,以便每台服务器都能接收所有更改。但是,只读查询可以只发送到一台服务器,从而允许读工作负载在它们之间进行分布。
如果仅广播未修改的查询,random()
、CURRENT_TIMESTAMP
等函数以及序列在不同服务器上可能会具有不同的值。这是因为每台服务器独立运行,并且广播的是 SQL 查询,而不是实际数据更改。如果这不被接受,中间件或应用程序必须从单一来源确定此类值,然后在写入查询中使用这些值。也必须注意,所有事务在所有服务器上要么提交要么中止,可能使用两阶段提交 (PREPARE TRANSACTION 和 COMMIT PREPARED)。 Pgpool-II 和 Continuent Tungsten 是这种类型的复制示例。
对于不定期连接或通信链路缓慢的服务器(如笔记本电脑或远程服务器),在服务器之间保持数据一致性是一个挑战。使用异步多主复制,每个服务器独立运行,并定期与其他服务器通信以识别冲突事务。冲突可以由用户或冲突解决规则解决。Bucardo 是该类复制的一个示例。
在同步多主复制中,每个服务器都可以接受写请求,修改后的数据将在每个事务提交之前从原始服务器传输到其他每个服务器。繁重的写活动可能导致过度的锁定和提交延迟,从而导致性能低。可以将读请求发送到任何服务器。某些实现使用共享磁盘以降低通信开销。同步多主复制最适合主要为读的工作负载,尽管其最大的优点是任何服务器都可以接受写请求 - 无需在主服务器和备用服务器之间划分工作负载,并且由于数据更改是从一个服务器发送到另一个服务器,因此不会出现诸如 random()
之类的非确定性函数的问题。
PostgreSQL 不提供此类复制,尽管 PostgreSQL 两阶段提交(PREPARE TRANSACTION 和 COMMIT PREPARED)可用于在应用程序代码或中间件中实现此操作。
表 26.1 总结了上述各种解决方案的功能。
表 26.1. 高可用性,负载平衡和复制功能矩阵
特征 | 共享磁盘 | 文件系统复制 | 预写日志传送 | 逻辑复制 | 基于触发器的复制 | SQL 复制中间件 | 异步 MM 复制 | 同步 MM 复制 |
---|---|---|---|---|---|---|---|---|
流行示例 | NAS | DRBD | 内置流复制 | 内置逻辑复制,pglogical | Londiste、Slony | pgpool-II | Bucardo | |
通信方法 | 共享磁盘 | 磁盘块 | WAL | 逻辑解码 | 表行 | SQL | 表行 | 表行和行锁 |
无需特殊硬件 | • | • | • | • | • | • | • | |
允许多个主服务器 | • | • | • | • | ||||
主服务器没有开销 | • | • | • | • | ||||
无需等待多台服务器 | • | 同步关闭 | 同步关闭 | • | • | |||
主故障永远不会丢失数据 | • | • | 开启同步时 | 开启同步时 | • | • | ||
备用服务器接受只读查询 | 采用热备用 | • | • | • | • | • | ||
按表粒度 | • | • | • | • | ||||
无需解决冲突 | • | • | • | • | • | • |
有少数解决方案不属于上述类别
数据分区将表拆分为数据集。每个数据集只能由一台服务器进行修改。例如,数据可以按办事处(例如伦敦和巴黎)进行分区,每个办事处都有一个服务器。如果需要查询合并伦敦和巴黎的数据,应用程序可以查询两个服务器,或者可以使用主/备用复制在每个服务器上保存另一个办事处数据的只读副本。
上述许多解决方案允许多个服务器处理多个查询,但没有一个解决方案允许单个查询使用多个服务器以更快的速度完成。此解决方案允许多个服务器同时处理单个查询。它通常通过在服务器之间拆分数据以及让每台服务器执行其部分查询并向将结果返回并返回给用户的中心服务器完成。可以使用 PL/Proxy 工具集实现这一点。
还需要注意的是,因为 PostgreSQL 是开源的并且易于扩展,一些公司已经采用了 PostgreSQL,并创建了具有独特故障转移、复制和负载平衡功能的商业闭源解决方案。这里不加以讨论。