管理 PostgreSQL 数据库集群

创建/销毁 PostgreSQL 集群,以及对现有集群进行扩容,缩容,克隆集群。

速查手册

操作快捷命令说明
创建集群bin/pgsql-add <cls>创建新的 PostgreSQL 集群
扩容集群bin/pgsql-add <cls> <ip...>为现有集群添加从库副本
缩容集群bin/pgsql-rm <cls> <ip...>从集群中移除指定实例
销毁集群bin/pgsql-rm <cls>销毁整个 PostgreSQL 集群
刷新服务bin/pgsql-svc <cls> [ip...]重载集群的负载均衡配置
刷新HBAbin/pgsql-hba <cls> [ip...]重载集群的 HBA 访问规则
克隆集群-通过备份集群或 PITR 克隆

其他管理任务,请参考:高可用管理管理用户管理数据库


创建集群

要创建一个新的 PostgreSQL 集群,请首先在 配置清单定义集群,然后 纳管节点并进行初始化:

bin/node-add  <cls>     # 添加分组 <cls> 下的节点
./node.yml  -l <cls>    # 直接使用 Ansible 剧本添加分组 <cls> 下的节点
bin/pgsql-add pg-test   # 例子,添加 pg-test 分组下的节点,实际执行 ./node.yml -l pg-test

在被纳管的节点上,可以使用以下命令创建集群:(针对 <cls> 分组执行 pgsql.yml 剧本)

bin/pgsql-add <cls>     # 创建 PostgreSQL 集群 <cls>
./pgsql.yml -l <cls>    # 直接使用 Ansible 剧本创建 PostgreSQL 集群 <cls>
bin/pgsql-add pg-test   # 例子,创建 pg-test 集群

示例:创建三节点 PG 集群 pg-test


扩容集群

若要将新从库添加到 现有的 PostgreSQL 集群 中,您需要将 实例定义 添加到 配置清单all.children.<cls>.hosts 中。

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary } # 已存在的成员
    10.10.10.12: { pg_seq: 2, pg_role: replica } # 已存在的成员
    10.10.10.13: { pg_seq: 3, pg_role: replica } # <--- 新成员
  vars: { pg_cluster: pg-test }

扩容集群的操作与 创建集群 非常类似,首先需要将扩容的节点纳入 Pigsty 管理:添加节点

bin/node-add <ip>       # 添加 IP 地址为 <ip> 的节点
./node.yml -l <ip>      # 直接使用 Ansible 剧本添加 <ip> 对应的节点
bin/node-add 10.10.10.13    # 例子,添加 IP 为 10.10.10.13 的节点,实际执行 ./node.yml -l 10.10.10.13

然后在新节点上运行以下命令以扩容集群(针对新节点安装 PGSQL 模块,使用与现有集群相同的 pg_cluster

bin/pgsql-add <cls> <ip>  # 添加 IP 地址为 <ip> 的节点
./pgsql.yml -l <ip>       # 核心逻辑:使用 Ansible 剧本在 <ip> 节点上安装 PGSQL 模块
bin/pgsql-add pg-test 10.10.10.13   # 示例,为 pg-test 集群扩容 IP 为 10.10.10.13 的节点

扩容完成后,您应当 刷新服务 以将新成员添加至负载均衡器中以实际承载流量。

示例:为两节点集群 pg-test 扩容一个新从库 10.10.10.13


缩容集群

若要从 现有的 PostgreSQL 集群 中移除副本,您需要从 配置清单all.children.<cls>.hosts 中移除对应的 实例定义

缩容集群首先需要卸载目标节点上的 PGSQL 模块(针对 <ip> 执行 pgsql-rm.yml 剧本):

bin/pgsql-rm <cls> <ip>   # 从集群 <cls> 中移除 <ip> 节点上的 PostgreSQL 实例
./pgsql-rm.yml -l <ip>    # 直接使用 Ansible 剧本移除 <ip> 节点上的 PostgreSQL 实例
bin/pgsql-rm pg-test 10.10.10.13  # 例子,从 pg-test 集群移除 10.10.10.13 节点

移除 PGSQL 模块后,您可以选择将节点从 Pigsty 管理中移除:移除节点(可选):

bin/node-rm <ip>          # 从 Pigsty 管理中移除 <ip> 节点
./node-rm.yml -l <ip>     # 直接使用 Ansible 剧本从 Pigsty 管理中移除 <ip> 节点
bin/node-rm 10.10.10.13   # 例子,从 Pigsty 管理中移除 10.10.10.13 节点

缩容完成后,您应当从 配置清单 中移除该实例的定义,然后 刷新服务 以将已它从负载均衡器中踢除。

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }
    10.10.10.13: { pg_seq: 3, pg_role: replica } # <--- 执行后移除此行
  vars: { pg_cluster: pg-test }

示例:从三节点集群 pg-test 中缩容一个从库 10.10.10.13


销毁集群

销毁集群需要在集群的所有节点上卸载 PGSQL 模块(针对 <cls> 执行 pgsql-rm.yml 剧本):

bin/pgsql-rm <cls>        # 销毁整个 PostgreSQL 集群 <cls>
./pgsql-rm.yml -l <cls>   # 直接使用 Ansible 剧本销毁整个 PostgreSQL 集群 <cls>
bin/pgsql-rm pg-test      # 例子,销毁 pg-test 集群

销毁 PGSQL 模块后,您可以选择将节点一并从 Pigsty 管理中移除:移除节点(可选,如果还有其他服务可以保留):

bin/node-rm <cls>         # 从 Pigsty 管理中移除 <cls> 分组下的所有节点
./node-rm.yml -l <cls>    # 直接使用 Ansible 剧本从 Pigsty 管理中移除 <cls> 分组下的所有节点
bin/node-rm pg-test       # 例子,从 Pigsty 管理中移除 pg-test 分组下的所有节点

销毁结束后,建议及时从 配置清单 中移除整个 集群定义

pg-test: # 清理这个集群定义分组
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }
    10.10.10.13: { pg_seq: 3, pg_role: replica }
  vars: { pg_cluster: pg-test }

示例:销毁三节点 PG 集群 pg-test

注意:如果为这个集群配置了 pg_safeguard(或全局设置为 true),pgsql-rm.yml 将中止执行,以避免意外销毁集群。 您可以使用剧本命令行参数明确地覆盖它,以强制执行销毁。 此外默认情况下,集群的备份仓库将同集群一并删除。如果你希望保留备份(例如在使用集中式备份仓库时),可以设置 pg_rm_backup=false 参数:

./pgsql-rm.yml -l pg-meta -e pg_safeguard=false    # 强制销毁受保护的 pg 集群 pg-meta
./pgsql-rm.yml -l pg-meta -e pg_rm_backup=false    # 在销毁集群过程中保留其备份仓库

刷新服务

PostgreSQL 集群通过主机节点上的 HAProxy 对外提供 服务。 当服务定义变化,实例权重变化,或者集群成员发生变化时(例如,集群 扩容 / 缩容,主从切换/故障转移),您需要择机刷新服务以更新负载均衡器的配置。

要在整个集群或特定实例上刷新服务配置(针对 <cls><ip> 执行 pgsql.ymlpg_service 子任务):

bin/pgsql-svc <cls>           # 刷新整个集群 <cls> 的服务配置
bin/pgsql-svc <cls> <ip...>   # 刷新集群 <cls> 中指定实例的服务配置
./pgsql.yml -l <cls> -t pg_service -e pg_reload=true        # 刷新整个集群的服务配置
./pgsql.yml -l <ip>  -t pg_service -e pg_reload=true        # 刷新指定实例的服务配置
bin/pgsql-svc pg-test                 # 例子,刷新 pg-test 集群的服务配置
bin/pgsql-svc pg-test 10.10.10.13     # 例子,刷新 pg-test 集群中 10.10.10.13 实例的服务配置

备注:如果您使用集中式的专用负载均衡集群(pg_service_provider),那么只有刷新集群主库时才会更新负载均衡配置。

示例:刷新集群 pg-test 的服务配置

示例:重载PG服务以踢除一个实例

asciicast


刷新HBA

当您修改了 HBA 相关配置后,需要刷新 HBA 规则以应用更改。(pg_hba_rules / pgb_hba_rules) 如果您有任何特定于角色的 HBA 规则,或者在 IP 地址段中引用了集群成员的别名,那么当主从切换/集群扩缩容后也可能需要刷新 HBA。

要在整个集群或特定实例上刷新 PG 和 Pgbouncer 的 HBA 规则(针对 <cls><ip> 执行 pgsql.yml 的 HBA 相关子任务):

bin/pgsql-hba <cls>           # 刷新整个集群 <cls> 的 HBA 规则
bin/pgsql-hba <cls> <ip...>   # 刷新集群 <cls> 中指定实例的 HBA 规则
./pgsql.yml -l <cls> -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true   # 刷新整个集群
./pgsql.yml -l <ip>  -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true   # 刷新指定实例
bin/pgsql-hba pg-test                 # 例子,刷新 pg-test 集群的 HBA 规则
bin/pgsql-hba pg-test 10.10.10.13     # 例子,刷新 pg-test 集群中 10.10.10.13 实例的 HBA 规则

示例:刷新集群 pg-test 的 HBA 规则


配置集群

PostgreSQL 的配置参数由 Patroni 管理,初始参数由 Patroni 配置模板 指定。 集群初始化之后,配置存储在 Etcd 中,并由 Patroni 进行动态管理,并在集群中同步与共享。 Patroni 本身的 配置参数 大部分可以通过 patronictl命令行工具修改。 其余参数(例如,etcd DCS 配置,日志/RestAPI 等配置)则可以通过下面的子任务进行更新。例如,当 etcd 集群成员发生变动时,你可以刷新 Patroni 配置:

./pgsql.yml -l pg-test -t pg_conf                   # 更新 Patroni 配置文件
ansible pg-test -b -a 'systemctl reload patroni'    # 重载 Patroni 服务

您可以在不同层次上覆盖 Patroni 集中管理的默认,例如单独 为实例指定配置参数; 单独为 为用户指定配置参数,或者 为数据库指定配置参数


克隆集群

有两种克隆集群的方式:使用 备份集群 功能,或者使用 时间点恢复 功能。 前者配置简单,无需依赖,但只能克隆指定集群的最新状态;后者依赖集中式的 备份仓库(例如 MinIO),但可以克隆到备份保留期内的任意时间点。

方式优点缺点适用场景
备份集群配置简单,无需依赖只能克隆最新状态灾备,读写分离,迁移
PITR可恢复到任意时间点依赖集中式备份仓库误操作恢复,数据审计

使用备份集群克隆

备份集群(Standby Cluster)通过流复制从上游集群持续同步数据,是克隆集群最简单的方式。 只需在新集群主库上指定 pg_upstream 参数,即可自动从上游集群拉取数据。

# pg-test 是原始集群
pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
  vars: { pg_cluster: pg-test }

# pg-test2 是 pg-test 的备份集群(克隆)
pg-test2:
  hosts:
    10.10.10.12: { pg_seq: 1, pg_role: primary, pg_upstream: 10.10.10.11 }  # 指定上游
    10.10.10.13: { pg_seq: 2, pg_role: replica }
  vars: { pg_cluster: pg-test2 }

使用以下命令创建备份集群:

bin/pgsql-add pg-test2    # 创建备份集群,自动从上游 pg-test 克隆数据
./pgsql.yml -l pg-test2   # 直接使用 Ansible 剧本创建备份集群

备份集群会持续追随上游集群,保持数据同步。您可以随时将其 提升 为独立集群:

示例:提升备份集群为独立集群

通过 配置集群 擦除 standby_cluster 配置段,即可将备份集群提升为独立集群:

$ pg edit-config pg-test2
-standby_cluster:
-  create_replica_methods:
-  - basebackup
-  host: 10.10.10.11
-  port: 5432

Apply these changes? [y/N]: y

提升后,pg-test2 将成为可以独立承载写入请求的独立集群,与原集群 pg-test 分叉。

示例:更改复制上游

如果上游集群发生主从切换,您可以通过 配置集群 更改备份集群的复制上游:

$ pg edit-config pg-test2

 standby_cluster:
   create_replica_methods:
   - basebackup
-  host: 10.10.10.11     # <--- 旧的上游
+  host: 10.10.10.14     # <--- 新的上游
   port: 5432

Apply these changes? [y/N]: y

使用 PITR 克隆

时间点恢复(PITR)允许您将集群恢复到备份保留期内的任意时间点。 此方式依赖集中式的 备份仓库(如 MinIO/S3),但功能更加强大。

要使用 PITR 克隆集群,在配置中添加 pg_pitr 参数指定恢复目标:

# 从 pg-meta 集群的备份克隆一个新集群 pg-meta2
pg-meta2:
  hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr:
      cluster: pg-meta                    # 从 pg-meta 的备份恢复
      time: '2025-01-10 10:00:00+00'      # 恢复到指定时间点

使用 pgsql-pitr.yml 剧本执行克隆:

./pgsql-pitr.yml -l pg-meta2    # 从 pg-meta 备份克隆 pg-meta2
# 也可以通过命令行参数指定 PITR 选项
./pgsql-pitr.yml -l pg-meta2 -e '{"pg_pitr": {"cluster": "pg-meta", "time": "2025-01-10 10:00:00+00"}}'

PITR 支持多种恢复目标类型:

目标类型参数示例说明
时间点time: "2025-01-10 10:00:00+00"恢复到指定时间戳
事务IDxid: "250000"恢复到指定事务之前/之后
恢复点name: "before_migration"恢复到命名恢复点
LSNlsn: "0/4001C80"恢复到指定 WAL 位置
最新type: "latest"恢复到 WAL 归档末尾

更多 PITR 的详细用法,请参考 恢复操作 文档。