PostgreSQL数据库连接和故障转移管理器
项目描述
利用ZooKeeper(https://zookeeper.net.cn)的协调能力,为PostgreSQL提供稳健的自动故障转移实现。
基本设计
所有服务器之间的通信都通过ZooKeeper进行。没有SSH或任何类型的网络连接。
系统由两个不同的守护进程组成:“死信”守护进程和“同步”守护进程。在实际使用PostgreSQL集群的节点上,运行“死信”守护进程来控制PostgreSQL进程,以及可选的同步守护进程来更新PostgreSQL配置文件(例如pg_hba.conf)。在应用程序服务器或代理上运行“同步”守护进程。
术语
数据库集群或集群: https://postgresql.ac.cn/docs/9.4/static/creating-cluster.html
znode:ZooKeeper数据库中的ZooKeeper数据节点
组、集群组、数据库组:由一个或多个数据库集群组成的,提供单个逻辑数据库的主/副本组。
ZooKeeper目录结构
在ZooKeeper中,我们有一个包含多个主-副本数据库组中所有节点信息的目录。这是一个包含4个子目录类型的目录
- /state/{DATABASE_GROUP_NAME}_{IPADDR}:{PORT}
这包含有关数据库集群节点(健康或不健康)的所有信息。它经常更新,包含诸如WAL日志重放状态之类的数据。它是一个临时节点,如果在ZooKeeper中丢失连接,它将消失。临时节点,由“死信”守护进程创建/维护。
- /conn/{DATABASE_GROUP_NAME}_{IPADDR}:{PORT}
此znode包含来自状态节点的部分信息。它是一个单个健康(即可连接)集群的静态连接信息/元数据。如果节点不“健康”,则此条目将不存在。此znode中的信息不是易失的,并且保证在znode的生命周期内不会更改。临时节点,由“死信”守护进程创建/维护。
- /lock/{DATABASE_GROUP_NAME}
这包含数据库组的当前主机的IPADDR:PORT。连接信息应在“_conn_”节点中查找(如果存在)。由当前节点上的“死信”守护进程创建/维护
- /static/{DATABASE_GROUP_NAME}-db-id
包含数据库组的数据库标识符。
上述大部分znode包含一个JSON编码的字典/对象/哈希表。
同步守护进程
此守护进程在任何希望连接到数据库组的节点上运行,并维护本地机的配置文件。例如,如果某个数据库组的主节点故障转移,它可以重写 pgbouncer 配置。如果创建了新的数据库组,它还可以启动新的 pgbouncer 守护进程。另一个例子是根据节点位置(例如可用区)或复制延迟动态更改 HAProxy 权重。
实际应用配置更改是插件的工作,同步守护进程不会自行应用任何更改。插件可以通过两种方式指定
使用 setuptools entry points 订阅进程内的更改。这允许订阅者订阅来自状态-、主-或健康- znodes 的事件。
提供一个可执行文件,它将使用包含健康-和主- znodes 信息的 JSON 编码文件的路径调用。这是由 zgres-apply 包提供的,该包通过使用以前的插件方法连接到 zgres-sync。出于性能原因,此插件不接收状态-事件。
这些插件必须是幂等的,因为它们将多次使用相同的数据调用。
死手守护进程
此守护进程控制一个 PostgreSQL 数据库集群,并在 zookeeper 中注册它(创建/维护状态-、conn-和主- znodes)。它必须在与数据库集群相同的机器上运行。
它负责提升或关闭其 PostgreSQL 数据库集群。
目前,在死手启动之前,应在外部处理重制和启动 PostgreSQL。
- 死手守护进程的插件应能做两件事
提供额外的元数据(例如可用区或复制延迟)
否决集群运行(除内置 SELECT 1 之外)
挑战
多个副本:如何切换到“最佳”副本。
多个副本:如何将副本连接到新主节点。
知道基线备份在哪里并在启动时初始化新副本是否是个好主意?
- 插件插件插件
提供大量内置插件,允许通过 zookeeper 的“配置”查看和启用它们?eek:守护进程的动态重新配置?
如果一些节点没有一些插件会发生什么?
“集群组”级别的配置
优点
相对简单的配置。没有 ssh 配置。
完全分布式。
实现思路
使用 python 实现 daemons,记录到 stdout 和 stderr。通过 systemd 运行,配置为在失败时重启。大声失败!
依赖项
systemd
kazoo - ZooKeeper 客户端
psycopg2 - 连接到 PostgreSQL
致谢
Zgres 受 HandyRep (https://github.com/pgexperts/handyrep) 和 Patroni (https://github.com/zalando/patroni) 的影响很大。非常感谢这些项目的开发者们,他们的许多想法都非常出色。