日常管理
1 - 管理 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/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
如果您在已经存在的集群上重新执行创建操作,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
缩容集群
若要从 现有的 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.yml 的 pg_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 的服务配置
刷新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" | 恢复到指定时间戳 |
| 事务ID | xid: "250000" | 恢复到指定事务之前/之后 |
| 恢复点 | name: "before_migration" | 恢复到命名恢复点 |
| LSN | lsn: "0/4001C80" | 恢复到指定 WAL 位置 |
| 最新 | type: "latest" | 恢复到 WAL 归档末尾 |
恢复后的集群会禁用 archive_mode,以防止意外的 WAL 写入覆盖归档。
如果恢复后的数据库状态正常,您应当启用归档并执行新的全量备份:
psql -c 'ALTER SYSTEM RESET archive_mode; SELECT pg_reload_conf();'
pg-backup full # 执行新的全量备份
更多 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 配置使其立即生效。
如果您需要手工创建用户,那么需要自行确保 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 配置的用户)。
Pigsty 使用 pg-drop-role 脚本安全删除用户,该脚本会自动处理用户拥有的数据库、表空间、Schema、表等对象,自动终止用户的活跃连接,将对象所有权转移给 postgres 用户,并在 /tmp/pg_drop_role_<user>_<timestamp>.log 创建审计日志。无需手动处理依赖对象。
手工删除用户
如果需要手动删除用户,可以直接使用 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_mode、pool_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_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_trgm 和 btree_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 选项,会同时删除依赖该模式/扩展的所有对象。请确保理解影响范围后再执行删除操作。
连接池配置:默认情况下所有业务数据库都会添加到 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 数据源中取消注册。
保护机制:系统数据库 postgres、template0、template1 无法删除。删除操作仅在主库上执行,流复制会自动同步到从库。
删除数据库是不可逆操作,会永久删除该数据库中的所有数据。执行前请确保:已有最新的数据库备份、已确认没有业务在使用该数据库、已通知相关干系人。 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,brtfs,zfs,apfs);不要使用 postgres 数据库作为模版数据库进行克隆;在高并发环境中使用瞬间克隆需要谨慎,需在克隆窗口(200ms)内清理掉所有连接到模版数据库的连接。
连接池管理
在数据库定义中配置的 连接池参数 会在创建/修改数据库时应用到 Pgbouncer 连接池中。
默认情况下所有业务数据库都会添加到 Pgbouncer 连接池(pgbouncer: true)。数据库会被添加到 /etc/pgbouncer/database.txt 文件中,数据库级别的连接池参数(pool_mode、pool_size 等)通过此文件配置。
您可以使用 postgres 操作系统用户,使用 pgb 别名访问 Pgbouncer 管理数据库。更多连接池管理操作,请参考 Pgbouncer 管理。
4 - 管理 Patroni 高可用
概览
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 本身的参数(如 ttl、loop_wait、synchronous_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 # 跳过确认提示
执行切换前请确保所有从库复制状态正常(状态为 running 或 streaming),复制延迟在可接受范围内,并已通知相关业务方。
# 交互式切换(推荐,会显示当前拓扑并提示选择)
$ 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_buffers、shared_preload_libraries、max_connections、max_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())。相比 restart,reload 更加轻量,不会中断数据库连接和正在执行的查询。
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_buffers、max_connections、shared_preload_libraries,archive_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-3 从 pg-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 连接池管理
概览
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.conf | HBA 访问控制规则 |
Pigsty 会自动管理 database.txt 和 userlist.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 命令恢复被 PAUSE、KILL 或 SUSPEND 暂停的数据库,允许新的连接请求并恢复正常服务。
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 命令等待服务端连接完成关闭。通常在 RECONNECT 或 RELOAD 后使用,确保旧连接已全部释放。
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 /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 组件服务
概述
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> |
常用组件服务名:patroni、pgbouncer、haproxy、pg_exporter、pgbouncer_exporter、vip-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 无法启动
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法连接 etcd | etcd 集群不可用 | 检查 etcd 服务状态 |
| 数据目录权限错误 | 文件所有权不是 postgres | chown -R postgres:postgres /pg/data |
| 端口被占用 | PostgreSQL 残留进程 | pg_ctl stop -D /pg/data 或 kill |
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 |
相关文档
- Patroni 管理:使用 patronictl 管理 PostgreSQL 高可用
- 集群管理:集群的创建、扩缩容、销毁
- 服务配置:HAProxy 服务定义与配置
- 监控系统:PostgreSQL 监控与告警
7 - 管理 PostgreSQL 定时任务
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-backup、pg-vacuum、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 |
工作逻辑
- 检查数据库的
datfrozenxid年龄,如果低于阈值则跳过该库 - 计算老化页面比例(超过年龄阈值的表页面占总页面的百分比)
- 如果老化比例 > 40%,执行全库
VACUUM FREEZE ANALYZE - 否则,仅对超过年龄阈值的表执行
VACUUM FREEZE ANALYZE
脚本会设置 vacuum_cost_limit = 10000 和 vacuum_cost_delay = 1ms 以控制 I/O 影响。
执行条件
- 脚本必须在 主库 上以
pg_dbsupostgres 用户身份运行 - 使用文件锁
/tmp/pg-vacuum.lock防止并发执行 - 自动跳过
template0、template1、postgres系统数据库
常用定时任务配置
建议将 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 默认安装) - 需要
monitorschema 中的pg_table_bloat和pg_index_bloat视图 - 使用文件锁
/tmp/pg-repack.lock防止并发执行 - 自动跳过
template0、template1、postgres系统数据库
重整期间不会影响正常读写,但重整完毕的 切换瞬间 需要获取表上的 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> # 移除整个集群(包含定时任务)
相关文档
- 备份管理:PostgreSQL 备份与恢复
- 监控系统:PostgreSQL 监控与告警
- 集群管理:集群的创建、扩缩容、销毁
- Patroni 管理:高可用集群管理
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;
大版本升级前,请确认所有使用的扩展都支持目标 PostgreSQL 版本。某些扩展可能需要先卸载再重新安装,请查阅扩展文档。
注意事项
- 备份优先:任何升级操作前都应进行完整备份
- 测试验证:先在测试环境验证升级流程
- 扩展兼容:确认所有扩展支持目标版本
- 回滚预案:准备好回滚方案,特别是大版本升级
- 监控观察:升级后密切监控数据库性能和错误日志
- 文档记录:记录升级过程中的所有操作和问题
相关文档
- 在线迁移:使用逻辑复制进行零停机迁移
- Patroni 管理:使用 patronictl 管理集群
- 集群管理:集群的创建、扩缩容、销毁
- 备份恢复:PostgreSQL 备份与恢复
- 扩展管理:扩展的安装与管理
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';
更新扩展前建议备份数据库。预加载扩展更新后可能需要重启 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 remove pgvector # 使用 pig 卸载
sudo yum remove pgvector_17* # EL 系统
sudo apt remove postgresql-17-pgvector # Debian/Ubuntu
使用 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_17* 或 postgresql-17-pgvector |
预加载扩展无法启动
如果 shared_preload_libraries 中的扩展不存在或加载失败,PostgreSQL 将无法启动。解决方法:
- 确保扩展软件包已正确安装
- 或从
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';