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