跳转到主要内容

1 - 管理 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...] 重载集群的负载均衡配置
刷新HBA bin/pgsql-hba <cls> [ip...] 重载集群的 HBA 访问规则
克隆集群 - 通过备份集群或 PITR 克隆

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


创建集群

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

脚本
bin/node-add  <cls>     # 添加分组 <cls> 下的节点
剧本
./node.yml  -l <cls>    # 直接使用 Ansible 剧本添加分组 <cls> 下的节点
示例
bin/node-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

demo/pgsql.cast
针对已经存在的集群重新执行创建存在风险

如果您在已经存在的集群上重新执行创建操作,Pigsty 不会移除已有的数据文件,但现有服务配置会被覆盖,集群会发生 重启! 此外,如果你在 数据库定义 中指定了 baseline SQL,它也会重新执行,如果里面包含删除/覆盖逻辑,可能会导致 数据丢失


扩容集群

若要将新从库添加到 现有的 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

demo/pgsql-append.cast

缩容集群

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

缩容会停止实例并默认删除其数据目录。操作前先执行 pig pg list <cls>pig pb info,确认目标不是主库、存在近期可恢复备份, 并让操作者输入精确的 <ip>,确认后方可实际执行。

缩容集群首先需要卸载目标节点上的 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

demo/pgsql-shrink.cast

销毁集群

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

这是不可逆的数据删除:先用 pig pg list <cls>pig pb info 核对状态和近期备份,决定是否保留独立备份副本, 并要求操作者输入精确集群名。下面命令会直接执行相应的销毁操作。

脚本
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

demo/pgsql-rm.cast

注意:如果为这个集群配置了 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 对外提供 服务。 当服务定义变化、实例权重变化,或者集群成员发生变化时(例如集群 扩容 / 缩容),您需要刷新服务以更新负载均衡器的静态成员配置。默认 Primary/Replica 服务通过 Patroni REST API 健康检查识别当前角色,正常的主从切换或故障转移会自动改道,不要求重新生成 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 的服务配置

demo/pgsql-svc.cast
示例:重载 PG 服务以踢除一个实例

asciicast


刷新HBA

当您修改了 HBA 相关配置后,需要刷新 HBA 规则以应用更改。(pg_hba_rules / pgb_hba_rules) 如果您有任何特定于清单角色的 HBA 规则,或者在 IP 地址段中引用了集群成员的别名,那么修改 pg_role 标签或集群扩缩容后也可能需要刷新 HBA。这里的角色筛选使用静态清单变量,不会随 Patroni 主从切换自动改变。

要在整个集群或特定实例上刷新 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 规则

demo/pgsql-hba.cast

配置集群

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 集中管理的默认,例如单独 为实例指定配置参数; 单独为 为用户指定配置参数,或者 为数据库指定配置参数


克隆集群

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

方式 优点 缺点 适用场景
备份集群 无需备份仓库 需要可达上游,只能克隆最新状态 灾备,读写分离,迁移
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)允许您将集群恢复到恢复窗口内的任意时间点。 此方式依赖集中式的 备份仓库(如 Silo/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'      # 恢复到指定时间点
      archive: false                       # 独立恢复阶段禁用归档
      action: promote                      # 完成重放后提升并启动集群

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

剧本
./pgsql-pitr.yml -l pg-meta2    # 使用上面显式声明的 action: promote
命令行
# 也可以通过命令行参数指定 PITR 选项
./pgsql-pitr.yml -l pg-meta2 -e '{"pg_pitr": {"cluster": "pg-meta", "time": "2025-01-10 10:00:00+00", "archive": false, "action": "promote"}}'

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

目标类型 参数示例 说明
时间点 time: "2025-01-10 10:00:00+00" 恢复到指定时间戳
事务 ID xid: "250000" 恢复到指定事务之前/之后
恢复点 name: "before_migration" 恢复到命名恢复点
LSN lsn: "0/4001C80" 恢复到指定 WAL 位置
最新 pg_pitr: {} 恢复到 WAL 归档末尾
PITR 恢复后处理

跨集群恢复完成后,按 克隆善后 处理归档与 stanza。

更多 PITR 的详细用法,请参考 恢复操作;跨集群恢复后的归档与 stanza 处理见 克隆数据库集群

2 - 管理 PostgreSQL 业务用户

用户管理:创建、修改、删除用户,管理角色成员关系,连接池用户配置

快速上手

Pigsty 使用声明式管理方式,首先在 配置清单定义用户,然后使用 bin/pgsql-user <cls> <username> 创建或修改用户。

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_users: [{ name: dbuser_app, password: 'DBUser.App', pgbouncer: true }]  # <--- 在这里定义用户列表!
脚本
bin/pgsql-user <cls> <username>    # 在 <cls> 集群上创建/修改 <username> 用户
剧本
./pgsql-user.yml -l pg-meta -e username=dbuser_app    # 直接使用剧本在 <cls> 集群上创建/修改 <username> 用户
示例
bin/pgsql-user pg-meta dbuser_app    # 在 pg-meta 集群上创建/修改 dbuser_app 用户

关于用户定义参数的完整参考,请查阅 用户配置。角色与权限模型参见 访问控制,认证与凭据管理参见 身份认证

namepgsql-user.yml 查找用户定义的键,剧本不会执行角色重命名。需要更名时,应先创建新角色,迁移所有权、成员关系与客户端凭据,完成切换和验证后再删除旧角色;不要把“删除后重建”当作无损的重命名操作。

操作 快捷命令 说明
创建用户 bin/pgsql-user <cls> <user> 创建新的业务用户或角色
修改用户 bin/pgsql-user <cls> <user> 修改已存在用户的属性
删除用户 bin/pgsql-user <cls> <user> 依赖感知的破坏性删除(需设置 state: absent
demo/pgsql-user.cast

创建用户

定义在 pg_users 里面的用户会在 PostgreSQL 集群创建 的时候在 pg_user 任务中自动创建。

要在现有的 PostgreSQL 集群上创建新的业务用户,请将 用户定义 添加到 all.children.<cls>.pg_users,然后执行:

脚本
bin/pgsql-user <cls> <username>   # 创建用户 <username>
剧本
./pgsql-user.yml -l <cls> -e username=<username>   # 直接使用 Ansible 剧本创建用户
示例
bin/pgsql-user pg-meta dbuser_app    # 例子,在 pg-meta 集群中创建 dbuser_app 用户

示例配置:创建名为 dbuser_app 的业务用户

#all.children.pg-meta.vars.pg_users: # 省略上级缩进
  - name: dbuser_app
    password: DBUser.App
    pgbouncer: true
    roles: [dbrole_readwrite]
    comment: application user for myapp

执行效果:在主库上创建用户 dbuser_app,设置密码,授予 dbrole_readwrite 角色权限, 将用户添加到 Pgbouncer 连接池,在每个实例上重载 Pgbouncer 配置使其立即生效。

建议使用剧本创建用户

如果您需要手工创建用户,那么需要自行确保 Pgbouncer 连接池用户列表同步。


修改用户

修改用户与创建用户使用相同的命令,剧本是幂等的。当目标用户已存在时,Pigsty 会修改目标用户的属性使其符合配置。

脚本
bin/pgsql-user <cls> <user>   # 修改用户 <user> 的属性
剧本
./pgsql-user.yml -l <cls> -e username=<user>   # 幂等操作,可重复执行
示例
bin/pgsql-user pg-meta dbuser_app    # 修改 dbuser_app 用户的属性使其符合配置

不可直接修改的属性:用户的 name 是声明式定义的身份键,剧本不会把一个现有角色重命名为另一个角色。应按“创建新角色 → 迁移所有权/权限与客户端 → 验证 → 删除旧角色”的顺序完成更名。

其他属性均可修改,以下是一些常见的修改示例:

修改密码:更新配置中的 password 字段后执行剧本。密码修改时会临时禁用日志记录,避免密码泄露到日志中。

- name: dbuser_app
  password: NewSecretPassword     # 修改密码

修改权限属性:通过配置相应的布尔标志来修改用户权限。

- name: dbuser_app
  superuser: false           # 超级用户(谨慎使用!)
  createdb: true             # 允许创建数据库
  createrole: false          # 允许创建角色
  inherit: true              # 自动继承角色权限
  replication: false         # 允许流复制连接
  bypassrls: false           # 绕过行级安全策略
  connlimit: 50              # 限制连接数,-1 不限制

修改用户有效期:使用 expire_in 设置相对过期时间(N 天后过期),或 expire_at 设置绝对过期日期。expire_in 优先级更高,每次执行剧本时会重新计算,适合需要定期续期的临时用户。

- name: temp_user
  expire_in: 30                   # 30 天后过期(相对时间)

- name: contractor_user
  expire_at: '2024-12-31'         # 指定日期过期(绝对时间)

- name: permanent_user
  expire_at: 'infinity'           # 永不过期

修改角色成员关系:通过 roles 数组配置角色成员关系,支持简单格式和扩展格式。角色成员关系是增量操作,不会移除未声明的现有角色。使用 state: absent 可以显式撤销角色。

- name: dbuser_app
  roles:
    - dbrole_readwrite                      # 简单形式:授予角色
    - { name: dbrole_admin, admin: true }   # 带 ADMIN OPTION(可以将此角色授予其他用户)
    - { name: pg_monitor, set: false }      # PG16+: 不允许 SET ROLE
    - { name: old_role, state: absent }     # 撤销角色成员关系

管理用户参数:通过 parameters 字典配置用户级参数,会生成 ALTER USER ... SET 语句。使用特殊值 DEFAULT 可将参数重置为 PostgreSQL 默认值。

- name: dbuser_analyst
  parameters:
    work_mem: '256MB'
    statement_timeout: '5min'
    search_path: 'analytics,public'
    log_statement: DEFAULT        # 重置为默认值

连接池配置:设置 pgbouncer: true 将用户添加到连接池,可选配置 pool_mode(池化模式:transaction/session/statement)和 pool_connlimit(用户最大连接数)。

- name: dbuser_app
  pgbouncer: true                 # 添加到连接池
  pool_mode: transaction          # 池化模式
  pool_connlimit: 50              # 用户最大连接数

删除用户

删除用户会终止连接、转移对象所有权、撤销授权并执行 DROP ROLE,属于不可逆操作。先确认精确的集群名、用户名、继任所有者与近期备份,再将目标用户的 state 设置为 absent 并执行实际变更。

脚本
bin/pgsql-user <cls> <user>   # 确认后实际删除;配置中必须为 state: absent
剧本
./pgsql-user.yml -l <cls> -e username=<user>   # 直接使用 Ansible 剧本删除用户
示例
bin/pgsql-user pg-meta dbuser_old    # 删除 dbuser_old 用户(配置中已设置 state: absent)

配置示例

pg_users:
  - name: dbuser_old
    state: absent

删除操作会:在主库调用 pg-drop-role <user> postgres --force,先禁用登录并终止活跃连接,将数据库、表空间以及每个可连接数据库中的对象所有权转移给 postgres,执行 DROP OWNED 清理授权,撤销角色成员关系,最后执行 DROP ROLE。脚本在 /tmp/pg_drop_role_<user>_<timestamp>.log 保存执行前的审计快照。

保护机制:Ansible 任务会跳过 postgres 以及清单中配置的复制、管理和监控用户。直接运行 pg-drop-role 时,脚本只硬编码保护默认名称 postgresreplicatordbuser_dbadbuser_monitor;如果改过系统用户名,直接脚本不会自动识别它们,必须额外谨慎。

依赖感知,但不是事务性删除

pg-drop-role 会在 REASSIGN OWNED 失败时跳过对应数据库的 DROP OWNED,但整个跨数据库流程不是一个事务;中途失败可能留下 NOLOGIN、已转移的部分对象或残余依赖。v4.5 的 Ansible 删除任务还使用 ignore_errors,因此剧本最终状态不能代替核验。执行后必须确认角色已消失、继任所有权正确、应用已切换,并检查审计日志。

v4.5 的 pgsql-user.yml 会重载 Pgbouncer,但不会可靠地从 /etc/pgbouncer/userlist.txt 清除已删除角色。删除后应在每个集群实例检查:

sudo -iu postgres psql -AXtwc "SELECT 1 FROM pg_roles WHERE rolname = 'dbuser_old';"
grep -n '^"dbuser_old"[[:space:]]' /etc/pgbouncer/userlist.txt

若仍有精确匹配的 Pgbouncer 条目,应在受控变更中移除该行、重载 Pgbouncer 并验证应用连接;不要用模糊匹配批量删除。


手工删除用户

如果需要手动删除用户,可以直接使用 pg-drop-role 脚本:

# 检查依赖关系(只读操作)
pg-drop-role dbuser_old --check

# 预览删除操作(不实际执行)
pg-drop-role dbuser_old --dry-run -v

# 确认近期备份、精确用户名与继任所有者后,才执行实际删除
pg-drop-role dbuser_old dbuser_new

# 仅当已明确同意终止连接时使用 --force
pg-drop-role dbuser_old dbuser_new --force

常见用例

下面是一些常见的用户配置示例:

创建基本业务用户

- name: dbuser_app
  password: DBUser.App
  pgbouncer: true
  roles: [dbrole_readwrite]
  comment: application user

创建只读用户

- name: dbuser_readonly
  password: DBUser.Readonly
  pgbouncer: true
  roles: [dbrole_readonly]

创建管理员用户(可执行 DDL)

- name: dbuser_admin
  password: DBUser.Admin
  pgbouncer: true
  pool_mode: session
  roles: [dbrole_admin]
  parameters:
    log_statement: 'all'

创建临时用户(30天后过期)

- name: temp_contractor
  password: TempPassword
  expire_in: 30
  roles: [dbrole_readonly]

创建角色(不可登录,用于权限分组)

- name: custom_role
  login: false
  comment: custom role for special permissions

创建带高级角色选项的用户(PG16+)

- name: dbuser_special
  password: DBUser.Special
  pgbouncer: true
  roles:
    - dbrole_readwrite
    - { name: dbrole_admin, admin: true }
    - { name: pg_monitor, set: false }
    - { name: pg_execute_server_program, inherit: false }

查询用户

以下是一些常用的 SQL 查询,用于查看用户信息:

查看所有用户

SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
       rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, rolvaliduntil
FROM pg_roles WHERE rolname NOT LIKE 'pg_%' ORDER BY rolname;

查看用户的角色成员关系

SELECT r.rolname AS member, g.rolname AS role, m.admin_option, m.set_option, m.inherit_option
FROM pg_auth_members m
JOIN pg_roles r ON r.oid = m.member
JOIN pg_roles g ON g.oid = m.roleid
WHERE r.rolname = 'dbuser_app';

查看用户级参数设置

SELECT rolname, setconfig FROM pg_db_role_setting s
JOIN pg_roles r ON r.oid = s.setrole WHERE s.setdatabase = 0;

查看即将过期的用户

SELECT rolname, rolvaliduntil, rolvaliduntil - CURRENT_TIMESTAMP AS time_remaining
FROM pg_roles WHERE rolvaliduntil IS NOT NULL
  AND rolvaliduntil < CURRENT_TIMESTAMP + INTERVAL '30 days'
ORDER BY rolvaliduntil;

连接池管理

在用户定义中配置的 连接池参数 会在创建/修改用户时应用到 Pgbouncer 连接池中。

设置 pgbouncer: true 的用户会被添加到 /etc/pgbouncer/userlist.txt 文件中。用户级别的连接池参数(pool_modepool_connlimit)通过 /etc/pgbouncer/useropts.txt 文件配置。

您可以使用 postgres 操作系统用户,使用 pgb 别名访问 Pgbouncer 管理数据库。更多连接池管理操作,请参考 Pgbouncer 管理


管理默认用户密码

要修改普通用户的密码, 按照上面 修改用户 的说明,更新配置中的 password 字段并执行剧本即可。 不过修改 默认用户 的密码会稍微复杂一些,因为它们的密码还在多个地方被其他服务引用。

参数 默认值 对应用户 用途
pg_admin_password DBUser.DBA dbuser_dba 管理员用户密码
pg_monitor_password DBUser.Monitor dbuser_monitor 监控用户密码
pg_replication_password DBUser.Replicator replicator 复制用户密码

这三个账号属于 pg_default_roles,不在 pg_users 中。pgsql-user.yml 只查找 pg_users,因此不应通过命令行临时覆盖 pg_users 来轮换默认密码:这既会改变本次剧本看到的业务用户列表,也会把明文密码留在 shell 历史中。

使用以下通用顺序一次轮换一个账号:

  1. pigsty.yml(或实际使用的清单)中持久化新的密码参数,不要把明文密码写进命令行。
  2. 在当前主库上以超级用户打开交互式 psql,使用 \password <username> 修改数据库角色密码;该元命令会交互读取密码。
  3. 使用下面对应的刷新剧本,并核对 -l 限定的集群/节点。
  4. 保留当前管理会话,验证 PostgreSQL 直连、Pgbouncer、复制、Exporter 和 Grafana 数据源,再轮换下一个账号。
# 在目标集群当前主库上,交互修改数据库角色密码
sudo -iu postgres psql -d postgres
\password dbuser_dba       # 或 dbuser_monitor / replicator

随后按账号刷新所有消费者;下列命令中的 <cls>infra 必须替换/限定为实际目标:

# 管理员 dbuser_dba:PG 节点 .pgpass、Pgbouncer、Infra 管理端与 pgAdmin 文件
./pgsql.yml -l <cls> -t pg_pass,pgbouncer_user,pgbouncer_reload -e pg_reload=true
./infra.yml -l infra -t env_pgpass,env_pgscv,env_pgadmin

# 监控用户 dbuser_monitor:PG 节点 .pgpass、Pgbouncer、两个 Exporter 与 Grafana 数据源
./pgsql.yml -l <cls> -t pg_pass,pgbouncer_user,pgbouncer_reload,pg_exporter,pgbouncer_exporter,add_ds -e pg_reload=true
./infra.yml -l infra -t env_pgpass

# 复制用户 replicator:Patroni 配置、PG 节点 .pgpass 与 Infra .pgpass
./pgsql.yml -l <cls> -t pg_conf,pg_pass,patroni_reload -e pg_reload=true
./infra.yml -l infra -t env_pgpass

复制密码在数据库角色与所有 Patroni 节点之间不一致时,新建复制连接会失败,因此应安排维护窗口并快速完成验证。若部署了 VIBE 等会把管理员连接串写入工作区上下文的模块,还应按模块文档重新渲染对应文件。

检查 Infra .pgpass 重复项

v4.5 的 env_pgpass 使用 lineinfile 添加新记录,不会按用户名自动删除旧密码;libpq 又采用第一条匹配记录。刷新后应在每个目标 Infra 节点检查每个系统用户名是否只有一条匹配记录,并通过受控编辑删掉旧项(不要把密码打印到终端或日志):

awk -F: '$4=="dbuser_dba" || $4=="dbuser_monitor" || $4=="replicator" {print NR, $4}' ~/.pgpass

Patroni REST API 的 patroni_password 不是 PostgreSQL 角色密码。修改清单后,应分别刷新目标 PostgreSQL 集群和 Infra 管理端:

./pgsql.yml -l <cls> -t pg_conf,patroni_reload -e pg_reload=true
./infra.yml -l infra -t env_patroni

执行后用 patronictlpig pg list <cls> 验证认证与集群状态。

3 - 管理 PostgreSQL 业务数据库

数据库管理:创建、修改、删除、重建数据库,使用模板克隆数据库

快速上手

Pigsty 使用声明式管理方式,首先在 配置清单定义数据库,然后使用 bin/pgsql-db <cls> <dbname> 创建或修改数据库。

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_databases: [{ name: some_db }]  # <--- 在这里定义数据库列表!
脚本
bin/pgsql-db <cls> <dbname>    # 在 <cls> 集群上创建/修改 <dbname> 数据库
剧本
./pgsql-db.yml -l pg-meta -e dbname=some_db    # 直接使用剧本在 <cls> 集群上创建/修改 <dbname> 数据库
示例
bin/pgsql-db pg-meta some_db    # 在 pg-meta 集群上创建/修改 some_db 数据库

关于数据库定义参数的完整参考,请查阅 数据库配置。数据库访问权限见 访问控制:数据库隔离

请注意,部分数据库参数仅能在 创建时 指定。修改这些参数需要先删除再创建数据库(使用 state: recreate 重建数据库)。

操作 快捷命令 说明
创建数据库 bin/pgsql-db <cls> <db> 创建新的业务数据库
修改数据库 bin/pgsql-db <cls> <db> 修改已存在数据库的属性
删除数据库 bin/pgsql-db <cls> <db> 删除数据库(需设置 state: absent
重建数据库 bin/pgsql-db <cls> <db> 先删再建(需设置 state: recreate
克隆数据库 bin/pgsql-db <cls> <db> 使用模板克隆数据库
demo/pgsql-db.cast

创建数据库

定义在 pg_databases 里面的数据库会在 PostgreSQL 集群创建 的时候在 pg_db 任务中自动创建。

要在现有的 PostgreSQL 集群上创建新的业务数据库,请将 数据库定义 添加到 all.children.<cls>.pg_databases,然后执行:

脚本
bin/pgsql-db <cls> <dbname>   # 创建数据库 <dbname>
剧本
./pgsql-db.yml -l <cls> -e dbname=<dbname>   # 直接使用 Ansible 剧本创建数据库
示例
bin/pgsql-db pg-meta myapp    # 例子,在 pg-meta 集群中创建 myapp 数据库

示例配置:创建名为 myapp 的业务数据库

#all.children.pg-meta.vars.pg_databases: # 省略上级缩进
  - name: myapp
    owner: dbuser_myapp
    schemas: [app]
    extensions:
      - { name: pg_trgm }
      - { name: btree_gin }
    comment: my application database

执行效果:在主库上创建数据库 myapp,设置数据库所有者为 dbuser_myapp,创建 schema app, 启用扩展 pg_trgmbtree_gin,数据库将默认添加到 Pgbouncer 连接池,并注册为 Grafana PG 数据源。

建议使用剧本创建数据库

如果您需要手工创建数据库,那么需要自行确保 pgbouncer 连接池 / grafana 数据源同步。


修改数据库

修改数据库与创建数据库使用相同的命令,在没有定义 baseline SQL 的情况下剧本是幂等的。

当目标数据库已存在时,Pigsty 会修改目标数据库的属性使其符合配置。然而,一些属性只能在数据库创建时设置。

脚本
bin/pgsql-db <cls> <db>   # 修改数据库 <db> 的属性
剧本
./pgsql-db.yml -l <cls> -e dbname=<db>   # 幂等操作,可重复执行
示例
bin/pgsql-db pg-meta myapp    # 修改 myapp 数据库的属性使其符合配置

不可修改的属性:以下属性在数据库创建后无法修改,需要使用 state: recreate 重建数据库:

  • name(数据库名称)、template(模板数据库)、strategy(克隆策略)。
  • encoding(字符编码)、locale/lc_collate/lc_ctype(本地化设置)、locale_provider/icu_locale/icu_rules/builtin_locale(本地化提供者设置)

其他属性均可修改,以下是一些常见的修改示例:

修改属主:更新配置中的 owner 字段后执行剧本,会执行 ALTER DATABASE ... OWNER TO 并授予相应权限。

- name: myapp
  owner: dbuser_new_owner     # 修改为新属主

修改连接限制:通过 connlimit 限制数据库的最大连接数。

- name: myapp
  connlimit: 100              # 限制最大 100 个连接

回收公共连接权限:设置 revokeconn: true 会回收 PUBLIC 的 CONNECT 权限,仅允许属主、DBA、监控用户和复制用户连接。

- name: myapp
  owner: dbuser_myapp
  revokeconn: true            # 回收 PUBLIC 的 CONNECT 权限

管理数据库参数:通过 parameters 字典配置数据库级参数,会生成 ALTER DATABASE ... SET 语句。使用特殊值 DEFAULT 可将参数重置为默认值。

- name: myapp
  parameters:
    work_mem: '256MB'
    maintenance_work_mem: '512MB'
    statement_timeout: '30s'
    search_path: DEFAULT      # 重置为默认值

管理模式(Schema):通过 schemas 数组配置模式,支持简单格式和指定属主的完整格式。使用 state: absent 删除模式(CASCADE)。

- name: myapp
  schemas:
    - app                                   # 简单形式
    - { name: core, owner: dbuser_myapp }   # 指定属主
    - { name: deprecated, state: absent }   # 删除模式

管理扩展(Extension):通过 extensions 数组配置扩展,支持简单格式和指定 schema/版本的完整格式。使用 state: absent 卸载扩展(CASCADE)。

- name: myapp
  extensions:
    - postgis                                 # 简单形式
    - { name: vector, schema: public }        # 指定 schema
    - { name: pg_trgm, state: absent }        # 卸载扩展
CASCADE 警告

删除模式或卸载扩展使用 CASCADE 选项,会同时删除依赖该模式/扩展的所有对象。请确保理解影响范围后再执行删除操作。

连接池配置:默认情况下所有业务数据库都会添加到 Pgbouncer 连接池。可配置 pgbouncer(是否加入连接池)、pool_mode(池化模式)、pool_size(默认池大小)、pool_reserve(保留连接数)、pool_size_min(最小池大小)、pool_connlimit(最大数据库连接)、pool_auth_user(认证查询用户)等参数。

- name: myapp
  pgbouncer: true              # 是否加入连接池(默认 true)
  pool_mode: transaction       # 池化模式:transaction/session/statement
  pool_size: 50                # 默认池大小
  pool_reserve: 30             # 保留池大小
  pool_size_min: 0             # 最小池大小
  pool_connlimit: 100          # 最大数据库连接
  pool_auth_user: dbuser_meta  # 认证查询使用用户(配合 pgbouncer_auth_query)

自 Pigsty v4.1.0 起,数据库连接池参数统一使用 pool_reservepool_connlimit,旧别名 pool_size_reserve / pool_max_db_conn 已收敛。


删除数据库

要删除数据库,将其 state 设置为 absent 并执行剧本:

脚本
bin/pgsql-db <cls> <db>   # 删除数据库 <db>(需在配置中设置 state: absent)
剧本
./pgsql-db.yml -l <cls> -e dbname=<db>   # 直接使用 Ansible 剧本删除数据库
示例
bin/pgsql-db pg-meta olddb    # 删除 olddb 数据库(配置中已设置 state: absent)

配置示例

pg_databases:
  - name: olddb
    state: absent

删除操作会:如果数据库标记为 is_template: true,先执行 ALTER DATABASE ... IS_TEMPLATE false;使用 DROP DATABASE ... WITH (FORCE) 强制删除数据库(PG13+)并终止所有活动连接;从 Pgbouncer 连接池中移除该数据库;从 Grafana 数据源中取消注册。

保护机制:系统数据库 postgrestemplate0template1 无法删除。删除操作仅在主库上执行,流复制会自动同步到从库。

危险操作警告

删除数据库是 不可逆 操作,会永久删除该数据库中的所有数据。执行前请确保:已有最新的数据库备份、已确认没有业务在使用该数据库、已通知相关干系人。 Pigsty 不对任何因删除数据库导致的数据丢失承担责任,使用需自担风险。


重建数据库

recreate 状态用于重建数据库,等效于先删除再创建:

脚本
bin/pgsql-db <cls> <db>   # 重建数据库 <db>(需在配置中设置 state: recreate)
剧本
./pgsql-db.yml -l <cls> -e dbname=<db>   # 直接使用 Ansible 剧本重建数据库
示例
bin/pgsql-db pg-meta testdb    # 重建 testdb 数据库(配置中已设置 state: recreate)

配置示例

pg_databases:
  - name: testdb
    state: recreate
    owner: dbuser_test
    baseline: test_init.sql    # 重建后执行初始化

适用场景:测试环境重置、清空开发数据库、修改不可变属性(编码、本地化等)、恢复数据库到初始状态。

与手动 DROP + CREATE 的区别:单条命令完成,无需两次操作;自动保留 Pgbouncer 和 Grafana 配置;执行后自动加载 baseline 初始化脚本。


克隆数据库

你可以通过 PG 的 template 机制复制一个 PostgreSQL 数据库,在克隆期间,不允许有任何连接到模版数据库的活动连接。

脚本
bin/pgsql-db <cls> <db>   # 克隆数据库 <db>(需在配置中指定 template)
剧本
./pgsql-db.yml -l <cls> -e dbname=<db>   # 直接使用 Ansible 剧本克隆数据库
示例
bin/pgsql-db pg-meta meta_dev    # 克隆创建 meta_dev 数据库(配置中已指定 template: meta)

配置示例

pg_databases:
  - name: meta                   # 源数据库

  - name: meta_dev
    template: meta               # 以 meta 作为模板
    strategy: FILE_COPY          # PG15+ 克隆策略,PG18 瞬间生效

瞬间克隆(PG18+):如果使用 PostgreSQL 18 以上版本,Pigsty 默认设置了 file_copy_method,配合 strategy: FILE_COPY 可以在约 200ms 内完成数据库克隆,而不需要复制数据文件。例如克隆一个 30 GB 的数据库,普通克隆用时 18 秒,瞬间克隆仅需 200 毫秒。

手动克隆:确保清理掉所有连接到模版数据库的连接后执行:

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'meta';
CREATE DATABASE meta_dev TEMPLATE meta STRATEGY FILE_COPY;

局限性与注意事项:瞬间克隆仅在支持的文件系统上可用(xfs,btrfs,zfs,apfs);不要使用 postgres 数据库作为模版数据库进行克隆;在高并发环境中使用瞬间克隆需要谨慎,需在克隆窗口(200ms)内清理掉所有连接到模版数据库的连接。


连接池管理

在数据库定义中配置的 连接池参数 会在创建/修改数据库时应用到 Pgbouncer 连接池中。

默认情况下所有业务数据库都会添加到 Pgbouncer 连接池(pgbouncer: true)。数据库会被添加到 /etc/pgbouncer/database.txt 文件中,数据库级别的连接池参数(pool_auth_userpool_modepool_sizepool_reservepool_size_minpool_connlimit)通过此文件配置。

您可以使用 postgres 操作系统用户,使用 pgb 别名访问 Pgbouncer 管理数据库。更多连接池管理操作,请参考 Pgbouncer 管理

4 - 管理 Patroni 高可用

使用 Patroni 管理 PG 集群高可用,包括,修改参数,查看状态,主从切换,重启,重做从库等操作。

概览

Pigsty 使用 Patroni 管理 PostgreSQL 集群,它可以用来修改集群配置,查看集群状态,执行主从切换,重启集群,重做从库等操作。

要使用 Patroni 进行管理,您需要有以下两种身份之一:

Patroni 提供了 patronictl 命令行工具用于管理,Pigsty 提供了封装的快捷命令 pg 来简化其操作。

通过 pg 别名使用 patronictl
pg ()
{
    local patroni_conf="/infra/conf/patronictl.yml";
    if [ ! -r ${patroni_conf} ]; then
        patroni_conf="/etc/patroni/patroni.yml";
        if [ ! -r ${patroni_conf} ]; then
            echo "error: patronictl config not found";
            return 1;
        fi;
    fi;
    patronictl -c ${patroni_conf} "$@"
}

可用命令

命令 功能 说明
edit-config 修改配置 交互式修改集群的 Patroni/PostgreSQL 配置
list 查看状态 列出集群成员及其状态
switchover 主动切换 将主库角色切换到指定从库(计划内维护)
failover 故障切换 强制故障转移到指定从库(紧急情况)
restart 重启实例 重启 PostgreSQL 实例以应用需要重启的参数
reload 重载配置 重载 Patroni 配置(无需重启)
reinit 重做从库 重新初始化从库(擦除数据并重新复制)
pause 暂停自动切换 暂停 Patroni 的自动故障转移功能
resume 恢复自动切换 恢复 Patroni 的自动故障转移功能
history 查看历史 显示集群的故障转移历史记录
show-config 显示配置 显示集群当前的配置(只读)
query 执行查询 在集群成员上执行 SQL 查询
topology 查看拓扑 显示集群的复制拓扑结构
version 查看版本 显示 Patroni 版本信息
remove 移除成员 从 DCS 中移除集群成员(危险操作)

修改配置

使用 edit-config 子命令可以交互式修改集群的 Patroni 与 PostgreSQL 配置。该命令会打开一个编辑器,让您修改存储在 DCS(分布式配置存储)中的集群配置,修改后会自动应用到所有集群成员。您可以更改 Patroni 本身的参数(如 ttlloop_waitsynchronous_mode 等),以及 postgresql.parameters 中的 PostgreSQL 参数。

pg edit-config <cls>                  # 交互式编辑集群配置
pg edit-config <cls> --force          # 跳过确认提示直接应用
pg edit-config <cls> -p <k>=<v>       # 修改 PostgreSQL 参数(--pg 简写)
pg edit-config <cls> -s <k>=<v>       # 修改 Patroni 参数(--set 简写)
demo/pgsql-config.cast

以下是一些常见的配置修改示例:

# 修改 PostgreSQL 参数:慢查询阈值(会询问是否应用)
pg edit-config pg-test -p log_min_duration_statement=1000

# 修改 PostgreSQL 参数并跳过确认
pg edit-config pg-test -p log_min_duration_statement=1000 --force

# 修改多个 PostgreSQL 参数
pg edit-config pg-test -p work_mem=256MB -p maintenance_work_mem=1GB --force

# 修改 Patroni 参数:增大故障检测时间窗口(增大 RTO)
pg edit-config pg-test -s loop_wait=15 -s ttl=60 --force

# 修改 Patroni 参数:启用同步复制模式
pg edit-config pg-test -s synchronous_mode=true --force

# 修改 Patroni 参数:启用严格同步模式(至少一个同步从库才允许写入)
pg edit-config pg-test -s synchronous_mode_strict=true --force

# 修改需要重启的参数(修改后需执行 pg restart)
pg edit-config pg-test -p shared_buffers=4GB --force
pg edit-config pg-test -p shared_preload_libraries='timescaledb, pg_stat_statements' --force
pg edit-config pg-test -p max_connections=200 --force

部分参数修改后需要重启 PostgreSQL 才能生效,您可以使用 pg list 检查集群状态,带 * 标记的实例表示需要重启。然后使用 pg restart 命令重启集群使配置生效。 您也可以使用 curl 或编写程序直接调用 Patroni 提供的 REST API 来修改配置:

# 查看当前配置
curl -s 10.10.10.11:8008/config | jq .

# 通过 API 修改参数(需要认证)
curl -u 'postgres:Patroni.API' \
     -d '{"postgresql":{"parameters": {"log_min_duration_statement":200}}}' \
     -s -X PATCH http://10.10.10.11:8008/config | jq .

查看状态

使用 list 子命令可以查看集群成员及其状态。输出结果会显示每个实例的名称、主机地址、角色、运行状态、时间线和复制延迟等信息。这是日常运维中最常用的命令之一,用于快速了解集群的健康状况。

pg list <cls>                         # 查看指定集群的状态
pg list                               # 列出所有集群(需要在管理节点上执行)
pg list <cls> -e                      # 显示扩展信息(--extended)
pg list <cls> -t                      # 显示时间戳(--timestamp)
pg list <cls> -f json                 # 以 JSON 格式输出(--format)
pg list <cls> -W 5                    # 每 5 秒刷新一次(--watch)

输出示例:

+ Cluster: pg-test (7322261897169354773) -----+----+--------------+
| Member    | Host        | Role    | State   | TL | Lag in MB    |
+-----------+-------------+---------+---------+----+--------------+
| pg-test-1 | 10.10.10.11 | Leader  | running |  1 |              |
| pg-test-2 | 10.10.10.12 | Replica | running |  1 |            0 |
| pg-test-3 | 10.10.10.13 | Replica | running |  1 |            0 |
+-----------+-------------+---------+---------+----+--------------+

输出列说明:Member 是实例名称,由 pg_cluster-pg_seq 组成;Host 是实例所在主机的 IP 地址;Role 表示角色,包括 Leader(主库)、Replica(从库)、Sync Standby(同步从库)、Standby Leader(级联复制的级联主库)等;State 表示运行状态,常见值包括 running(正常运行)、streaming(流复制中)、in archive recovery(归档恢复中)、starting(启动中)、stopped(已停止)等;TL 是时间线编号(Timeline),每次主从切换后会递增;Lag in MB 是复制延迟,以 MB 为单位,主库不显示此值。

如果某个实例需要重启才能应用配置更改,实例名称后会显示 * 标记:

+ Cluster: pg-test (7322261897169354773) -------+----+--------------+
| Member      | Host        | Role    | State   | TL | Lag in MB    |
+-------------+-------------+---------+---------+----+--------------+
| pg-test-1 * | 10.10.10.11 | Leader  | running |  1 |              |
| pg-test-2 * | 10.10.10.12 | Replica | running |  1 |            0 |
+-------------+-------------+---------+---------+----+--------------+

主动切换

使用 switchover 子命令可以执行计划内的主从切换。Switchover 是一种优雅的切换方式:Patroni 会先确保从库完全同步,然后让主库降级为从库,最后提升目标从库为新主库。这个过程通常只需要几秒钟,期间会有短暂的写入不可用。适用于主库所在主机需要维护、升级、或者需要将主库迁移到性能更好的节点等场景。

pg switchover <cls>                   # 交互式切换,会提示选择目标从库
pg switchover <cls> --leader <old>    # 指定当前主库名称
pg switchover <cls> --candidate <new> # 指定目标从库名称
pg switchover <cls> --scheduled <time> # 定时切换,格式如 2024-12-01T03:00
pg switchover <cls> --force           # 跳过确认提示

执行切换前请确保所有从库复制状态正常(状态为 runningstreaming),复制延迟在可接受范围内,并已通知相关业务方。

# 交互式切换(推荐,会显示当前拓扑并提示选择)
$ pg switchover pg-test
Current cluster topology
+ Cluster: pg-test (7322261897169354773) -----+----+--------------+
| Member    | Host        | Role    | State   | TL | Lag in MB    |
+-----------+-------------+---------+---------+----+--------------+
| pg-test-1 | 10.10.10.11 | Leader  | running |  1 |              |
| pg-test-2 | 10.10.10.12 | Replica | running |  1 |            0 |
| pg-test-3 | 10.10.10.13 | Replica | running |  1 |            0 |
+-----------+-------------+---------+---------+----+--------------+
Primary [pg-test-1]:
Candidate ['pg-test-2', 'pg-test-3'] []: pg-test-2
When should the switchover take place (e.g. 2024-01-01T12:00) [now]:
Are you sure you want to switchover cluster pg-test, demoting current leader pg-test-1? [y/N]: y

# 非交互式切换(指定主库和候选从库)
pg switchover pg-test --leader pg-test-1 --candidate pg-test-2 --force

# 定时切换(在凌晨 3 点执行,适合维护窗口)
pg switchover pg-test --leader pg-test-1 --candidate pg-test-2 --scheduled "2024-12-01T03:00"

切换完成后,请使用 pg list 确认新的集群拓扑。


故障切换

使用 failover 子命令可以执行紧急故障切换。与 switchover 不同,failover 用于主库已经不可用的紧急情况。它会直接提升一个从库为新主库,而不等待原主库的确认。由于从库可能尚未完全同步所有数据,使用 failover 可能会导致少量数据丢失。因此,在非紧急情况下请优先使用 switchover

pg failover <cls>                     # 交互式故障切换
pg failover <cls> --candidate <new>   # 指定要提升的从库
pg failover <cls> --force             # 跳过确认提示

故障切换示例:

# 交互式故障切换
$ pg failover pg-test
Candidate ['pg-test-2', 'pg-test-3'] []: pg-test-2
Are you sure you want to failover cluster pg-test? [y/N]: y
Successfully failed over to "pg-test-2"

# 非交互式故障切换(紧急情况快速执行)
pg failover pg-test --candidate pg-test-2 --force

Switchover 与 Failover 的区别:Switchover 用于计划内维护,要求原主库在线,执行前会确保数据完全同步,不会丢失数据;Failover 用于紧急故障恢复,原主库可以离线,会直接提升从库,可能丢失未同步的数据。日常维护、升级请使用 Switchover;只有在主库彻底故障无法恢复时才使用 Failover。

当前内置 Patroni 的 failover 子命令没有 --leader 选项;需要校验或指定原主库时应使用计划内的 switchover --leader ...,故障切换只指定候选从库。


重启实例

使用 restart 子命令可以重启 PostgreSQL 实例,通常用于应用需要重启才能生效的参数更改。直接对整个集群执行时,patronictl 会逐个提交所选成员,但不保证“从库优先、主库最后”的顺序。若需要明确的 leader-last 顺序,应先按角色重启从库,再单独重启主库。

pg restart <cls>                      # 重启整个集群的所有实例
pg restart <cls> <member>             # 重启指定实例
pg restart <cls> --role leader        # 仅重启主库
pg restart <cls> --role replica       # 仅重启所有从库
pg restart <cls> --pending            # 仅重启标记为需要重启的实例
pg restart <cls> --scheduled <time>   # 定时重启
pg restart <cls> --timeout <sec>      # 设置重启超时时间(秒)
pg restart <cls> --force              # 跳过确认提示

当您修改了需要重启才能生效的参数(如 shared_buffersshared_preload_librariesmax_connectionsmax_worker_processes 等)后,需要使用此命令重启实例。

# 查看哪些实例需要重启(名称后带 * 标记)
$ pg list pg-test
+ Cluster: pg-test (7322261897169354773) -------+----+--------------+
| Member      | Host        | Role    | State   | TL | Lag in MB    |
+-------------+-------------+---------+---------+----+--------------+
| pg-test-1 * | 10.10.10.11 | Leader  | running |  1 |              |
| pg-test-2 * | 10.10.10.12 | Replica | running |  1 |            0 |
+-------------+-------------+---------+---------+----+--------------+

# 重启单个从库实例
pg restart pg-test pg-test-2

# 重启整个集群的所有成员(不承诺 leader-last 顺序)
pg restart pg-test --force

# 仅重启需要重启的实例
pg restart pg-test --pending --force

# 显式按“从库优先、主库最后”执行
pg restart pg-test --role replica --force
pg restart pg-test --role leader --force

# 定时重启(在维护窗口执行)
pg restart pg-test --scheduled "2024-12-01T03:00"

# 设置重启超时时间为 300 秒
pg restart pg-test --timeout 300 --force

重载配置

使用 reload 子命令可以重载 Patroni 配置,无需重启 PostgreSQL。该命令会让 Patroni 重新读取配置文件,并将不需要重启的参数变更应用到 PostgreSQL(通过 pg_reload_conf())。相比 restartreload 更加轻量,不会中断数据库连接和正在执行的查询。

pg reload <cls>                       # 重载整个集群的配置
pg reload <cls> <member>              # 重载指定实例的配置
pg reload <cls> --role leader         # 仅重载主库
pg reload <cls> --role replica        # 仅重载所有从库
pg reload <cls> --force               # 跳过确认提示

大多数 PostgreSQL 参数可以通过 reload 生效,只有少数参数(位于 postmaster 上下文的参数,例如 shared_buffersmax_connectionsshared_preload_librariesarchive_mode 等)需要重启 PostgreSQL 才能生效。

# 重载整个集群
pg reload pg-test

# 重载单个实例
pg reload pg-test pg-test-1

# 强制重载,跳过确认
pg reload pg-test --force

重做从库

使用 reinit 子命令可以重新初始化从库。该操作会删除从库上的所有数据,再按 Patroni 的 create_replica_methods 顺序重建:Pigsty 默认先尝试 basebackup(即 pg_basebackup);启用远程 pgBackRest 仓库时还会配置 pgbackrest 作为后备方法。适用于从库数据损坏无法修复、从库落后太多导致 WAL 已被清理无法追赶、或从库配置错误需要重置等场景。

pg reinit <cls> <member>              # 重新初始化指定从库
pg reinit <cls> <member> --force      # 跳过确认提示
pg reinit <cls> <member> --wait       # 等待重建完成后再返回

⚠️ 警告:此操作会删除目标实例的所有数据!只能对从库执行,不能对主库执行。

# 重新初始化从库(会提示确认)
$ pg reinit pg-test pg-test-2
Are you sure you want to reinitialize members pg-test-2? [y/N]: y
Success: reinitialize for member pg-test-2

# 强制重新初始化,跳过确认
pg reinit pg-test pg-test-2 --force

# 重新初始化并等待完成
pg reinit pg-test pg-test-2 --force --wait

重建过程中,可以使用 pg list 查看进度。从库状态会显示为 creating replica

+ Cluster: pg-test (7322261897169354773) --------------+----+------+
| Member    | Host        | Role    | State            | TL | Lag  |
+-----------+-------------+---------+------------------+----+------+
| pg-test-1 | 10.10.10.11 | Leader  | running          |  2 |      |
| pg-test-2 | 10.10.10.12 | Replica | creating replica |    |    ? |
+-----------+-------------+---------+------------------+----+------+

暂停自动切换

使用 pause 子命令可以暂停 Patroni 的自动故障转移功能。暂停后,即使主库故障,Patroni 也不会自动提升从库为新主库。适用于计划内维护窗口(避免维护操作误触发切换)、调试问题时防止集群状态变化、或需要手动控制切换时机等场景。

pg pause <cls>                        # 暂停自动故障转移
pg pause <cls> --wait                 # 暂停并等待所有成员确认

⚠️ 警告:暂停期间如果主库故障,集群将不会自动恢复!请确保在维护完成后及时使用 resume 恢复。

# 暂停自动切换
$ pg pause pg-test
Success: cluster management is paused

# 查看集群状态(底部会显示 Maintenance mode: on)
$ pg list pg-test
+ Cluster: pg-test (7322261897169354773) -----+----+--------------+
| Member    | Host        | Role    | State   | TL | Lag in MB    |
+-----------+-------------+---------+---------+----+--------------+
| pg-test-1 | 10.10.10.11 | Leader  | running |  1 |              |
| pg-test-2 | 10.10.10.12 | Replica | running |  1 |            0 |
+-----------+-------------+---------+---------+----+--------------+
 Maintenance mode: on

恢复自动切换

使用 resume 子命令可以恢复 Patroni 的自动故障转移功能。维护完成后应立即执行此命令,以确保集群在主库故障时能够自动恢复。

pg resume <cls>                       # 恢复自动故障转移
pg resume <cls> --wait                # 恢复并等待所有成员确认
# 恢复自动切换
$ pg resume pg-test
Success: cluster management is resumed

# 确认已恢复(Maintenance mode 提示消失)
$ pg list pg-test

查看历史

使用 history 子命令可以查看集群的故障转移历史记录。每次主从切换(无论是自动故障转移还是手动切换)都会生成一条新的时间线记录。

pg history <cls>                      # 显示故障转移历史
pg history <cls> -f json              # 以 JSON 格式输出
pg history <cls> -f yaml              # 以 YAML 格式输出
$ pg history pg-test
+----+-----------+------------------------------+---------------------------+
| TL |       LSN | Reason                       | Timestamp                 |
+----+-----------+------------------------------+---------------------------+
|  1 | 0/5000060 | no recovery target specified | 2024-01-15T10:30:00+08:00 |
|  2 | 0/6000000 | switchover to pg-test-2      | 2024-01-20T14:00:00+08:00 |
|  3 | 0/7000028 | failover to pg-test-1        | 2024-01-25T09:15:00+08:00 |
+----+-----------+------------------------------+---------------------------+

输出列说明:TL 是时间线编号(Timeline),每次切换后递增,用于区分不同的主库历史;LSN 是切换时的日志序列号(Log Sequence Number),标识切换发生时的 WAL 位置;Reason 是切换原因,可能是 switchover to xxx(手动切换)、failover to xxx(故障转移)或 no recovery target specified(初始化);Timestamp 是切换发生的时间戳。


显示配置

使用 show-config 子命令可以查看集群当前存储在 DCS 中的配置。这是一个只读操作,如需修改配置请使用 edit-config 命令。

pg show-config <cls>                  # 显示集群配置
$ pg show-config pg-test
loop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
  parameters:
    archive_command: pgbackrest --stanza=pg-test archive-push %p
    max_connections: 100
    shared_buffers: 256MB
    log_min_duration_statement: 1000
  use_pg_rewind: true
  use_slots: true
retry_timeout: 10
ttl: 30
synchronous_mode: false

执行查询

使用 query 子命令可以在集群成员上快速执行 SQL 查询。这是一个方便的调试工具,适合快速检查集群状态或执行简单查询。生产环境中的复杂查询建议使用 psql 或应用程序连接。

pg query <cls> -c "<sql>"             # 在主库上执行查询
pg query <cls> -c "<sql>" -m <member> # 在指定实例上执行(--member)
pg query <cls> -c "<sql>" -r leader   # 在主库上执行(--role)
pg query <cls> -c "<sql>" -r replica  # 在所有从库上执行
pg query <cls> -f <file>              # 从文件读取 SQL 执行
pg query <cls> -c "<sql>" -U <user>   # 指定用户名(--username)
pg query <cls> -c "<sql>" -d <db>     # 指定数据库(--dbname)
pg query <cls> -c "<sql>" --format json  # 以 JSON 格式输出
# 查看主库当前连接数
pg query pg-test -c "SELECT count(*) FROM pg_stat_activity"

# 查看 PostgreSQL 版本
pg query pg-test -c "SELECT version()"

# 在所有从库上查看复制状态
pg query pg-test -c "SELECT pg_is_in_recovery(), pg_last_wal_replay_lsn()" -r replica

# 在指定实例上执行
pg query pg-test -c "SELECT pg_is_in_recovery()" -m pg-test-2

# 使用指定用户和数据库
pg query pg-test -c "SELECT current_user, current_database()" -U postgres -d postgres

# 以 JSON 格式输出结果
pg query pg-test -c "SELECT * FROM pg_stat_replication" --format json

查看拓扑

使用 topology 子命令可以以树形结构查看集群的复制拓扑。与 list 相比,topology 更直观地展示了主从复制关系,特别适合级联复制(Cascading Replication)场景。

pg topology <cls>                     # 显示复制拓扑
$ pg topology pg-test
+ Cluster: pg-test (7322261897169354773) -------+----+--------------+
| Member      | Host        | Role    | State   | TL | Lag in MB    |
+-------------+-------------+---------+---------+----+--------------+
| pg-test-1   | 10.10.10.11 | Leader  | running |  1 |              |
| + pg-test-2 | 10.10.10.12 | Replica | running |  1 |            0 |
| + pg-test-3 | 10.10.10.13 | Replica | running |  1 |            0 |
+-------------+-------------+---------+---------+----+--------------+

在级联复制场景中,拓扑图会清晰展示复制链路层级,例如 pg-test-3pg-test-2 复制,而 pg-test-2 从主库 pg-test-1 复制。


查看版本

使用 version 子命令可以查看 patronictl 的版本信息。

pg version                            # 显示 patronictl 版本
$ pg version
patronictl version 4.1.0

移除成员

使用 remove 子命令可以从 DCS(分布式配置存储)中移除集群或成员的元数据。这是一个危险操作,仅移除 DCS 中的元数据,不会停止 PostgreSQL 服务或删除数据文件。错误使用可能导致集群状态不一致。

pg remove <cls>                       # 从 DCS 中移除整个集群的元数据

通常情况下您不需要使用此命令。如需正确移除集群或实例,请使用 Pigsty 提供的 bin/pgsql-rm 脚本或 pgsql-rm.yml 剧本。 只有在以下特殊情况下才考虑使用 remove:DCS 中存在孤立的元数据需要清理(例如节点已物理移除但元数据残留),或集群已通过其他方式销毁需要清理残留信息。

# 移除整个集群的元数据(需要多次确认)
$ pg remove pg-test
Please confirm the cluster name to remove: pg-test
You are about to remove all information in DCS for pg-test, please type: "Yes I am aware": Yes I am aware

5 - 管理 PostgreSQL HBA 认证规则

HBA 管理:刷新规则、验证配置、故障排查、PgBouncer HBA

快速上手

Pigsty 使用声明式管理方式,首先在 配置清单定义 HBA 规则,然后使用 bin/pgsql-hba <cls> 刷新规则。

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_hba_rules:                            # <--- 在这里定义 HBA 规则列表!
      - {user: dbuser_app, db: app, addr: intra, auth: pwd, title: 'app access'}
      - {user: dbuser_api, db: all, addr: world, auth: ssl, title: 'api ssl access'}
脚本
bin/pgsql-hba <cls>              # 刷新集群的 PostgreSQL 和 Pgbouncer HBA 规则
bin/pgsql-hba <cls> <ip>...      # 刷新集群中特定实例的 HBA 规则
剧本
./pgsql.yml -l <cls> -t pg_hba,pg_reload                 # 仅刷新 PostgreSQL HBA
./pgsql.yml -l <cls> -t pgbouncer_hba,pgbouncer_reload   # 仅刷新 Pgbouncer HBA
./pgsql.yml -l <cls> -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload  # 同时刷新两者
示例
bin/pgsql-hba pg-meta                      # 刷新 pg-meta 集群的 HBA 规则
bin/pgsql-hba pg-meta 10.10.10.10          # 仅刷新特定实例
bin/pgsql-hba pg-meta 10.10.10.11 10.10.10.12  # 刷新多个实例

关于规则语法,请查阅 HBA 配置;关于认证方法、默认边界与凭据管理,请参考 身份认证

操作 说明 风险
刷新 HBA 规则 重新渲染配置文件并重载服务
验证 HBA 规则 查看当前生效规则,测试连接认证 只读
常见管理场景 添加规则、封禁 IP、角色区分、扩容刷新
故障排查 连接被拒绝、认证失败、规则未生效 -
Pgbouncer HBA Pgbouncer 连接池的 HBA 管理
demo/pgsql-hba.cast

刷新 HBA 规则

修改 pigsty.yml 中的 HBA 规则后,需要重新渲染配置文件并让服务重载。

脚本
bin/pgsql-hba <cls>              # 刷新整个集群的 HBA 规则(PostgreSQL + Pgbouncer)
bin/pgsql-hba <cls> <ip>...      # 刷新特定实例(多个 IP 空格分隔)
剧本
./pgsql.yml -l <cls> -t pg_hba,pg_reload                 # 仅刷新 PostgreSQL HBA
./pgsql.yml -l <cls> -t pgbouncer_hba,pgbouncer_reload   # 仅刷新 Pgbouncer HBA
./pgsql.yml -l <cls> -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload  # 同时刷新两者
示例
bin/pgsql-hba pg-meta                      # 刷新 pg-meta 集群
bin/pgsql-hba pg-meta 10.10.10.10          # 仅刷新 10.10.10.10 实例

执行效果:根据配置清单中的 HBA 规则定义,渲染 PostgreSQL 和 Pgbouncer 的 HBA 配置文件,然后重载服务使配置生效。

配置文件位置

服务 配置文件路径 模板文件
PostgreSQL /pg/data/pg_hba.conf roles/pgsql/templates/pg_hba.conf
Pgbouncer /etc/pgbouncer/pgb_hba.conf roles/pgsql/templates/pgbouncer.hba
不要直接编辑配置文件

直接编辑 /pg/data/pg_hba.conf/etc/pgbouncer/pgb_hba.conf 虽然可以临时生效,但下次执行 Ansible 剧本时会被覆盖。所有 HBA 规则变更应在 pigsty.yml 中进行,然后执行 bin/pgsql-hba 刷新。

相关 Tags

Tag 说明
pg_hba 渲染 PostgreSQL HBA 配置文件
pg_reload 重载 PostgreSQL 配置(需配合 pg_reload=true
pgbouncer_hba 渲染 Pgbouncer HBA 配置文件
pgbouncer_reload 重载 Pgbouncer 配置

验证 HBA 规则

刷新 HBA 规则后,可以通过以下方式验证配置是否正确生效。

查看当前生效的 HBA 规则

SQL
-- 查看 PostgreSQL HBA 规则(推荐)
TABLE pg_hba_file_rules;

-- 查看特定数据库的匹配规则
SELECT * FROM pg_hba_file_rules WHERE database @> ARRAY['mydb']::text[];
Bash
# 查看 PostgreSQL HBA 配置文件
cat /pg/data/pg_hba.conf

# 查看 Pgbouncer HBA 配置文件
cat /etc/pgbouncer/pgb_hba.conf

# 查看配置文件头部(确认是否更新)
head -20 /pg/data/pg_hba.conf
测试连接
# 测试特定用户从特定地址的连接
psql -h <host> -p 5432 -U <user> -d <database> -c "SELECT 1"

# 测试通过 Pgbouncer 连接
psql -h <host> -p 6432 -U <user> -d <database> -c "SELECT 1"

检查 HBA 配置语法

# 重载配置(会验证语法)
psql -c "SELECT pg_reload_conf()"

# 如果有语法错误,查看日志
tail -f /pg/log/postgresql-*.log

常见管理场景

添加新的 HBA 规则

在集群配置的 pg_hba_rules 中添加规则,然后执行刷新:

pg-meta:
  vars:
    pg_hba_rules:
      - {user: new_user, db: new_db, addr: '192.168.1.0/24', auth: pwd, title: 'new app access'}
bin/pgsql-hba pg-meta

紧急封禁 IP

当发现恶意 IP 时,可以添加高优先级(order: 0)的拒绝规则:

pg_hba_rules:
  - {user: all, db: all, addr: '10.1.1.100/32', auth: deny, order: 0, title: 'emergency block'}
bin/pgsql-hba pg-meta    # 立即刷新生效

按角色区分规则

为主库和从库配置不同的 HBA 规则,使用 role 参数:

pg_hba_rules:
  # 仅主库允许写入用户
  - {user: writer, db: all, addr: intra, auth: pwd, role: primary, title: 'writer on primary'}
  # 从库允许只读用户
  - {user: reader, db: all, addr: world, auth: ssl, role: replica, title: 'reader on replica'}

执行刷新后,规则会根据实例的 pg_role 自动启用或禁用。

集群扩容后刷新 HBA

当集群新增实例后,使用 addr: cluster 的规则需要刷新才能包含新成员:

./pgsql.yml -l 10.10.10.14       # 扩容新实例
bin/pgsql-hba pg-meta            # 刷新所有实例的 HBA(包含新成员 IP)

主从切换后刷新 HBA

Patroni 故障转移后,实例的 pg_role 可能与配置不一致。如果 HBA 规则使用了 role 过滤,需要更新配置并刷新:

# 更新 pigsty.yml 中的角色定义后刷新
bin/pgsql-hba pg-meta

故障排查

连接被拒绝

症状FATAL: no pg_hba.conf entry for host "x.x.x.x", user "xxx", database "xxx"

排查步骤

  1. 检查当前 HBA 规则,确认是否有匹配的规则:
psql -c "TABLE pg_hba_file_rules"
  1. 确认客户端 IP、用户名、数据库是否匹配任何规则

  2. 检查规则顺序(HBA 是首条匹配生效)

  3. 在配置清单中添加对应规则并刷新:

bin/pgsql-hba <cls>

认证失败

症状FATAL: password authentication failed for user "xxx"

排查步骤

  1. 确认密码正确
  2. 检查密码加密方式(pg_pwd_enc)与客户端兼容性
  3. 检查用户是否存在:
SELECT * FROM pg_roles WHERE rolname = 'xxx';

HBA 规则未生效

排查步骤

  1. 确认已执行刷新命令
  2. 检查 Ansible 执行是否成功
  3. 确认 PostgreSQL 已重载:
psql -c "SELECT pg_reload_conf()"
  1. 检查配置文件是否更新:
head -20 /pg/data/pg_hba.conf

规则顺序问题

HBA 是首条匹配生效,如果规则未按预期工作:

  1. 检查规则定义中的 order
  2. 使用 psql -c "TABLE pg_hba_file_rules" 查看实际顺序
  3. 调整 order 值(数字越小优先级越高)

Pgbouncer HBA

Pgbouncer 的 HBA 管理与 PostgreSQL 类似,但有一些差异。

配置差异

差异点 PostgreSQL Pgbouncer
配置文件 /pg/data/pg_hba.conf /etc/pgbouncer/pgb_hba.conf
复制连接 支持 db: replication 不支持
本地认证 使用 ident 使用 peer

刷新 Pgbouncer HBA

脚本
bin/pgsql-hba <cls>    # 同时刷新 PostgreSQL 和 Pgbouncer
剧本
./pgsql.yml -l <cls> -t pgbouncer_hba,pgbouncer_reload   # 仅刷新 Pgbouncer HBA
查看
cat /etc/pgbouncer/pgb_hba.conf    # 查看 Pgbouncer HBA 规则

最佳实践

  1. 始终在配置文件中管理:不要直接编辑 pg_hba.conf,所有变更通过 pigsty.yml
  2. 测试环境先验证:HBA 变更可能导致连接问题,先在测试环境验证
  3. 使用 order 控制优先级:黑名单规则使用 order: 0,确保优先匹配
  4. 及时刷新:添加/删除实例、主从切换后及时刷新 HBA
  5. 最小权限原则:只开放必要的访问,避免使用 addr: world + auth: trust
  6. 监控认证失败:关注 pg_stat_activity 中的认证失败记录
  7. 备份配置:重要变更前备份 pigsty.yml

相关文档

6 - Pgbouncer 连接池管理

使用 Pgbouncer 管理连接池,包括暂停、恢复、禁用、启用、重连、终止、重载等操作。

概览

Pigsty 使用 Pgbouncer 作为 PostgreSQL 的连接池中间件,默认监听 6432 端口,代理访问本机 5432 端口上的 PostgreSQL 实例。

这是一个 可选组件,如果您并没有海量连接,也不需要事务池化与查询监控指标,可以关闭连接池,直连数据库,或者保留但不使用。


用户与数据库管理

Pgbouncer 中的用户和数据库由 Pigsty 自动管理,并在 创建数据库创建用户 时自动应用 数据库配置用户配置

数据库管理:在 pg_databases 中定义的数据库,默认会自动添加到 Pgbouncer。设置 pgbouncer: false 可以排除特定数据库。

pg_databases:
  - name: mydb                # 默认加入连接池
    pool_auth_user: dbuser_meta # 可选,认证查询用户(配合 pgbouncer_auth_query)
    pool_mode: transaction    # 数据库级池化模式
    pool_size: 50             # 默认池大小
    pool_reserve: 30          # 保留池大小
    pool_size_min: 0          # 最小池大小
    pool_connlimit: 100       # 最大数据库连接数
  - name: internal
    pgbouncer: false          # 不加入连接池

用户管理:在 pg_users 中定义的用户,需要显式设置 pgbouncer: true 才会加入连接池用户列表。

pg_users:
  - name: dbuser_app
    password: DBUser.App
    pgbouncer: true           # 加入连接池用户列表
    pool_mode: transaction    # 用户级池化模式
    pool_connlimit: 50        # 用户级最大连接数

自 Pigsty v4.1.0 起,数据库连接池参数统一使用 pool_reservepool_connlimit,旧别名 pool_size_reserve / pool_max_db_conn 已收敛。


服务管理

在 Pigsty 中,PostgreSQL 集群的 Primary 服务 与 Replica 服务默认指向 Pgbouncer 6432 端口, 如果您想要让这两个服务绕过连接池直接访问 PostgreSQL 实例,可以定制 pg_services,或将 pg_default_service_dest 设置为 postgres


配置管理

Pgbouncer 的配置文件位于 /etc/pgbouncer/ 目录,由 Pigsty 统一生成与管理:

文件 说明
pgbouncer.ini 主配置文件,连接池级别参数
database.txt 数据库列表,数据库级别参数
userlist.txt 用户密码列表
useropts.txt 用户级别的连接池参数
pgb_hba.conf HBA 访问控制规则

Pigsty 会自动管理 database.txtuserlist.txt,在 创建数据库创建用户 时自动更新这些文件。

您也可以手动编辑配置文件后执行 RELOAD 使其生效:

# 编辑配置
$ vim /etc/pgbouncer/pgbouncer.ini

# 重载生效:通过 systemctl
$ sudo systemctl reload pgbouncer

# 重载生效,本身是 pg_dbsu / postgres 用户
$ pgb -c "RELOAD;"

连接池管理

Pgbouncer 使用和 PostgreSQL 相同的 dbsu 运行,默认为 postgres 操作系统用户。Pigsty 提供了快捷命令 pgb 来简化管理操作:

alias pgb='psql -p6432 -dpgbouncer'

您可以在数据库节点上使用 pgb 命令连接到 Pgbouncer 管理控制台,执行管理命令和监控查询。

$ pgb
pgbouncer=# SHOW POOLS;
pgbouncer=# SHOW CLIENTS;
pgbouncer=# SHOW SERVERS;
命令 功能 说明
PAUSE 暂停 暂停数据库连接,等待事务完成后断开服务端连接
RESUME 恢复 恢复被 PAUSE/KILL/SUSPEND 暂停的数据库
DISABLE 禁用 拒绝指定数据库的新客户端连接
ENABLE 启用 允许指定数据库的新客户端连接
RECONNECT 重连 优雅地关闭并重建服务端连接
KILL 终止 立即断开指定数据库的所有客户端和服务端连接
KILL_CLIENT 杀客户端 终止指定的客户端连接
SUSPEND 挂起 刷新缓冲区并停止监听,用于在线重启
SHUTDOWN 关闭 关闭 Pgbouncer 进程
RELOAD 重载 重新加载配置文件
WAIT_CLOSE 等待关闭 等待 RECONNECT/RELOAD 后的服务端连接释放
监控命令 监控 查看连接池状态、客户端、服务端等信息

PAUSE

使用 PAUSE 命令暂停数据库连接。Pgbouncer 会根据池化模式等待活动事务/会话完成后断开服务端连接。新的客户端请求会被阻塞直到执行 RESUME

PAUSE [db];           -- 暂停指定数据库,不指定则暂停所有数据库

典型使用场景:

  • 在线切换后端数据库(如主从切换后更新连接目标)
  • 执行需要断开所有连接的维护操作
  • 配合 SUSPEND 实现 Pgbouncer 在线重启
$ pgb -c "PAUSE mydb;"        # 暂停 mydb 数据库
$ pgb -c "PAUSE;"             # 暂停所有数据库

暂停后,SHOW DATABASES 会显示 paused 状态:

pgbouncer=# SHOW DATABASES;
   name   |   host    | port | database | ... | paused | disabled
----------+-----------+------+----------+-----+--------+----------
 mydb     | /var/run  | 5432 | mydb     | ... |      1 |        0

RESUME

使用 RESUME 命令恢复被 PAUSEKILLSUSPEND 暂停的数据库,允许新的连接请求并恢复正常服务。

RESUME [db];          -- 恢复指定数据库,不指定则恢复所有数据库
$ pgb -c "RESUME mydb;"       # 恢复 mydb 数据库
$ pgb -c "RESUME;"            # 恢复所有数据库

DISABLE

使用 DISABLE 命令禁用指定数据库,拒绝所有新的客户端连接请求。已存在的连接不受影响。

DISABLE db;           -- 禁用指定数据库(必须指定数据库名)

典型使用场景:

  • 临时下线某个数据库进行维护
  • 阻止新连接以便安全地进行数据库迁移
  • 逐步下线即将删除的数据库
$ pgb -c "DISABLE mydb;"      # 禁用 mydb,新连接被拒绝

ENABLE

使用 ENABLE 命令启用之前被 DISABLE 禁用的数据库,重新接受新的客户端连接。

ENABLE db;            -- 启用指定数据库(必须指定数据库名)
$ pgb -c "ENABLE mydb;"       # 启用 mydb,允许新连接

RECONNECT

使用 RECONNECT 命令优雅地重建服务端连接。Pgbouncer 会在连接释放回池后关闭它们,并在需要时建立新连接。

RECONNECT [db];       -- 重建指定数据库的服务端连接,不指定则重建所有

典型使用场景:

  • 后端数据库 IP 地址变更后刷新连接
  • 主从切换后重新路由流量
  • DNS 更新后重建连接
$ pgb -c "RECONNECT mydb;"    # 重建 mydb 的服务端连接
$ pgb -c "RECONNECT;"         # 重建所有服务端连接

执行 RECONNECT 后,可以使用 WAIT_CLOSE 等待旧连接完全释放。


KILL

使用 KILL 命令立即断开指定数据库的所有客户端和服务端连接。与 PAUSE 不同,KILL 不等待事务完成,直接强制断开。

KILL [db];            -- 终止指定数据库的所有连接,不指定则终止所有(admin 除外)
$ pgb -c "KILL mydb;"         # 强制断开 mydb 的所有连接
$ pgb -c "KILL;"              # 强制断开所有数据库的连接(admin 除外)

执行 KILL 后,新连接会被阻塞直到执行 RESUME


KILL_CLIENT

使用 KILL_CLIENT 命令终止指定的客户端连接。客户端 ID 可以从 SHOW CLIENTS 输出中获取。

KILL_CLIENT id;       -- 终止指定 ID 的客户端连接
# 查看客户端连接
$ pgb -c "SHOW CLIENTS;"

# 终止特定客户端(假设 ptr 列显示的 ID 为 0x1234567890)
$ pgb -c "KILL_CLIENT 0x1234567890;"

SUSPEND

使用 SUSPEND 命令挂起 Pgbouncer。Pgbouncer 会刷新所有 socket 缓冲区并停止监听数据,直到执行 RESUME

SUSPEND;              -- 挂起 Pgbouncer

SUSPEND 主要用于实现 Pgbouncer 的在线重启(零停机升级):

# 1. 挂起当前 Pgbouncer
$ pgb -c "SUSPEND;"

# 2. 启动新的 Pgbouncer 进程(使用 -R 选项接管 socket)
$ pgbouncer -R /etc/pgbouncer/pgbouncer.ini

# 3. 新进程接管后,旧进程自动退出

SHUTDOWN

使用 SHUTDOWN 命令关闭 Pgbouncer 进程。支持多种关闭模式:

SHUTDOWN;                      -- 立即关闭
SHUTDOWN WAIT_FOR_SERVERS;     -- 等待服务端连接释放后关闭
SHUTDOWN WAIT_FOR_CLIENTS;     -- 等待客户端断开后关闭(零停机滚动重启)
模式 说明
SHUTDOWN 立即关闭 Pgbouncer 进程
WAIT_FOR_SERVERS 停止接受新连接,等待服务端连接释放后退出
WAIT_FOR_CLIENTS 停止接受新连接,等待所有客户端断开后退出,适用于滚动重启
$ pgb -c "SHUTDOWN WAIT_FOR_CLIENTS;"   # 优雅关闭,等待客户端断开

RELOAD

使用 RELOAD 命令重新加载 Pgbouncer 配置文件。可以动态更新大部分配置参数,无需重启进程。

RELOAD;               -- 重载配置文件
$ pgb -c "RELOAD;"              # 通过管理控制台重载
$ systemctl reload pgbouncer    # 通过 systemd 重载
$ kill -SIGHUP $(cat /run/postgresql/pgbouncer.pid)  # 通过信号重载

Pigsty 提供了重载 Pgbouncer 配置的剧本任务:

./pgsql.yml -l <cls> -t pgbouncer_reload    # 重载集群的 Pgbouncer 配置

WAIT_CLOSE

使用 WAIT_CLOSE 命令等待服务端连接完成关闭。通常在 RECONNECTRELOAD 后使用,确保旧连接已全部释放。

WAIT_CLOSE [db];      -- 等待指定数据库的服务端连接关闭,不指定则等待所有
# 完整的连接重建流程
$ pgb -c "RECONNECT mydb;"
$ pgb -c "WAIT_CLOSE mydb;"    # 等待旧连接释放

监控命令

Pgbouncer 提供了丰富的 SHOW 命令用于监控连接池状态:

命令 说明
SHOW HELP 显示可用命令帮助
SHOW DATABASES 显示数据库配置和状态
SHOW POOLS 显示连接池统计信息
SHOW CLIENTS 显示客户端连接列表
SHOW SERVERS 显示服务端连接列表
SHOW USERS 显示用户配置
SHOW STATS 显示统计信息(请求数、字节数等)
SHOW STATS_TOTALS 显示累计统计信息
SHOW STATS_AVERAGES 显示平均统计信息
SHOW CONFIG 显示当前配置参数
SHOW MEM 显示内存使用情况
SHOW DNS_HOSTS 显示 DNS 缓存的主机名
SHOW DNS_ZONES 显示 DNS 缓存的区域
SHOW SOCKETS 显示打开的 socket 信息
SHOW ACTIVE_SOCKETS 显示活动的 socket
SHOW LISTS 显示内部列表计数
SHOW FDS 显示文件描述符使用情况
SHOW STATE 显示 Pgbouncer 运行状态
SHOW VERSION 显示 Pgbouncer 版本

常用监控示例:

# 查看连接池状态
$ pgb -c "SHOW POOLS;"

# 查看客户端连接
$ pgb -c "SHOW CLIENTS;"

# 查看服务端连接
$ pgb -c "SHOW SERVERS;"

# 查看统计信息
$ pgb -c "SHOW STATS;"

# 查看数据库状态
$ pgb -c "SHOW DATABASES;"

更多监控命令的详细说明,请参考 Pgbouncer 官方文档


Unix 信号

Pgbouncer 支持通过 Unix 信号进行控制,这在无法连接管理控制台时非常有用:

信号 等效命令 说明
SIGHUP RELOAD 重载配置文件
SIGTERM SHUTDOWN WAIT_FOR_CLIENTS 优雅关闭,等待客户端断开
SIGINT SHUTDOWN WAIT_FOR_SERVERS 优雅关闭,等待服务端释放
SIGQUIT SHUTDOWN 立即关闭
SIGUSR1 PAUSE 暂停所有数据库
SIGUSR2 RESUME 恢复所有数据库
# 通过信号重载配置
$ kill -SIGHUP $(cat /run/postgresql/pgbouncer.pid)

# 通过信号优雅关闭
$ kill -SIGTERM $(cat /run/postgresql/pgbouncer.pid)

# 通过信号暂停
$ kill -SIGUSR1 $(cat /run/postgresql/pgbouncer.pid)

# 通过信号恢复
$ kill -SIGUSR2 $(cat /run/postgresql/pgbouncer.pid)

流量切换

Pigsty 管理的数据库路由位于 /etc/pgbouncer/database.txt。要将某个数据库的 Pgbouncer 流量切换到其他节点,需要修改该文件、重载配置,再让已有服务端连接排空并重建:

# 1. 仅把 mydb 的后端目标改为 10.10.10.12
$ sed -i -E '/^mydb[[:space:]]*=/ s#host=[^[:space:]]+#host=10.10.10.12#' /etc/pgbouncer/database.txt

# 2. 重载配置
$ pgb -c "RELOAD;"

# 3. 重建该数据库的连接并等待旧连接释放
$ pgb -c "RECONNECT mydb;"
$ pgb -c "WAIT_CLOSE mydb;"

当前源码附带的 pgb-route 函数只修改 /etc/pgbouncer/pgbouncer.ini;该文件仅 include database.txt,并不包含 Pigsty 生成的逐库 host= 路由。因此它不会改变托管数据库的后端目标,请不要用它替代上述操作。

7 - 管理 PostgreSQL 组件服务

使用 systemctl 管理 PostgreSQL 集群中的各个组件服务:启动、停止、重启、重载与状态检查。

概述

Pigsty 的 PGSQL 模块由多个组件构成,每个组件都以 systemd 服务的形式运行在节点上。(pgbackrest 除外)

了解这些组件及其管理方式,对于维护生产环境中的 PostgreSQL 集群非常重要。

组件 端口 服务名 说明
Patroni 8008 patroni 高可用管理器,负责 PostgreSQL 的生命周期管理
PostgreSQL 5432 postgres 占位服务,默认不使用,应急使用
Pgbouncer 6432 pgbouncer 连接池中间件,业务流量入口
PgBackRest - - pgBackRest 没有守护服务
HAProxy 543x haproxy 负载均衡器,暴露数据库服务
pg_exporter 9630 pg_exporter PostgreSQL 监控指标导出器
pgbouncer_exporter 9631 pgbouncer_exporter Pgbouncer 监控指标导出器
vip-manager - vip-manager 可选,管理 L2 VIP 地址漂移
重要提示

不要直接使用 systemctl 管理 PostgreSQL 服务。PostgreSQL 由 Patroni 托管,应通过 patronictl 命令进行管理。 直接操作 PostgreSQL 可能导致 Patroni 状态不一致,触发意外的故障转移。postgres 服务是 Patroni 服务失效时的应急逃生窗口。


命令速查

操作 命令
启动服务 systemctl start <service>
停止服务 systemctl stop <service>
重启服务 systemctl restart <service>
重载配置 systemctl reload <service>
查看状态 systemctl status <service>
查看日志 journalctl -u <service> -f
开机启动 systemctl enable <service>
禁用启动 systemctl disable <service>

常用组件服务名:patronipgbouncerhaproxypg_exporterpgbouncer_exportervip-manager


Patroni

Patroni 是 PostgreSQL 的高可用管理器,负责 PostgreSQL 的启动、停止、故障检测与自动故障转移。 它是 PGSQL 模块的核心组件,PostgreSQL 进程由 Patroni 托管,不应直接通过 systemctl 管理 postgres 服务。

启动 Patroni

systemctl start patroni     # 启动 Patroni(同时启动 PostgreSQL)

启动 Patroni 后,它会自动拉起 PostgreSQL 进程。首次启动时,Patroni 会根据角色决定行为:

  • 主库:初始化或恢复数据目录
  • 从库:从主库克隆数据并建立复制

停止 Patroni

systemctl stop patroni      # 停止 Patroni(同时停止 PostgreSQL)

停止 Patroni 时,它会优雅地关闭 PostgreSQL 进程。注意:如果这是主库,且未暂停自动切换,可能触发故障转移。

重启 Patroni

systemctl restart patroni   # 重启 Patroni(同时重启 PostgreSQL)

重启会导致短暂的服务中断。对于生产环境,建议使用 pg restart 命令进行滚动重启。

重载 Patroni

systemctl reload patroni    # 重载 Patroni 配置

重载会让 Patroni 重新读取配置文件,并将可热加载的参数应用到 PostgreSQL。

查看状态与日志

systemctl status patroni    # 查看 Patroni 服务状态
journalctl -u patroni -f    # 实时查看 Patroni 日志
journalctl -u patroni -n 100 --no-pager  # 查看最近 100 行日志

配置文件位置/etc/patroni/patroni.yml

最佳实践:使用 patronictl 而非 systemctl 管理 PostgreSQL 集群。


Pgbouncer

Pgbouncer 是轻量级的 PostgreSQL 连接池中间件。 业务流量通常通过 Pgbouncer(6432 端口)而非直接连接 PostgreSQL(5432 端口),以实现连接复用和保护数据库。

启动 Pgbouncer

systemctl start pgbouncer

停止 Pgbouncer

systemctl stop pgbouncer

注意:停止 Pgbouncer 会中断所有通过连接池的业务连接。

重启 Pgbouncer

systemctl restart pgbouncer

重启会断开所有现有连接。如果只是配置变更,建议使用 reload

重载 Pgbouncer

systemctl reload pgbouncer

重载会重新读取配置文件(用户列表、连接池参数等),不会断开现有连接。

查看状态与日志

systemctl status pgbouncer
journalctl -u pgbouncer -f

配置文件位置

  • 主配置:/etc/pgbouncer/pgbouncer.ini
  • HBA 规则:/etc/pgbouncer/pgb_hba.conf
  • 用户列表:/etc/pgbouncer/userlist.txt
  • 数据库列表:/etc/pgbouncer/database.txt

管理控制台

psql -p 6432 -U postgres -d pgbouncer  # 连接到 Pgbouncer 管理控制台

常用管理命令:

SHOW POOLS;      -- 查看连接池状态
SHOW CLIENTS;    -- 查看客户端连接
SHOW SERVERS;    -- 查看后端服务器连接
SHOW STATS;      -- 查看统计信息
RELOAD;          -- 重载配置
PAUSE;           -- 暂停所有连接池
RESUME;          -- 恢复所有连接池

HAProxy

HAProxy 是高性能的负载均衡器,负责将流量分发到正确的 PostgreSQL 实例。 Pigsty 使用 HAProxy 暴露 服务,根据角色(主库/从库)和健康状态进行流量调度。

启动 HAProxy

systemctl start haproxy

停止 HAProxy

systemctl stop haproxy

注意:停止 HAProxy 会中断所有通过负载均衡器的连接。

重启 HAProxy

systemctl restart haproxy

重载 HAProxy

systemctl reload haproxy

HAProxy 支持优雅重载,不会断开现有连接。配置变更后推荐使用 reload

查看状态与日志

systemctl status haproxy
journalctl -u haproxy -f

配置文件位置:主配置为 /etc/haproxy/haproxy.cfg,Pigsty 生成的服务片段位于 /etc/haproxy/conf.d/

管理界面

HAProxy 提供 Web 管理界面,默认监听在 9101 端口:

http://<node_ip>:9101/haproxy

默认认证:用户名 admin,密码由 haproxy_admin_password 配置。


pg_exporter

pg_exporter 是 PostgreSQL 的 Prometheus 监控指标导出器,负责采集数据库性能指标。

启动 pg_exporter

systemctl start pg_exporter

停止 pg_exporter

systemctl stop pg_exporter

停止后,Prometheus 将无法采集该实例的 PostgreSQL 监控指标。

重启 pg_exporter

systemctl restart pg_exporter

查看状态与日志

systemctl status pg_exporter
journalctl -u pg_exporter -f

配置文件位置/etc/pg_exporter.yml

验证指标采集

curl -s localhost:9630/metrics | head -20

pgbouncer_exporter

pgbouncer_exporter 是 Pgbouncer 的 Prometheus 监控指标导出器。

启动/停止/重启

systemctl start pgbouncer_exporter
systemctl stop pgbouncer_exporter
systemctl restart pgbouncer_exporter

查看状态与日志

systemctl status pgbouncer_exporter
journalctl -u pgbouncer_exporter -f

验证指标采集

curl -s localhost:9631/metrics | head -20

vip-manager

vip-manager 是可选组件,用于管理 L2 VIP 地址漂移。 当启用 pg_vip_enabled 时,vip-manager 会将 VIP 绑定到当前主库节点。

启动 vip-manager

systemctl start vip-manager

停止 vip-manager

systemctl stop vip-manager

停止后,VIP 地址会从当前节点释放。

重启 vip-manager

systemctl restart vip-manager

查看状态与日志

systemctl status vip-manager
journalctl -u vip-manager -f

配置文件位置/etc/default/vip-manager

验证 VIP 绑定

ip addr show           # 查看网络接口,检查 VIP 是否绑定
pg list <cls>          # 确认主库位置

启动顺序与依赖

PGSQL 模块组件的推荐启动顺序:

1. patroni          # 首先启动 Patroni(会自动启动 PostgreSQL)
2. pgbouncer        # 然后启动连接池
3. haproxy          # 启动负载均衡器
4. pg_exporter      # 启动监控导出器
5. pgbouncer_exporter
6. vip-manager      # 最后启动 VIP 管理器(如果启用)

停止顺序应相反。Pigsty 剧本会自动处理这些依赖关系。

批量启动所有服务

systemctl start patroni pgbouncer haproxy pg_exporter pgbouncer_exporter

批量停止所有服务

systemctl stop pgbouncer_exporter pg_exporter haproxy pgbouncer patroni

常见故障排查

服务启动失败

systemctl status <service>        # 查看服务状态
journalctl -u <service> -n 50     # 查看最近日志
journalctl -u <service> --since "5 min ago"  # 查看最近 5 分钟日志

Patroni 无法启动

现象 可能原因 解决方案
无法连接 etcd etcd 集群不可用 检查 etcd 服务状态
数据目录权限错误 文件所有权不是 postgres chown -R postgres:postgres /pg/data
端口被占用 PostgreSQL 残留进程 pg_ctl stop -D /pg/datakill

Pgbouncer 无法启动

现象 可能原因 解决方案
配置文件语法错误 INI 格式错误 检查 /etc/pgbouncer/pgbouncer.ini
端口被占用 6432 端口已被使用 lsof -i :6432
userlist.txt 权限 文件权限不正确 chmod 600 /etc/pgbouncer/userlist.txt

HAProxy 无法启动

现象 可能原因 解决方案
配置文件语法错误 主配置或服务片段格式错误 haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d -c -q
端口被占用 服务端口冲突 lsof -i :5433

相关文档

8 - 管理 PostgreSQL 定时任务

配置 Crontab 定期调度 PostgreSQL 备份任务,执行备份 / Vacuum Freeze / Analyze 任务,以及处理表膨胀

Pigsty 使用 crontab 来管理定时任务,用于执行例行备份,冻结老化事务,重整膨胀表索引等维护工作。

速查手册

操作 快捷命令 说明
配置定时任务 ./pgsql.yml -t pg_crontab -l <cls> 应用 pg_crontab 配置
查看定时任务 crontab -l 以 postgres 用户查看
物理备份 pg-backup [full|diff|incr] 使用 pgBackRest 执行备份
事务冻结 pg-vacuum [database...] 冻结老化事务,预防 XID 回卷
膨胀治理 pg-repack [database...] 在线重整膨胀的表与索引

其他管理任务,请参考:备份管理监控系统高可用管理


配置定时任务

使用 pg_crontab 参数配置 PostgreSQL 数据库超级用户(pg_dbsu,默认 postgres)的定时任务。

下面 pg-meta 集群配置了每天凌晨1点进行全量备份的定时任务,pg-test 配置了每周一全量备份,其余日期增量备份的定时任务。

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_crontab:
      - '00 01 * * * /pg/bin/pg-backup'
pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }
  vars:
    pg_cluster: pg-test
    pg_crontab:
      - '00 01 * * 1            /pg/bin/pg-backup full'
      - '00 01 * * 2,3,4,5,6,7  /pg/bin/pg-backup'

推荐的维护计划

pg_crontab:
  - '00 01 * * * /pg/bin/pg-backup full'    # 每天凌晨1点全量备份
  - '00 03 * * 0 /pg/bin/pg-vacuum'         # 每周日凌晨3点执行 vacuum freeze
  - '00 04 * * 1 /pg/bin/pg-repack'         # 每周一凌晨4点执行 repack
任务 频率 时机 说明
pg-backup 每天 凌晨 全量或增量备份,视业务需求而定
pg-vacuum 每周一次 周日凌晨 冻结老化事务,预防 XID 回卷
pg-repack 每周/每月 业务低峰期 重整膨胀表索引,回收空间
仅在主库执行

pg-backuppg-vacuumpg-repack 脚本会自动检测当前节点角色,只有主库才会实际执行,从库会直接退出。

因此可以安全地在所有节点配置相同的定时任务,故障切换后新主库会自动继续执行维护任务。


应用定时任务

定时任务会在 pgsql.yml 剧本执行时(pg_crontab 任务)自动写入对应操作系统发行版的默认位置:

  • EL(RHEL/Rocky/Alma):/var/spool/cron/postgres
  • Debian/Ubuntu:/var/spool/cron/crontabs/postgres
剧本
./pgsql.yml -l pg-meta -t pg_crontab     # 应用 pg_crontab 配置到指定集群
./pgsql.yml -l 10.10.10.10 -t pg_crontab # 仅针对特定主机
手工
# 以 postgres 用户编辑定时任务
sudo -u postgres crontab -e

# 或直接编辑 crontab 文件
sudo vi /var/spool/cron/postgres           # EL 系列
sudo vi /var/spool/cron/crontabs/postgres  # Debian/Ubuntu

每次执行剧本都会 全量覆盖刷新 定时任务配置。


查看定时任务

使用 pg_dbsu 操作系统用户执行以下命令查看定时任务:

crontab -l

# Pigsty Managed Crontab for postgres
SHELL=/bin/bash
PATH=/usr/pgsql/bin:/pg/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
MAILTO=""
00 01 * * * /pg/bin/pg-backup

如果您不熟悉 Crontab 的语法,可以参考 Crontab Guru 的解释。


pg-backup

pg-backup 是 Pigsty 提供的物理备份脚本,基于 pgBackRest 实现,支持全量、差异、增量三种备份模式。

基本用法

pg-backup                # 执行增量备份(默认),如果没有全量备份则自动执行全量备份
pg-backup full           # 执行全量备份
pg-backup diff           # 执行差异备份(基于最近的全量备份)
pg-backup incr           # 执行增量备份(基于最近的任意备份)

备份类型说明

类型 参数 说明
全量备份 full 完整备份所有数据,恢复时只需要该备份
差异备份 diff 备份自上次全量备份以来的变更,恢复时需要全量+差异
增量备份 incr 备份自上次任意备份以来的变更,恢复时需要完整链路

执行条件

  • 脚本必须在 主库 上以 postgres 用户身份运行
  • 脚本会自动检测当前节点角色,从库执行时会直接退出(exit 1)
  • /etc/pgbackrest/pgbackrest.conf 中自动获取 stanza 名称

常用定时任务配置

每日全量
pg_crontab:
  - '00 01 * * * /pg/bin/pg-backup full'    # 每天凌晨1点全量备份
周全量+日增量
pg_crontab:
  - '00 01 * * 1            /pg/bin/pg-backup full'  # 周一全量备份
  - '00 01 * * 2,3,4,5,6,7  /pg/bin/pg-backup'       # 其他日期增量备份
周全量+日差异
pg_crontab:
  - '00 01 * * 1            /pg/bin/pg-backup full'  # 周一全量备份
  - '00 01 * * 2,3,4,5,6,7  /pg/bin/pg-backup diff'  # 其他日期差异备份

更多备份恢复操作,请参考 备份管理 章节。


pg-vacuum

pg-vacuum 是 Pigsty 提供的事务冻结脚本,用于执行 VACUUM FREEZE 操作,防止事务 ID(XID)回卷导致数据库停机。

基本用法

基本
pg-vacuum                    # 冻结所有数据库中的老化表
pg-vacuum mydb               # 仅处理指定数据库
选项
pg-vacuum -n mydb            # 空跑模式,只显示不执行
pg-vacuum -a 80000000 mydb   # 使用自定义年龄阈值(默认1亿)
pg-vacuum -r 50 mydb         # 使用自定义老化比例阈值(默认40%)
手工SQL
-- 对整个数据库执行 VACUUM FREEZE
VACUUM FREEZE;

-- 对特定表执行 VACUUM FREEZE
VACUUM FREEZE schema.table_name;

命令选项

选项 说明 默认值
-h, --help 显示帮助信息 -
-n, --dry-run 空跑模式,只显示不执行 false
-a, --age 年龄阈值,超过此值的表需要冻结 100000000
-r, --ratio 老化比例阈值,超过则全库冻结(%) 40

工作逻辑

  1. 检查数据库的 datfrozenxid 年龄,如果低于阈值则跳过该库
  2. 计算老化页面比例(超过年龄阈值的表页面占总页面的百分比)
  3. 如果老化比例 > 40%,执行全库 VACUUM FREEZE ANALYZE
  4. 否则,仅对超过年龄阈值的表执行 VACUUM FREEZE ANALYZE

脚本会设置 vacuum_cost_limit = 10000vacuum_cost_delay = 1ms 以控制 I/O 影响。

执行条件

  • 脚本必须在 主库 上以 pg_dbsu postgres 用户身份运行
  • 使用文件锁 /tmp/pg-vacuum.lock 防止并发执行
  • 自动跳过 template0template1postgres 系统数据库

常用定时任务配置

建议将 vacuum 任务与备份/Repack 任务分开执行,避免冲突。

pg_crontab:
  - '00 03 * * 0 /pg/bin/pg-vacuum'     # 每周日凌晨3点执行

pg-repack

pg-repack 是 Pigsty 提供的膨胀治理脚本,基于 pg_repack 扩展实现,用于在线重整膨胀的表与索引。

基本用法

基本
pg-repack                    # 重整所有数据库中的膨胀表与索引
pg-repack mydb               # 仅重整指定数据库
pg-repack mydb1 mydb2        # 重整多个数据库
选项
pg-repack -n mydb            # 空跑模式,只显示不执行
pg-repack -t mydb            # 仅重整表
pg-repack -i mydb            # 仅重整索引
pg-repack -T 30 -j 4 mydb    # 自定义锁超时(秒)和并行度
手工
# 直接使用 pg_repack 命令重整特定表
pg_repack dbname -t schema.table

# 直接使用 pg_repack 命令重整特定索引
pg_repack dbname -i schema.index

命令选项

选项 说明 默认值
-h, --help 显示帮助信息 -
-n, --dry-run 空跑模式,只显示不执行 false
-t, --table 仅重整表 false
-i, --index 仅重整索引 false
-T, --timeout 锁等待超时时间(秒) 10
-j, --jobs 并行作业数 2

自动选择阈值

脚本会根据表和索引的大小与膨胀率,自动选择需要重整的对象:

表膨胀阈值

大小范围 膨胀率阈值 最大数量
< 256MB > 40% 64
256MB - 2GB > 30% 16
2GB - 8GB > 20% 4
8GB - 64GB > 15% 1

索引膨胀阈值

大小范围 膨胀率阈值 最大数量
< 128MB > 40% 64
128MB - 1GB > 35% 16
1GB - 8GB > 30% 4
8GB - 64GB > 20% 1

超过 64GB 的巨型表/索引会被跳过并给出提示,需要手动处理。

执行条件

  • 脚本必须在 主库 上以 postgres 用户身份运行
  • 需要安装 pg_repack 扩展(Pigsty 默认安装)
  • 需要 monitor schema 中的 pg_table_bloatpg_index_bloat 视图
  • 使用文件锁 /tmp/pg-repack.lock 防止并发执行
  • 自动跳过 template0template1postgres 系统数据库
锁等待

重整期间不会影响正常读写,但重整完毕的 切换瞬间 需要获取表上的 AccessExclusive 锁阻塞一切访问。对于高吞吐量业务,建议在业务低峰期或维护窗口进行。

常用定时任务配置

pg_crontab:
  - '00 04 * * 1 /pg/bin/pg-repack'     # 每周一凌晨4点执行

您可以通过 Pigsty 的 PGCAT Database - Table Bloat 面板确认数据库中的膨胀情况,并选择膨胀率较高的表与索引进行重整。

更多细节请参考:关系膨胀的治理


移除定时任务

当使用 pgsql-rm.yml 剧本移除 PostgreSQL 集群时,会自动删除 postgres 用户的 crontab 文件。

./pgsql-rm.yml -l <cls> -t pg_crontab    # 仅移除定时任务
./pgsql-rm.yml -l <cls>                  # 移除整个集群(包含定时任务)

相关文档

9 - 升级 PostgreSQL 大小版本

版本升级:小版本滚动升级、大版本迁移、扩展升级

快速上手

PostgreSQL 版本升级分为两种类型:小版本升级大版本升级,两者的风险和复杂度差异很大。

类型 示例 停机时间 数据兼容性 风险等级
小版本升级 17.2 → 17.3 秒级(滚动重启) 完全兼容
大版本升级 17 → 18 分钟级 需要升级数据目录
小版本
# 滚动升级:先从库后主库
ansible <cls> -b -a 'yum upgrade -y postgresql17*'
pg restart --role replica --force <cls>
pg switchover <cls>
pg restart <cls> <old-primary> --force
大版本
# 推荐:逻辑复制迁移
bin/pgsql-add pg-new              # 创建新版本集群
# 配置逻辑复制同步数据...
# 切换流量到新集群
扩展
ansible <cls> -b -a 'yum upgrade -y postgis36_17*'
psql -c 'ALTER EXTENSION postgis UPDATE;'

关于在线迁移的详细流程,请参考 在线迁移 文档。

操作 说明 风险
小版本升级 更新软件包,滚动重启
小版本降级 回退到之前的小版本
大版本升级 逻辑复制或 pg_upgrade
扩展升级 升级扩展软件包和扩展对象

小版本升级

小版本升级(如 17.2 → 17.3)是最常见的升级场景,通常用于应用安全补丁和 Bug 修复。数据目录完全兼容,通过滚动重启即可完成。

升级策略:推荐采用 滚动升级 方式:先升级从库,再通过主从切换升级原主库,最小化服务中断。

1. 更新软件仓库 → 2. 升级从库软件包 → 3. 重启从库
4. 主从切换 → 5. 升级原主库软件包 → 6. 重启原主库

步骤一:准备软件包

确保本地软件仓库中有最新版本的 PostgreSQL 包,并刷新节点缓存:

仓库
cd ~/pigsty
./infra.yml -t repo_upstream      # 添加上游仓库(需要互联网)
./infra.yml -t repo_build         # 重建本地仓库
EL
ansible <cls> -b -a 'yum clean all'
ansible <cls> -b -a 'yum makecache'
Debian
ansible <cls> -b -a 'apt clean'
ansible <cls> -b -a 'apt update'

步骤二:升级从库

在所有从库上升级软件包并验证版本:

EL
ansible <cls> -b -a 'yum upgrade -y postgresql17*'
ansible <cls> -b -a '/usr/pgsql/bin/pg_ctl --version'
Debian
ansible <cls> -b -a 'apt install -y postgresql-17'
ansible <cls> -b -a '/usr/lib/postgresql/17/bin/pg_ctl --version'

重启所有从库以应用新版本:

pg restart --role replica --force <cls>

步骤三:切换主库

执行主从切换,将主库角色转移到已升级的从库:

pg switchover <cls>
# 或非交互式:
pg switchover --leader <old-primary> --candidate <new-primary> --scheduled=now --force <cls>

步骤四:升级原主库

原主库现在已降级为从库,升级软件包并重启:

EL
ansible <old-primary-ip> -b -a 'yum upgrade -y postgresql17*'
Debian
ansible <old-primary-ip> -b -a 'apt install -y postgresql-17'
pg restart <cls> <old-primary-name> --force

步骤五:验证

确认所有实例版本一致:

pg list <cls>
pg query <cls> -c "SELECT version()"

小版本降级

在极少数情况下(如新版本引入 Bug),可能需要将 PostgreSQL 降级到之前的版本。

步骤一:获取旧版本包

EL
cd ~/pigsty; ./infra.yml -t repo_upstream     # 添加上游仓库
cd /www/pigsty; repotrack postgresql17-*-17.1 # 下载指定版本的包
cd ~/pigsty; ./infra.yml -t repo_create       # 重建仓库元数据
刷新缓存
ansible <cls> -b -a 'yum clean all'
ansible <cls> -b -a 'yum makecache'

步骤二:执行降级

EL
ansible <cls> -b -a 'yum downgrade -y postgresql17*'
Debian
ansible <cls> -b -a 'apt install -y postgresql-17=17.1*'

步骤三:重启集群

pg restart --force <cls>

大版本升级

大版本升级(如 17 → 18)涉及数据格式变更,需要使用专用工具进行数据迁移。

方式 停机时间 复杂度 适用场景
逻辑复制迁移 秒级切换 生产环境,要求最小停机
pg_upgrade 原地升级 分钟~小时 测试环境,数据量较小
推荐方案

对于生产环境,推荐使用 逻辑复制迁移 方式:创建新版本集群,通过逻辑复制同步数据,然后进行蓝绿切换。这种方式停机时间最短,且可以随时回滚。详见 在线迁移

逻辑复制迁移

逻辑复制迁移是生产环境大版本升级的推荐方式,核心步骤:

1. 创建新版本目标集群 → 2. 配置逻辑复制同步数据 → 3. 验证数据一致性
4. 切换应用流量到新集群 → 5. 下线旧集群

步骤一:创建新版本集群

pg-meta-new:
  hosts:
    10.10.10.12: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta-new
    pg_version: 18                    # 新版本
bin/pgsql-add pg-meta-new

步骤二:配置逻辑复制

-- 源集群(旧版本)主库:创建发布
CREATE PUBLICATION upgrade_pub FOR ALL TABLES;

-- 目标集群(新版本)主库:创建订阅
CREATE SUBSCRIPTION upgrade_sub
  CONNECTION 'host=10.10.10.11 port=5432 dbname=mydb user=replicator password=xxx'
  PUBLICATION upgrade_pub;

步骤三:等待同步完成

-- 目标集群:检查订阅状态
SELECT * FROM pg_stat_subscription;

-- 源集群:检查复制槽 LSN
SELECT slot_name, confirmed_flush_lsn FROM pg_replication_slots;

步骤四:切换流量

确认数据同步完成后:停止应用写入源集群 → 等待最后的数据同步 → 切换应用连接到新集群 → 删除订阅,下线源集群。

-- 目标集群:删除订阅
DROP SUBSCRIPTION upgrade_sub;

详细的迁移流程请参考 在线迁移 文档。

pg_upgrade 原地升级

pg_upgrade 是 PostgreSQL 官方提供的大版本升级工具,适用于测试环境或可接受较长停机时间的场景。

重要警告

原地升级会导致较长的停机时间,且回滚困难。生产环境请优先考虑逻辑复制迁移方式。

步骤一:安装新版本软件包

./pgsql.yml -l <cls> -t pg_pkg -e pg_version=18

步骤二:停止 Patroni

pg pause <cls>                        # 暂停自动故障转移
systemctl stop patroni                # 停止 Patroni(会停止 PostgreSQL)

步骤三:运行 pg_upgrade

sudo su - postgres
mkdir -p /data/postgres/pg-meta-18/data

# 预检(-c 参数只检查不执行)
/usr/pgsql-18/bin/pg_upgrade \
  -b /usr/pgsql-17/bin -B /usr/pgsql-18/bin \
  -d /data/postgres/pg-meta-17/data \
  -D /data/postgres/pg-meta-18/data \
  -v -c

# 执行升级
/usr/pgsql-18/bin/pg_upgrade \
  -b /usr/pgsql-17/bin -B /usr/pgsql-18/bin \
  -d /data/postgres/pg-meta-17/data \
  -D /data/postgres/pg-meta-18/data \
  --link -j 8 -v

步骤四:更新链接并启动

rm -rf /usr/pgsql && ln -s /usr/pgsql-18 /usr/pgsql
rm -rf /pg && ln -s /data/postgres/pg-meta-18 /pg
# 编辑 /etc/patroni/patroni.yml 更新路径
systemctl start patroni
pg resume <cls>

步骤五:后处理

/usr/pgsql-18/bin/vacuumdb --all --analyze-in-stages
./delete_old_cluster.sh   # pg_upgrade 生成的清理脚本

扩展升级

升级 PostgreSQL 版本时,通常也需要升级相关扩展插件。

升级扩展软件包

EL
ansible <cls> -b -a 'yum upgrade -y postgis36_17 timescaledb-2-postgresql-17* pgvector_17*'
Debian
ansible <cls> -b -a 'apt install -y postgresql-17-postgis-3 postgresql-17-pgvector'

升级扩展版本

软件包升级后,在数据库中执行扩展升级:

-- 查看可升级的扩展
SELECT name, installed_version, default_version FROM pg_available_extensions
WHERE installed_version IS NOT NULL AND installed_version <> default_version;

-- 升级扩展
ALTER EXTENSION postgis UPDATE;
ALTER EXTENSION timescaledb UPDATE;
ALTER EXTENSION vector UPDATE;

-- 检查扩展版本
SELECT extname, extversion FROM pg_extension;
扩展兼容性

大版本升级前,请确认所有使用的扩展都支持目标 PostgreSQL 版本。某些扩展可能需要先卸载再重新安装,请查阅扩展文档。


注意事项

  1. 备份优先:任何升级操作前都应进行完整备份
  2. 测试验证:先在测试环境验证升级流程
  3. 扩展兼容:确认所有扩展支持目标版本
  4. 回滚预案:准备好回滚方案,特别是大版本升级
  5. 监控观察:升级后密切监控数据库性能和错误日志
  6. 文档记录:记录升级过程中的所有操作和问题

相关文档

10 - 管理 PostgreSQL 扩展插件

扩展管理:下载、安装、配置、启用、更新、卸载扩展

快速上手

Pigsty 提供 575 扩展,使用扩展涉及四个步骤:下载安装配置启用

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_extensions: [ postgis, timescaledb, pgvector ]           # <--- 安装扩展软件包
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain'    # <--- 配置预加载扩展
    pg_databases:
      - name: meta
        extensions: [ postgis, timescaledb, vector ]            # <--- 在数据库中启用
脚本
bin/pgsql-ext <cls>           # 在 <cls> 集群上安装配置中定义的扩展
bin/pgsql-ext <cls> [ext...]  # 在 <cls> 集群上安装命令行参数给出的扩展
剧本
./pgsql.yml -l pg-meta -t pg_ext    # 使用剧本安装扩展
示例
bin/pgsql-ext pg-meta                         # 在 pg-meta 集群上安装定义的扩展
bin/pgsql-ext pg-meta pg_duckdb pg_mooncake   # 安装指定扩展

关于扩展的完整参考,请查阅 扩展插件 章节。关于可用扩展列表,请参考 扩展目录

操作 快捷命令 说明
下载扩展 ./infra.yml -t repo_build 将扩展下载到本地仓库
安装扩展 bin/pgsql-ext <cls> 在集群节点上安装扩展软件包
配置扩展 pg edit-config <cls> -p 将扩展添加到预加载库(需重启)
启用扩展 psql -c 'CREATE EXT ...' 在数据库中创建扩展对象
更新扩展 ALTER EXTENSION UPDATE 更新扩展软件包与扩展对象
移除扩展 DROP EXTENSION 删除扩展对象,卸载软件包
demo/pgsql-ext.cast

安装扩展

定义在 pg_extensions 里面的扩展会在 PostgreSQL 集群创建 的时候在 pg_extension 任务中自动安装。

要在现有的 PostgreSQL 集群上安装扩展,请将扩展添加到 all.children.<cls>.pg_extensions,然后执行:

脚本
bin/pgsql-ext <cls>   # 在 <cls> 集群上安装扩展
剧本
./pgsql.yml -l <cls> -t pg_extension   # 直接使用 Ansible 剧本安装扩展
示例
bin/pgsql-ext pg-meta    # 在 pg-meta 集群上安装配置中定义的扩展

示例配置:在集群上安装 PostGIS、TimescaleDB 和 PGVector

#all.children.pg-meta.vars: # 省略上级缩进
pg_extensions: [ postgis, timescaledb, pgvector ]

执行效果:在集群所有节点上安装扩展软件包。Pigsty 会自动将 包别名 翻译为对应操作系统和 PostgreSQL 版本的实际包名。

安装前,确保软件源可用

安装扩展前请确保节点已配置正确的软件源 —— 扩展已经在本地仓库中 下载好,或者已经 配置扩展仓库


手工安装

如果您不想使用 Pigsty 配置来管理 PostgreSQL 扩展,可以在命令行中直接传递要安装的扩展列表:

脚本
bin/pgsql-ext pg-meta pg_duckdb pg_mooncake   # 在 pg-meta 集群上安装指定扩展
剧本
./pgsql.yml -l pg-meta -t pg_ext -e '{"pg_extensions": ["pg_duckdb", "pg_mooncake"]}'

您也可以使用 pig 包管理器命令行工具在单个节点上安装扩展,同样会自动进行 包别名 解析。

pig install postgis timescaledb       # 安装多个扩展
pig install pgvector -v 18            # 针对特定 PG 大版本安装

ansible pg-test -b -a 'pig install pg_duckdb'   # 使用 Ansible 在集群上批量安装

您也可以 直接使用操作系统包管理器 (apt/dnf) 进行安装,但您必须知道具体操作系统/PG 下的 RPM/DEB 包名:

# EL 系统(RHEL、Rocky、Alma、Oracle Linux)
sudo yum install -y pgvector_18*

# Debian / Ubuntu 系统
sudo apt install -y postgresql-18-pgvector

下载扩展

要想安装扩展,您需要确保节点上配置的 扩展仓库 包含待安装的扩展:

  • 单机安装 时无需操心,上游仓库已经直接添加到节点上。
  • 离线安装 时无需操心,绝大部分扩展都已经包含在离线安装包里,个别扩展需要在线安装。
  • 使用本地仓库的 生产多节点部署,要看情况,如果在本地仓库创建的时候 repo_packages / repo_extra_packages 中包含了扩展包, 则意味着已经下载到了本地,可以直接安装,否则需要先下载扩展包到本地仓库。或者直接为节点 配置上游仓库 在线安装。

Pigsty 的默认配置在安装过程中会自动下载主流扩展到本地仓库。如需额外扩展,添加到 repo_extra_packages 后重建仓库:

repo_extra_packages: [ pgvector, postgis, timescaledb ]
脚本
make repo         # 快捷方式 = repo-build + node-repo
make repo-build   # 快捷方式,重建 Infra 上的软件仓库(下载软件包与依赖)
make node-repo    # 快捷方式,刷新节点上的软件源缓存,更新对 Infra 软件仓库的引用
剧本
./deploy.yml -t repo_build,node_repo  # 一次性执行两个任务
./infra.yml -t repo_build     # 重新下载软件包到本地仓库
./node.yml  -t node_repo      # 刷新节点软件源缓存

配置仓库

您也可以选择直接让所有节点都使用上游仓库(生产环境不推荐),跳过下载步骤,直接从互联网 上游扩展仓库 安装

./node.yml -t node_repo -e node_repo_modules=node,pgsql   # 添加 PGDG 与 Pigsty 上游仓库

配置扩展

部分扩展需要预加载到 shared_preload_libraries 才能使用,修改后需要 重启数据库 生效。

您可以用 pg_libs 参数作为它的默认值,在配置预加载的扩展,但是这个参数只在集群初始化时生效,后面修改就无效了。

pg-meta:
  vars:
    pg_cluster: pg-meta
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain'   # 预加载扩展
    pg_extensions: [ timescaledb, postgis, pgvector ]          # 安装扩展包

对于已有集群,您可以参考 修改配置 的介绍,修改 shared_preload_libraries 参数:

pg edit-config pg-meta --force -p shared_preload_libraries='timescaledb, pg_stat_statements, auto_explain'
pg restart pg-meta   # 修改 pg-meta 集群的参数,并重启集群使配置生效

请确保扩展软件包已正确安装后再添加预加载配置,如果 shared_preload_libraries 中的扩展不存在或加载失败,PostgreSQL 将 无法启动。 此外,请通过 Patroni 管理集群的配置变更,避免使用 ALTER SYSTEM 或者 pg_parameters 单独修改实例配置。 如果主库和从库配置不一致,可能导致启动失败或复制中断。


启用扩展

安装扩展软件包后,需要在数据库中执行 CREATE EXTENSION 才能使用扩展提供的功能。

集群初始化时启用

数据库定义 中通过 extensions 数组声明要启用的扩展:

pg_databases:
  - name: meta
    extensions:
      - vector                             # 简单形式
      - { name: postgis, schema: public }  # 指定 Schema

手动启用

SQL
CREATE EXTENSION vector;                      -- 创建扩展
CREATE EXTENSION postgis SCHEMA public;       -- 指定 Schema
CREATE EXTENSION IF NOT EXISTS vector;        -- 幂等创建
CREATE EXTENSION postgis_topology CASCADE;    -- 自动安装依赖
psql
psql -d meta -c 'CREATE EXTENSION vector;'                  # 在 meta 数据库创建扩展
psql -d meta -c 'CREATE EXTENSION postgis SCHEMA public;'   # 指定 Schema
剧本
# 修改数据库定义后使用剧本启用扩展
bin/pgsql-db pg-meta meta    # 创建/修改数据库会自动启用定义的扩展

执行效果:在数据库中创建扩展对象(函数、类型、操作符、索引方法等),之后即可使用扩展提供的功能。


更新扩展

扩展更新涉及两个层面:软件包更新扩展对象更新

更新软件包

pig
pig update pgvector                           # 使用 pig 更新扩展
yum
sudo yum update pgvector_18 # EL
apt
sudo apt upgrade postgresql-18-pgvector  # Debian/Ubuntu

更新扩展对象

-- 查看可升级的扩展
SELECT name, installed_version, default_version FROM pg_available_extensions
WHERE installed_version IS NOT NULL AND installed_version <> default_version;

-- 更新扩展到最新版本
ALTER EXTENSION vector UPDATE;

-- 更新到指定版本
ALTER EXTENSION vector UPDATE TO '0.8.1';
更新注意事项

更新扩展前建议备份数据库。预加载扩展更新后可能需要重启 PostgreSQL。某些扩展版本升级可能不兼容,请查阅扩展文档。


移除扩展

移除扩展涉及两个层面:删除扩展对象卸载软件包

删除扩展对象

DROP EXTENSION vector;              -- 删除扩展
DROP EXTENSION vector CASCADE;      -- 级联删除(删除依赖对象)

移除预加载

如果是预加载扩展,需从 shared_preload_libraries 中移除并重启:

pg edit-config pg-meta --force -p shared_preload_libraries='pg_stat_statements, auto_explain'
pg restart pg-meta   # 重启使配置生效

卸载软件包(可选)

pig
pig remove pgvector                           # 使用 pig 卸载
yum
sudo yum remove pgvector_18*                  # EL 系统
apt
sudo apt remove postgresql-18-pgvector        # Debian/Ubuntu
CASCADE 警告

使用 CASCADE 删除扩展会同时删除所有依赖该扩展的对象(表、索引、视图等)。请先检查依赖关系再执行删除。


查询扩展

以下是一些常用的 SQL 查询,用于查看扩展信息:

查看已启用的扩展

SELECT extname, extversion, nspname AS schema
FROM pg_extension e JOIN pg_namespace n ON e.extnamespace = n.oid
ORDER BY extname;

查看可用扩展

SELECT name, default_version, installed_version, comment
FROM pg_available_extensions
WHERE installed_version IS NOT NULL   -- 仅显示已安装的
ORDER BY name;

检查扩展是否可用

SELECT * FROM pg_available_extensions WHERE name = 'vector';

查看扩展依赖关系

SELECT e.extname, d.refobjid::regclass AS depends_on
FROM pg_extension e
JOIN pg_depend d ON d.objid = e.oid
WHERE d.deptype = 'e' AND e.extname = 'postgis_topology';

查看扩展对象

SELECT classid::regclass, objid, deptype
FROM pg_depend
WHERE refobjid = (SELECT oid FROM pg_extension WHERE extname = 'vector');

psql 快捷命令

\dx                    # 列出已启用的扩展
\dx+ vector            # 显示扩展详情

添加仓库

如需直接从上游安装扩展,可手动添加软件仓库。

使用 Pigsty 剧本添加

./node.yml -t node_repo -e node_repo_modules=node,pgsql        # 添加 PGDG 与 Pigsty 仓库
./node.yml -t node_repo -e node_repo_modules=node,pgsql,local  # 包括本地仓库

YUM 仓库(EL 系统)

# Pigsty 仓库
curl -fsSL https://repo.pigsty.io/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null
curl -fsSL https://repo.pigsty.io/yum/repo | sudo tee /etc/yum.repos.d/pigsty.repo >/dev/null

# 中国大陆镜像
curl -fsSL https://repo.pigsty.cc/key | sudo tee /etc/pki/rpm-gpg/RPM-GPG-KEY-pigsty >/dev/null
curl -fsSL https://repo.pigsty.cc/yum/repo | sudo tee /etc/yum.repos.d/pigsty.repo >/dev/null

APT 仓库(Debian/Ubuntu)

curl -fsSL https://repo.pigsty.io/key | sudo gpg --dearmor -o /etc/apt/keyrings/pigsty.gpg
sudo tee /etc/apt/sources.list.d/pigsty.list > /dev/null <<EOF
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/infra generic main
deb [signed-by=/etc/apt/keyrings/pigsty.gpg] https://repo.pigsty.io/apt/pgsql $(lsb_release -cs) main
EOF
sudo apt update

# 中国大陆镜像:将 repo.pigsty.io 替换为 repo.pigsty.cc

常见问题

扩展名与包名的区别

名称 说明 示例
扩展名 CREATE EXTENSION 使用的名称 vector
包别名 Pigsty 配置中使用的标准化名称 pgvector
包名 操作系统实际的包名 pgvector_18*postgresql-18-pgvector

预加载扩展无法启动

如果 shared_preload_libraries 中的扩展不存在或加载失败,PostgreSQL 将无法启动。解决方法:

  1. 确保扩展软件包已正确安装
  2. 或从 shared_preload_libraries 中移除该扩展(编辑 /pg/data/postgresql.conf

扩展依赖问题

某些扩展依赖于其他扩展,需按顺序创建或使用 CASCADE

CREATE EXTENSION postgis;                    -- 先创建基础扩展
CREATE EXTENSION postgis_topology;           -- 再创建依赖扩展
-- 或
CREATE EXTENSION postgis_topology CASCADE;   -- 自动创建依赖

扩展版本不兼容

查看当前 PostgreSQL 版本支持的扩展版本:

SELECT * FROM pg_available_extension_versions WHERE name = 'vector';

相关资源