Patroni Failover logical slots 提供的功能是:
在一个 PostgreSQL 流复制集群内发生 failover 时可以将旧节点上的逻辑复制槽的信息(主要是几个位置信息)在新主节点上构建。
由于 subscriber 可以防止重复数据,所以即使在主节点切换前,各个逻辑复制备节点上的位置信息落后一点,也没关系。
由于整个方案使用到了 pg_replication_slot_advance 函数,所以从 PostgresSQL 11 支持;
背景
PostgreSQL 从 9.4 开始引入流复制槽和逻辑复制功能,引入这两个功能之后,首先可以通过追踪 restart_lsn 和 confirmed_flush_lsn 来确认 logical decode 需要的 WAL 文件都会被保留,第二个是可以通过追踪 catalog_xmin 来防止可能被 logical decode需要但是已经死掉的 catalog tuple被 PostgreSQL autovacuum 清理掉;
使用逻辑复制槽最大的问题是,PostgreSQL 不支持在 standby 角色的服务上创建逻辑复制槽。因此,如果在一个PostgreSQL 流复制集群内发生 failover 之后,接着在刚刚被 promote 的节点上创建逻辑复制槽的话,可能会丢失事务。
到目前为止,所以在 PostgreSQL 内核实现在 standby 端 logical decode ,然后期望在 failover 到这样的一个 standby 时,可以实现逻辑复制槽重新在新主节点上创建并且不丢失事务的尝试都没有取得很好的效果。但是现在,随着 PostgreSQL 功能的增强,这个问题有望通过外部的工具解决。 Failover slots
和 Logical replication and physical standby failover 这两篇文章可以补充一下基础知识。
Patroni 的实现
Patroni 没有依赖任何的第三方拓展即实现了 Failover logical slots 功能。
Patroni 实现此功能的主要目标是安全可靠的使用 logical slot,数据库流复制集群内发生 failover 时整个过程中不会丢失事务。
- 在 standby 上创建 logical slot。PostgreSQL 不支持在在 standby 上创建 logical slot,但是可以通过如下的步骤来实现。首先 pg_ctl stop 停止 PostgreSQL 进程,然后从 primary 节点拷贝 pg_replslot/$slot_name/state 到 standby 节点,重新启动 PostgreSQL,即可在 standby 节点上查询 logical slot 信息。
- 第一步中”创建“逻辑复制槽的操作只会在有资格成为 primary 的节点上执行。比如打了 tags.nofailover 标签的节点将不在考虑范围内。
- 从 PostgreSQL 11 开始,新增了 pg_replication_slot_advance() 函数,这个函数可以同时操作 physical slot 和 logical slot。使用此函数可以及时前进更新 replica 节点上的 logical slot 的位置,而不用依赖第三方扩展。
- hot_standby_feedback 必须在所有”创建“了 logical slot 的 standby 节点上配置,在所有的级联节点上也需要配置。举个例子:Primary <-- Node1(tags.nofailover=true) <-- Node2;
- 主节点持续更新每个 replica 节点关联的复制槽的 catalog_xmin 信息,所以 postgresql.use_slots 必须开启;
- Patroni 会持续追踪判断每个带有 logical slot 信息的 standby 是否可以安全可靠地被 promote ,如果不在符合条件,会记录 ERROR 级别地日志。在将来,Patroni 可能会直接移除不再符合条件的 standby。
Patroni 具体实现
PostgreSQL 主节点上的 Patroni 进程将定期将所有 logical slots 的位置信息(last_lsn、restart_lsn、confirmed_flush_lsn等 )更新到 Raft Server (存储到 /status 键下)。
所有带有 logical slot 信息的 standby 节点会定期拉取此信息,并使用 pg_replication_slot_advance() 函数更新当前数据库节点上的所有 logical slot 的位置信息。
参考
Failover logical slots #1820Logical replication slot inquery