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...]重载集群的负载均衡配置
刷新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 的详细用法,请参考 恢复操作 文档。

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 用户

关于用户定义参数的完整参考,请查阅 用户配置。关于用户的访问权限,请参考 ACL:角色权限

请注意,用户的 name 字段在创建后无法修改。如需更改用户名,请先删除原用户,再创建新用户。

操作快捷命令说明
创建用户bin/pgsql-user <cls> <user>创建新的业务用户或角色
修改用户bin/pgsql-user <cls> <user>修改已存在用户的属性
删除用户bin/pgsql-user <cls> <user>安全删除用户(需设置 state: absent

创建用户

定义在 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 配置使其立即生效。


修改用户

修改用户与创建用户使用相同的命令,剧本是幂等的。当目标用户已存在时,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              # 用户最大连接数

删除用户

要删除用户,将其 state 设置为 absent 并执行剧本:

bin/pgsql-user <cls> <user>   # 删除用户 <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 脚本安全删除用户,自动禁用用户登录并终止活跃连接,自动转移数据库/表空间所有权到 postgres,自动处理所有数据库中的对象所有权和权限,撤销所有角色成员关系,创建审计日志,从 Pgbouncer 用户列表中移除并重载配置。

保护机制:以下系统用户无法删除,会被自动跳过:postgres(超级用户)、replicator(或 pg_replication_username 配置的用户)、dbuser_dba(或 pg_admin_username 配置的用户)、dbuser_monitor(或 pg_monitor_username 配置的用户)。


手工删除用户

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

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

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

# 删除用户,转移对象给 postgres
pg-drop-role dbuser_old

# 强制删除(终止活跃连接)
pg-drop-role dbuser_old --force

# 删除用户,转移对象给指定用户
pg-drop-role dbuser_old dbuser_new

常见用例

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

创建基本业务用户

- 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_passwordDBUser.DBAdbuser_dba管理员用户密码
pg_monitor_passwordDBUser.Monitordbuser_monitor监控用户密码
pg_replication_passwordDBUser.Replicatorreplicator复制用户密码

要修改 pg_admin_password,请执行以下命令:

# Step 1: 修改配置文件中的密码 pg_admin_password 后(重要!),通过剧本批量修改密码
./pgsql-user.yml -e username=dbuser_dba -e '{"pg_users":[{"name":"dbuser_dba","password":"NewPass123"}]}'

# Step 2: 更新所有 PG 节点的 patroni 配置文件与 .pgpass,然后重载 patroni 配置
./pgsql.yml -t pg_conf,pg_pass,patroni_reload -e pg_reload=true

# Step 3: 刷新 /infra/env/.pgpass 以及 /infra/conf/pg_service.conf 对管理员密码的引用
./infra.yml -t env_pgpass,env_pg_service

要修改 pg_monitor_password,请执行以下命令:

# Step 1: 修改配置文件中的密码 pg_monitor_password 后(重要!),通过剧本批量修改密码
./pgsql-user.yml -e username=dbuser_monitor -e '{"pg_users":[{"name":"dbuser_monitor","password":"NewPass123"}]}'

# Step 2: 更新所有 PG 节点的 patroni 配置文件与 .pgpass,然后重载 patroni 配置
./pgsql.yml -t pg_conf,pg_pass,patroni_reload -e pg_reload=true

# Step 3: 刷新 pg_exporter 与 pgbouncer_exporter 配置里面使用的密码,更新 Grafana 监控面板中数据源使用的密码
./pgsql.yml -t pg_exporter,pgbouncer_exporter,add_ds

要修改 pg_replication_password,请执行以下命令:

# Step 1: 修改配置文件中的密码 pg_replication_password 后(重要!),通过剧本批量修改密码
./pgsql-user.yml -e username=replicator -e '{"pg_users":[{"name":"replicator","password":"NewPass123"}]}'

# Step 2: 更新所有 PG 节点的 patorni 配置文件与 .pgpass,然后重载 patroni 配置
./pgsql.yml -t pg_conf,pg_pass,patroni_reload -e pg_reload=true

# Step 3: 更新 Infra 节点的 .pgpass
./infra.yml -t env_pgpass

此外,Patroni 本身 RestAPI 的密码 patroni_password 可以通过以下命令进行修改:

# Step 1: 刷新 patroni 配置文件里面配置的密码,并重载 patroni 配置应用生效
./pgsql.yml -t pg_conf,patroni_reload -e pg_reload=true

# Step 2: 刷新 /infra/conf/patronictl.yml 对 patroni 密码的引用
./infra.yml -t env_patroni

修改前三个密码前,需先用 SQL 修改对应 PostgreSQL 用户的密码:ALTER USER <username> PASSWORD '<new_password>';

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 数据库

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

请注意,部分数据库参数仅能在 创建时 指定。修改这些参数需要先删除再创建数据库(使用 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>使用模板克隆数据库

创建数据库

定义在 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 数据源。


修改数据库

修改数据库与创建数据库使用相同的命令,在没有定义 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 }        # 卸载扩展

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

- name: myapp
  pgbouncer: true              # 是否加入连接池(默认 true)
  pool_mode: transaction       # 池化模式:transaction/session/statement
  pool_size: 64                # 默认池大小
  pool_connlimit: 100          # 最大数据库连接

删除数据库

要删除数据库,将其 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 无法删除。删除操作仅在主库上执行,流复制会自动同步到从库。


重建数据库

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,brtfs,zfs,apfs);不要使用 postgres 数据库作为模版数据库进行克隆;在高并发环境中使用瞬间克隆需要谨慎,需在克隆窗口(200ms)内清理掉所有连接到模版数据库的连接。


连接池管理

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

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

您可以使用 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 简写)

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

# 修改 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> --leader <old>      # 指定原主库(用于验证,可选)
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

# 指定原主库进行验证(如果原主库名称不匹配会报错)
pg failover pg-test --leader pg-test-1 --candidate pg-test-2 --force

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


重启实例

使用 restart 子命令可以重启 PostgreSQL 实例,通常用于应用需要重启才能生效的参数更改。Patroni 会协调重启过程,对于整个集群的重启会采用滚动方式:先重启从库,最后重启主库,以最小化服务中断。

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

# 重启整个集群(滚动重启,先从库后主库)
pg restart pg-test --force

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

# 仅重启所有从库
pg restart pg-test --role replica --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 子命令可以重新初始化从库。该操作会删除从库上的所有数据,然后从主库重新执行 pg_basebackup 进行完整的数据复制。适用于从库数据损坏无法修复、从库落后太多导致 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 - Pgbouncer 连接池管理

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

概览

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

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


用户与数据库管理

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

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

pg_databases:
  - name: mydb                # 默认加入连接池
    pool_mode: transaction    # 数据库级池化模式
    pool_size: 64             # 默认池大小
  - name: internal
    pgbouncer: false          # 不加入连接池

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

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

服务管理

在 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.confHBA 访问控制规则

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 -p 6432 -d pgbouncer -U postgres"

您可以在数据库节点上使用 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 /var/run/pgbouncer/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 信号进行控制,这在无法连接管理控制台时非常有用:

信号等效命令说明
SIGHUPRELOAD重载配置文件
SIGTERMSHUTDOWN WAIT_FOR_CLIENTS优雅关闭,等待客户端断开
SIGINTSHUTDOWN WAIT_FOR_SERVERS优雅关闭,等待服务端释放
SIGQUITSHUTDOWN立即关闭
SIGUSR1PAUSE暂停所有数据库
SIGUSR2RESUME恢复所有数据库
# 通过信号重载配置
$ kill -SIGHUP $(cat /var/run/pgbouncer/pgbouncer.pid)

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

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

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

流量切换

Pigsty 提供了 pgb-route 实用函数,可以将 Pgbouncer 流量快速切换至其他节点,用于零停机迁移:

# 定义(已在 /etc/profile.d/pg-alias.sh 中)
function pgb-route(){
  local ip=${1-'\/var\/run\/postgresql'}
  sed -ie "s/host=[^[:space:]]\+/host=${ip}/g" /etc/pgbouncer/pgbouncer.ini
  cat /etc/pgbouncer/pgbouncer.ini
}

# 使用:将流量路由到 10.10.10.12
$ pgb-route 10.10.10.12
$ pgb -c "RECONNECT; WAIT_CLOSE;"

完整的零停机切换流程:

# 1. 修改路由目标
$ pgb-route 10.10.10.12

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

# 3. 重建连接并等待旧连接释放
$ pgb -c "RECONNECT;"
$ pgb -c "WAIT_CLOSE;"

6 - 管理 PostgreSQL 组件服务

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

概述

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

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

组件端口服务名说明
Patroni8008patroni高可用管理器,负责 PostgreSQL 的生命周期管理
PostgreSQL5432postgres占位服务,默认不使用,应急使用
Pgbouncer6432pgbouncer连接池中间件,业务流量入口
PgBackRest--pgBackRest 没有守护服务
HAProxy543xhaproxy负载均衡器,暴露数据库服务
pg_exporter9630pg_exporterPostgreSQL 监控指标导出器
pgbouncer_exporter9631pgbouncer_exporterPgbouncer 监控指标导出器
vip-manager-vip-manager可选,管理 L2 VIP 地址漂移

命令速查

操作命令
启动服务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

管理界面

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 无法启动

现象可能原因解决方案
无法连接 etcdetcd 集群不可用检查 etcd 服务状态
数据目录权限错误文件所有权不是 postgreschown -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.cfg 格式错误haproxy -c -f /etc/haproxy/haproxy.cfg
端口被占用服务端口冲突lsof -i :5433

相关文档

7 - 管理 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每周/每月业务低峰期重整膨胀表索引,回收空间

应用定时任务

定时任务会在 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%)
-- 对整个数据库执行 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 系统数据库

常用定时任务配置

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>                  # 移除整个集群(包含定时任务)

相关文档

8 - 升级 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         # 重建本地仓库
ansible <cls> -b -a 'yum clean all'
ansible <cls> -b -a 'yum makecache'
ansible <cls> -b -a 'apt clean'
ansible <cls> -b -a 'apt update'

步骤二:升级从库

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

ansible <cls> -b -a 'yum upgrade -y postgresql17*'
ansible <cls> -b -a '/usr/pgsql/bin/pg_ctl --version'
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>

步骤四:升级原主库

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

ansible <old-primary-ip> -b -a 'yum upgrade -y postgresql17*'
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 降级到之前的版本。

步骤一:获取旧版本包

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'

步骤二:执行降级

ansible <cls> -b -a 'yum downgrade -y postgresql17*'
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 版本时,通常也需要升级相关扩展插件。

升级扩展软件包

ansible <cls> -b -a 'yum upgrade -y postgis36_17 timescaledb-2-postgresql-17* pgvector_17*'
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;

注意事项

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

相关文档

9 - 管理 PostgreSQL 扩展插件

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

快速上手

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

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删除扩展对象,卸载软件包

安装扩展

定义在 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 17            # 针对特定 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_17*

# Debian / Ubuntu 系统
sudo apt install -y postgresql-17-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

手动启用

CREATE EXTENSION vector;                      -- 创建扩展
CREATE EXTENSION postgis SCHEMA public;       -- 指定 Schema
CREATE EXTENSION IF NOT EXISTS vector;        -- 幂等创建
CREATE EXTENSION postgis_topology CASCADE;    -- 自动安装依赖
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 update pgvector                           # 使用 pig 更新扩展
sudo yum update pgvector_18 # EL
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';

移除扩展

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

删除扩展对象

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 remove pgvector                           # 使用 pig 卸载
sudo yum remove pgvector_17*                  # EL 系统
sudo apt remove postgresql-17-pgvector        # Debian/Ubuntu

查询扩展

以下是一些常用的 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_17*postgresql-17-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';

相关资源