PostgreSQL数据库有着各种各样的高可用方案,绝大多数,都是基于流复制机制实现的,常见的例如Patroni+DCS,Pacemaker+Corosync,Repmgr,keepalived,pg_auto_failover,PGpool等等,其中使用较多的应该是Patroni和Repmgr两种,下文针对PostgreSQ的两种高可用方案Repmgr和Patroni进行部分场景对比。
Repmgr是2010年由2ndQuadrant推出的一款PostgreSQL故障切换工具,repmgr是一个开源工具套件,用于管理PostgreSQL服务器集群中的复制和故障转移。它扩展了PostgresSQL内建的hot-standby能力,可以监控复制和执行管理任务。
Repmgr是一个命令行工具,日常操作主要通过Repmgr进行操作,功能包括集群状态查看、switchover、克隆备库、失效节点重新加入等。
用于执行管理任务的命令行工具,主要有以下方面作用:
- 设置备用服务器
- 将备用服务器升级为主服务器
- 切换主服务器和备用服务器
- 显示流复制状态
- clone恢复备机数据
- 注册节点
Repmgrd 是一个守护进程,支持故障检测、failover,监控和记录集群信息以及自定义脚本接受集群事件通知event_notification_command,它有一组预定义的事件,并将这些事件的每次发生都存储在 repmgr.events 表中。Repmgr 允许将事件通知传递给用户定义的程序或脚本,该程序或脚本可以采取进一步的行动,例如发送电子邮件或触发任何警报。
可以使用Repmgrd设置自动故障转移。Repmgrd 需要在启动 PostgreSQL 服务器时加载共享库“repmgr”。库名称应配置在 postgresql.conf 文件的shared_preload_libraries里。并且需要在 repmgr.conf 文件中设置 failover=automatic 参数。一旦设置了所有这些参数,Repmgrd 守护程序就会开始主动监控集群。如果主节点出现任何故障,它将尝试多次重新连接。当所有连接到主节点的尝试都失败时,Repmgrd 将通过选举选择最符合条件的备用节点作为新的主节点。
它主动监视复制集群中的服务器并执行以下任务:
- 监控和记录集群复制性能
- 通过检测主服务器故障并提升最合适的备用服务器来执行故障转移
- 将有关群集中事件的通知提供给用户定义的脚本,该脚本可以执行诸如通过电子邮件发送警报等任务
- repmgrd 根据本地数据库角色不同,其功能也不同:
主库:repmgrd仅监控本地数据库,负责自动恢复、同异步切换
备库:repmgrd监控本地数据库和主数据库,负责自动切换、复制槽删除
表
repmgr.events:用来记录repmgr管理的事件信息
repmgr.nodes:复制群集中每个服务器的连接和状态信息
repmgr.monitoring_history:repmgrd写入的历史备用监视信息
repmgr.voting_term:【5.2新增】主要用来记录投票信息
视图
repmgr.show_nodes:基于表repmgr.nodes,增加了显示上游节点的信息
repmgr.replication_status:启用repmgrd的监视时,显示每个备用数据库的当前监视状态。
Repmgr元数据的schema可以存储在现有的数据库或在自己的专用数据库,repmgr元数据的schema不能驻留在不属于Repmgr管理的复制集群的数据库服务器上。
——
Repmgr本身不支持虚拟IP的功能 ,我们可以借助keepalived来实现虚拟IP的功能。另外在配置文件中,也可以设置promote_command为一个自定义脚本
Repmgr怎么选主: 当需要failover时,repmgr选举候选备节点会以以下顺序选举:LSN > Priority > Node_ID。若LSN一样,会根据priority优先级进行比较,该优先级是在配置文件中进行参数配置,将priority设置为0会禁止参与选主。若优先级也一样,会比较节点的Node ID,小者会优先选举
Repmgr使用location位置参数处理脑裂场景,其中每个节点应根据其所在的数据中心指定位置参数。在任何网络分裂的情况下,Repmgr将确保与主节点位于同一位置的节点的提升。如果它在该位置找不到任何节点,它将不会提升任何位置的任何节点。
location='location1' # 定义location
除此之外可以使用witness见证服务器的额外节点处理网络隔离,避免产生脑裂。
witness见证节点重要用来处理集群主库和备库之间可能存在网络拥塞、延迟、路由等问题影响,导致主库还在正常工作,而备库无法联系主库的场景。通过设置witness节点可以针对主库与备库之间切换的检查完整性,即辅助备节点进行监控,避免因网络问题导致的脑裂现象。
见证节点主要的工作是帮助备库达到法定的数量。它是一个仅考虑多数票数的节点。该服务器上不需要安装PostgreSQL,因此在复制中没有任何作用。
当备机连不上主机了,就会连接witness见证节点,如果也连接不上见证节点,那判断自己网络故障了,如果能连上见证节点,则认为主机故障,见证节点的作用类似于一个信任的网关。
witness必须配合Repmgrd。 Remgrd启动后会作为常规服务运行并持续监视集群的运行状况。当达到与主机数据库失去联系的法定人数时,它将启动故障转移。它不仅可以自动升级备用数据库,还可以在多节点群集中重新启动其他备用数据库以跟随新的主数据库。
Patroni起源于 Compose 的一个项目Governor 的一个分支。它是一个用 Python 编写的开源工具套件,用于管理 PostgreSQL 集群的高可用性。Patroni 没有构建自己的一致性协议,而是利用了分布式配置存储(DCS) 提供的一致性模型 ,如 Zookeeper、etcd、Consul 和 Kubernetes等。下文主要以ETCD作为DCS举例来说明:
etcd可以进行心跳检测(etcd 之间的心态检测)、存储并在各个节点上同步键值信息。etcd最少需要三个节点且为奇数来进行 leader 选举(脑裂发生时 etcd 集群会僵死等待恢复,不会发生都认为自己是主的情况)。
Patroni通过一个api接口连接到etcd(或者其他DCS),向其插入键值对记录patroni参数、数据库参数、主备信息以及连接信息,平常通过etcd对其它节点做心跳检测,通过从etcd获取数据对中存储的主备信息来判断各节点的状态对集群进行自动管理
Patroni 确保 PostgreSQL HA 集群的端到端设置,包括流复制。它支持创建备用节点的各种方式,并且可以根据您的需要定制模板。 Patroni 借助回调可以支持事件通知,回调是由某些操作触发的脚本。它使用户能够通过提供暂停/恢复功能来执行任何维护操作。watchdog支持功能使框架更加健壮。
Zookeeper带来的主要优势是它的成熟度,健壮性和功能丰富性。 但是,它也有其自身的一系列缺点,其中Java和复杂性是主要原因。 Zookeeper对Java的使用以及相当数量的依赖关系使它比同等竞争产品消耗更多的资源。 除此之外,Zookeeper也很复杂。 维护成本比较高。 功能丰富性很高,但是很多复杂的功能可能不会使用到。
etcd是可通过HTTP访问的键/值存储。 它是分布式的,具有可用于构建服务发现的分层配置系统。 它非常易于部署,设置和使用,可提供可靠的数据持久性,安全性并具有非常好的文档。etcd的简单性比Zookeeper更好。 但是,必须先将其与少量第三方工具结合使用,然后才能实现服务发现目标。
Consul是一个高度一致的数据存储,它形成了一个动态集群。 具有分层的键/值存储,该键/值存储不仅可以用于存储数据,还可以注册服务,这些服务可以用于各种任务,从发送有关数据更改的通知到根据其输出运行运行状况检查和自定义命令。与Zookeeper和etcd不同,Consul实现了嵌入式服务发现系统,因此无需构建自己的系统或使用第三方系统。 除其他事项外,该发现还包括对节点和在它们之上运行的服务的运行状况检查。
ZooKeeper和etcd仅提供原始的K/V存储,并要求应用程序开发人员构建自己的系统来提供服务发现。 另一方面,Consul提供了用于服务发现的内置框架。 客户端只需要注册服务并使用DNS或HTTP接口执行发现。 其他两个工具需要手工解决方案或使用第三方工具。Consul为多个数据中心提供了开箱即用的本机支持,该系统不仅可以在同一集群中的节点之间工作,而且还可以跨数据中心工作。
Patroni监控本地的PostgreSQL状态,并将相关信息写入etcd,每个Patroni都能读写etcd上的key,从而获取外地PostgreSQL数据库信息。当etcd的leader节点不可用时,etcd会一致性的选择一个合适的节点作为主节点,新的etcd主节点将获取leader key。
etcd怎么选主:假设etcd有三个节点,三个节点都去创建一个全局的唯一key,谁先创建成功谁就是master主节点。其他节点持续待命继续获取,主节点继续续租key值(key值会过期)。当持有key的节点down机时,或者key值过期被删,其他节点创建key成功,则新master主节点产生,其他节点继续这样待命持续获取key的状态。
正常停止Patroni时,Patroni会顺便把本机的PG进程也停掉。然而,当Patroni进程自身没法正常工作时,以上的保护措施难以成功。例如Patroni进程异常终止或主机临时hang住等。
为了更可靠的防止脑裂,Patroni支持经过Linux的watchdog监视patroni进程的运行,当Patroni进程没法正常往watchdog设备写入心跳时,由watchdog触发Linux重启。
使用watchdog防止出现脑裂,如果Leader节点异常导致Patroni进程无法及时更新watchdog,会在Leader key过期的前5秒触发重启。重启如果在5秒之内完成,Leader节点有机会再次获得Leader锁,否则Leader key过期后,由备库通过选举选出新的Leader。
Patroni会在将PostgreSQL提升为master之前尝试激活watchdog。
如果看atchdog激活失败并且watchdog模式是required那么节点将拒绝成为主节点。
在决定参加leader选举时,Patroni还将检查watchdog配置是否允许它成为领导者。
在将PostgreSQL降级后(例如由于手动故障转移),Patroni将再次禁用watchdog。当 Patroni处于暂停状态时,watchdog也将被禁用。正常停止Patroni服务,也会将watchdog禁用。
除此之外,Patroni在目前支持的 逻辑复制槽的自动failover 这一功能,在PostgreSQL的高可用方案里,是比较方便且独树一帜的。所以,如果可用服务器在至少3台或者有逻辑复制需求的时候,Patroni是一款很值得推荐的PostgreSQL高可用工具,但是这个最少节点的限制也是其中一个缺点。
场景 | Repmgr | Patroni |
---|---|---|
kill PostgreSQL 进程 | 需要手动干预才能再次启动PostgreSQL 进程。 | Patroni 使 PostgreSQL 进程回到运行状态。 |
正常停止 PostgreSQL 进程 | 需要手动干预才能再次启动PostgreSQL 进程。 | Patroni 使 PostgreSQL 进程回到运行状态。 |
重启服务器 | 需要手动启动PostgreSQL,并将服务器标记为正在运行。 | Patroni会在在重启及服务器后启动,除非配置为在重新启动时不启动。一旦 Patroni 启动,它就会启动 PostgreSQL 进程并设置备机配置。 |
正常停止repmgrd或Patroni | 备机的不会成为自动故障转移的一个节点,(备机状态无变化) | Patroni会停止备机PostgreSQL进程 |
场景 | Repmgr | Patroni |
---|---|---|
kill PostgreSQL 进程 | Repmgrd在固定的时间间隔内,所有备机都会对主节点连接进行健康检查。当所有重试都失败时,在所有备机上触发选举。作为选举的结果,具有最新收到的 LSN 的备用被提升。失去选举的备用服务器将等待来自新主节点的通知,并在收到通知后跟随它。原主节点需要手动干预才能再次启动 postgreSQL 进程。 | Patroni 使 PostgreSQL 进程回到运行状态。在该节点上运行的 Patroni 具有主锁,因此没有触发选举。 |
正常停止 PostgreSQL进程并在健康检查到期前立即将其恢复 | Repmgrd在固定的时间间隔内,所有备机都会对主节点连接进行健康检查。当所有重试都失败时,在所有备机上触发选举。然而,新当选的主节点没有通知现有的备机,因为旧的主节点回来了。群集处于不确定状态,需要人工干预。 | Patroni 使 PostgreSQL 进程回到运行状态。在该节点上运行的 Patroni 具有主锁,因此没有触发选举。 |
重启服务器 | 当所有备机上与主的连接健康检查失败时,remgrd 开始选举。符合条件的备机被提升为新主。当原主回来时,它没有加入集群并被标记为失败。需要运行 repmgr node rejoin 命令将服务器添加回集群。 | 发生故障转移,其中一台备机在获得锁后被选为新的主节点。当Patroni在旧主机点上启动时,它会拉起原主的PostgreSQL进程并执行pg_rewind,并、且开始跟随新主节点。 |
正常停止repmgrd或Patroni | 主节点不会成为自动故障转移的一部分。PostgreSQL 服务正常运行。启动Repmgrd,PostgreSQL进程不自动拉起。 | Patroni所在的其中一台备机获得了 DCS 锁并提升自身成为主库。旧主的PostgreSQL被Patroni关掉,一旦在旧主机上启动了 Patroni,它会将旧主的时间线和 lsn(use_pg_rewind设置为 true)调整到与新主一致并开始跟随新主。 |