随着数据量的快速增长,可伸缩性已经成为数据库领域最热门的话题之一,可伸缩性分为垂直扩展和水平扩展。垂直扩展意味着给已经存在的节点增加更多的硬件资源,以提升单个节点存储和处理更多数据的能力,比如增加更多的CPU,磁盘空间和内存。几乎所有的DBMS引擎通过改进锁/互斥机制和并发性来提高其垂直扩展能力,以便更有效的利用新添加的资源,数据库引擎通常提供相关的配置参数,来更有效的利用硬件资源。
由于硬件成本以及在现有节点中添加新硬件的限制,不可能总是靠添加新硬件资源来解决数据库性能瓶颈,因此,水平扩展成为解决性能瓶颈的另一种可选方案。相对于垂直扩展,水平扩展更难实现,它需要更多的开发工作以及相关的配套工具。PostgreSQL为垂直扩展和水平扩展提供了相当丰富的功能特性,它支持在多个处理器和大量内存的机器上执行,并提供配置参数来管理和充分利用这些资源。PostgreSQL并发执行的特性使其在垂直扩展上更加突出,同时也不缺乏水平扩展性。复制功能是PostgreSQL水平扩展的核心,目前支持的单向主从复制已经能够解决大多数应用场景。
一、关键概念
1.1 数据复制
数据复制是指在其他服务器上复制数据,并将其存储在多个节点上。在这个过程中,数据库实例从一个节点传输到另一个节点,并生成一个精确的副本。数据复制用于提高数据可用性,这是HA的一个关键特性。可以对完整的数据库实例进行复制,也可以将一些常用的或必需的对象复制到另一个服务器。由于复制提供了数据库的多个一致性副本,它不仅提供了高可用性,而且还提高了应用性能,比如读写分离。
2.2 同步复制
在磁盘上写入数据时有两种策略:同步和异步。同步复制意味着数据同时写入主设备和从设备,换句话说,“同步复制”意味着一个事务提交,需要等待远端从节点写入,并刷到磁盘。同步复制通常用于对瞬时故障转移要求高的事务场景。
2.3 异步复制
异步意味着数据首先写入主库,然后复制到备库。在主库崩溃的情况下,可能会发生数据丢失,但是因为异步复制的开销很少,不会阻塞主库事务提交,因此在大多数业务场景下是可以接受的。然而与同步复制相比,failover故障转移所需的时间更长。
2.4 单主复制
单主复制意味着只允许在单个节点上写入数据,这些修改将复制到一个或多个节点。数据更新和插入只能在主节点上进行,应用程序需要将流量路由到主节点,因为只有一个主节点,所以不可能发生数据冲突。大多数情况下,单主复制对应用程序来说已经足够了,因为它的配置和管理不太复杂,但在某些情况下,单主复制是不够的,不能满足某些场景的需求,因此需要多主机复制。
二、多主复制
多主复制意味着有多个节点充当主节点。数据在节点之间复制,插入和更新可以在一组主节点上执行。数据有多个副本,系统负责解决并发更改之间发生的任何冲突。
使用多主复制主要有两个原因:一是高可用性,二是性能。在大多数情况下,有些节点专用于密集的写操作,而有些节点专用于读操作或故障转移。
关于多主复制的优缺点,如下:
优点:
- 如果一个主节点出现故障,另外一个主节点将会接替它的工作,避免业务中断。
- 主节点位于多个不同的位置,降低所有主节点都发生故障的概率。
- 可以在多个主节点上写入数据。
- 应用服务不需要将写流量只路由到一个节点。
缺点:
- 复杂性增加。
- 冲突解决非常困难,因为可以在多个节点上同时写入。
- 有时发生冲突时需要人工干预。
- 可能导致数据不一致。
正如上述讨论过的,在大多数情况下,单主复制已经足够满足业务需求,大多数场景下都建议使用单主复制,但是仍然有一些情况需要多主复制。PostgreSQL内置了单主复制,但遗憾的是,在PostgreSQL主分支中并没有多主复制功能。
有一些多主复制解决方案可用,其中一些是在应用程序端实现,有一些是PostgreSQL分叉的fork版本实现,这些fork有自己的小型社区,主要由一家公司管理,但不是由PostgreSQL主线社区管理。
常用的PostgreSQL多主解决方案如下:
- BDR (Bi-Directional Replication)
- xDB
- PostgreSQL-XL
- PostgreSQL-XC / PostgreSQL-XC2
- Rubyrep
- Bucardo
2.1 BDR (Bi-Directional Replication)
BDR是一个多主复制解决方案,它有不同的版本。早期版本的BDR是开源的,但最新版本是闭源的。BDR由2ndQuadrant开发,是迄今为止最优雅的多主机解决方案之一。BDR提供异步的多主机逻辑复制,基于PostgreSQL逻辑解码特性。由于BDR实质上是在其他节点上重新应用事务,因此如果正在应用的事务与在接收节点上提交的事务之间存在冲突,应用操作可能会失败。
2.2 xDB
EnterpriseDB使用Java开发了双向复制解决方案xDB,基于他们自己的协议,因为它是一个闭源方案,所以相关的设计信息无从获取。
- 由EnterpriseDB开发和维护
- 使用Java开发,性能欠佳
- 闭源代码,专有软件
- xDB复制服务包含多个可执行程序
- failover故障转移时间较长
- 拥有用户界面,用于配置和维护复制系统
2.3 PostgreSQL XC/XC2
PostgreSQL XC由EnterpriseDB和NTT开发,它是一个同步复制解决方案。PostgresXC是一个开源项目,提供写场景可伸缩的、同步的、对称的和透明的PostgreSQL集群解决方案。从EnterpriseDB和NTT官网,已经多年没有看到PostgreSQL XC有新的发展。目前,华为正致力于此产品。在OLAP的场景下,已经报告了一些性能提高,但不适合于TPS。
2.4 PostgreSQL XL
PostgreSQL XL是PostgreSQL XC的一个分支,目前由2ndQuadrant支持。它远远落后于PostgreSQL社区,它基于PostgreSQL 10.6,与PostgreSQL最新版本PostgreSQL 12不一致。它是基于PostgreSQL XC的,对于OLAP性能非常好,但是不太适合于高TPS。
所有的PostgreSQL XC/XC2/XL都被认为是“PostgreSQL派生软件”,与PostgreSQL当前的开发不同步。
2.5 Rubyrep
它是由Arndt-Lehmann开发的异步主主复制,声称通过最简单的配置、安装,就可以跨平台工作,包括windows。它总是在两台服务器上运行,在Rubyrep术语中被称为“左”和“右”。因此,将其称为主主架构更合适,而不是多主架构。
- rubyrep可以在左数据库和右数据库之间同步复制数据
- 自动设置必要的触发器、日志表等
- 自动发现新添加的表并同步表内容
- 自动重新配置序列以避免重复的序列数据冲突
- 跟踪主键字段的更改
- 可以同时实现主从复制和主主复制
- 预构建冲突解决方法:左/右获胜,早期/后期更改获胜
- 可通过ruby代码段指定的自定义冲突解决方案
- 复制决策可以选择性地记录在rubyrep事件日志表中
注:就发展而言,该项目在过去三年中一直不活跃。
2.6 Bucardo
Bucardo是End Point公司的Jon Jensen和Greg Sabino Mullane开发的基于触发器的复制解决方案。Bucardo已经存在了近20年,最初被设计为一个”懒惰“的异步解决方案,实现最终复制所有的更改。有一个Perl守护进程监听NOTIFY请求并对其执行操作。表上发生的更改记录在表(bucardo_delta)中,并通知守护进程。守护进程通知控制器启动“kid”以同步表更改。如果存在冲突,则使用标准或自定义冲突处理程序对其进行处理。
- 基于触发器的复制
- 冲突解决策略
- 依赖Perl5、DBI、DBD::Pg、DBIx::Safe
- 安装和配置都很复杂
- 复制经常中断,bug较多
三、总结
单主复制足够应对大多数应用场景,但仍然有人试图配置多主机复制,并使其多主复制设计得过于复杂。强烈建议设计系统时尽量避免多主复制,除非没有其他可选方案。主要有两个原因:第一,它使系统过于复杂,难以调试;第二,由于没有可用的社区维护的多主复制,无法获得PostgreSQL社区的任何支持。