选择 打开 改范围 完整检索页
受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10
当前 PostgreSQL 版本不在支持生命周期内。
您可以参阅当前版本的对应页面,或其他在上面列出的活跃大版本。

Chapter 26. 高可用、负载均衡和复制

数据库服务器可以协同工作,从而在主库失效时让第二台服务器快速接管其任务(高可用性),或者让多台计算机提供同一份数据(负载均衡)。理想情况下,数据库服务器应当能够无缝协同工作。提供静态网页服务的 Web 服务器只需把 Web 请求分发到多台机器,就能很容易地组合起来。事实上,只读数据库服务器也相对容易组合起来。不幸的是,大多数数据库服务器同时处理读写请求,而读/写服务器要更难组合。这是因为,只读数据只需要在每台服务器上放置一次,而对任意一台服务器的写入都必须传播到所有服务器,以保证后续对这些服务器的读取请求返回一致的结果。

这种同步问题是服务器协同工作的根本难点。由于不存在一种能够对所有使用场景都消除同步问题影响的单一方案,因此出现了多种不同的解决方案。每一种方案都以不同方式处理这个问题,并且针对特定负载将其影响降到最低。

某些方案通过只允许一台服务器修改数据来处理同步。能够修改数据的服务器称为读/写、主库(master)主库(primary)服务器。跟踪主库变更的服务器称为备库(standby)备库(secondary)。只能在被提升为主库之后才能连接的备库称为温备,而能够接受连接并提供只读查询的备库称为热备

某些方案是同步的,即一个修改数据的事务只有在所有服务器都提交该事务之后才被视为已提交。这保证一次故障切换不会丢失任何数据,并且所有负载均衡的服务器无论查询哪一台都将返回一致的结果。相反,异步方案允许一次提交与其传播到其他服务器之间存在一定延迟,这就带来了切换到备库时丢失某些事务的可能性,也意味着负载均衡的服务器可能返回略微陈旧的结果。当同步通信过慢时,就会使用异步通信。

这些方案还可以按粒度分类。有些方案只能处理整个数据库服务器,而另一些则允许在每个表或者每个数据库级别进行控制。

无论做出哪种选择,都必须考虑性能。功能与性能之间通常存在权衡。例如,在低速网络上采用完全同步的方案,性能可能下降一半以上,而异步方案对性能的影响则可能很小。

本节其余部分将概述多种故障切换、复制和负载均衡方案。

26.1. 不同方案的比较 #

共享磁盘故障切换

共享磁盘故障切换通过只保留一份数据库拷贝来避免同步开销。它使用一个由多个服务器共享的单一磁盘阵列。如果主库失效,备库就可以挂载并启动数据库,就好像它正在从一次数据库崩溃中恢复一样。这允许快速故障切换而不会丢失数据。

共享硬件功能常见于网络存储设备。使用网络文件系统也是可行的,但必须注意文件系统是否具备完整的 POSIX 行为(见Section 18.2.2)。这种方法的一大局限是,如果共享磁盘阵列失效或损坏,主库和备库都会无法工作。另一个问题是,在主库运行期间,备库绝不应访问共享存储。

文件系统(块设备)复制

共享硬件功能的一种变体是文件系统复制,其中对一个文件系统的所有更改都会镜像到位于另一台计算机上的文件系统。唯一的限制是,这种镜像必须以能够保证备库拥有该文件系统一致拷贝的方式完成 — 特别是,对备库的写入必须与主库上的写入保持相同顺序。DRBD 是 Linux 上一种流行的文件系统复制方案。

预写式日志传送

温备和热备服务器能够通过读取预写式日志(WAL)记录流来保持最新状态。如果主库失效,备库拥有主库的几乎全部数据,并且能够迅速成为新的主库。这可以是同步的,也可以是异步的,并且只能用于整个数据库服务器。

可以使用基于文件的日志传送(Section 26.2)、流复制(见 Section 26.2.5)或两者结合的方式来实现备库。有关热备的信息,见 Section 26.5

逻辑复制

逻辑复制允许数据库服务器向另一台服务器发送数据修改流。PostgreSQL 逻辑复制从 WAL 中构造逻辑数据修改流。逻辑复制允许复制单个表的数据更改,无需将某台特定服务器指定为主库或副本,而是允许数据沿多个方向流动。有关逻辑复制的更多信息,参见 Chapter 31。第三方扩展也可以通过逻辑解码接口(Chapter 49)提供类似功能。

基于触发器的主备复制

主备复制配置会将所有修改数据的查询发送到主库。主库将数据更改异步发送到备库。主库运行期间,备库可以响应只读查询。备库很适合处理数据仓库查询。

Slony-I 是这种复制类型的一个示例。它按表粒度工作,并且支持多个备库。由于它会以批处理方式异步更新备库,因此在故障切换期间可能会发生数据丢失。

基于语句的复制中间件

使用基于语句的复制中间件时,一个程序会截获每条 SQL 查询,并将其发送到一台或所有服务器。每台服务器独立运行。读写查询必须发送到所有服务器,确保每台服务器都收到所有更改。但只读查询可以只发送到一台服务器,从而将读取负载分散到这些服务器上。

如果只是原样广播查询,random()CURRENT_TIMESTAMP 等函数以及序列在不同服务器上可能产生不同的值。这是因为每台服务器独立运行,且广播的是 SQL 查询,而不是实际修改后的行。如果无法接受这种情况,中间件或应用就必须从同一台服务器查询这些值,然后在写入查询中使用这些值。另一种选择是将这种复制方式与传统主备配置结合使用,即只向主库发送修改数据的查询,再通过主备复制将其传播到备库,而不是通过复制中间件传播。还必须确保所有事务在所有服务器上要么全部提交,要么全部中止,为此可以使用两阶段提交(PREPARE TRANSACTIONCOMMIT PREPARED)。Pgpool-IIContinuent Tungsten 就是这类复制的例子。

异步多主复制

对于那些并不经常连接或通信链路较慢的服务器,例如笔记本电脑或远程服务器,保持服务器间的数据一致是一个挑战。使用异步多主复制时,每台服务器都独立工作,并定期与其他服务器通信,以识别冲突事务。这些冲突可以由用户或冲突解决规则来解决。Bucardo 是这种复制类型的一个示例。

同步多主复制

在同步多主复制中,每台服务器都能接受写请求,并且在每个事务提交之前,修改过的数据都会从原始服务器传送给其他每台服务器。繁重的写入活动可能导致过多锁定和提交延迟,进而带来较差的性能。读请求可以发送给任意服务器。某些实现使用共享磁盘来减少通信开销。同步多主复制尤其适合以读为主的负载,尽管它的一大优势是任意服务器都能接受写请求 — 无需在主库和备库之间划分负载,并且由于数据更改是从一台服务器传送到另一台服务器,因此不会出现非确定函数(如 random())的问题。

PostgreSQL 本身不提供这种复制,不过可以在应用代码或中间件中利用 PostgreSQL 的两阶段提交(PREPARE TRANSACTIONCOMMIT PREPARED)来实现这一功能。

商业解决方案

由于 PostgreSQL 是开源的,而且易于扩展,许多公司以 PostgreSQL 为基础,创建了具有独特故障切换、复制和负载均衡功能的商业闭源解决方案。

Table 26.1总结了上述多种方案的能力。

Table 26.1. 高可用、负载均衡和复制特性矩阵

特性 共享磁盘故障切换 文件系统复制 预写式日志传送 逻辑复制 基于触发器的主备复制 基于语句的复制中间件 异步多主复制 同步多主复制
最常见的实现 NAS DRBD 内置流复制 内置逻辑复制、pglogical Londiste,Slony pgpool-II Bucardo  
通信方法 共享磁盘 磁盘块 WAL 逻辑解码 表行 SQL 表行 表行和行锁
不要求特殊硬件  
允许多个主库        
主库无额外开销        
不等待多个服务器   关闭同步时 关闭同步时    
主库失效绝不会丢失数据 启用同步时 启用同步时    
副本接受只读查询     启用热备时
每个表粒度        
不需要冲突解决    

有一些方案不适合上述的类别:

数据分区

数据分区会把表拆分成多个数据集。每个数据集只能由一台服务器修改。例如,可以按办公室划分数据,如伦敦和巴黎,每个办公室各有一台服务器。如果有必要执行组合伦敦和巴黎数据的查询,应用可以同时查询两台服务器,或者可以使用主库/备库复制,在每台服务器上保留其他办公室数据的只读副本。

多服务器并行查询执行

上述许多方案都允许多台服务器处理多个查询,但没有一种允许单个查询同时使用多台服务器来更快完成。这种方案允许多台服务器在同一个查询上并发工作。通常的做法是把数据分散到各台服务器上,让每台服务器执行该查询中属于自己的部分,然后把结果返回给一台中心服务器,由它汇总结果并返回给用户。这种方案也可以使用PL/Proxy工具集来实现。