跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

PostgreSQL

世界上最先进的开源关系型数据库!

概念

了解 Pigsty 中的 PostgreSQL 集群架构,重要实体与核心概念。

架构
    PostgreSQL 集群架构与核心概念
服务
    通过负载均衡、代理、连接池提供可靠服务接入
数据库
    定义、创建、管理业务数据库
用户
    定义、创建、管理业务用户与角色
认证
    使用 HBA 规则进行认证与访问控制
权限
    开箱即用的默认角色与权限模型

管理

内核
    使用不同风味的 PostgreSQL 内核分支
扩展
    利用 437 个 PostgreSQL 扩展协同带来的超能力
配置
    定义不同类型的 PostgreSQL 实例和集群
参数
    使用 120 个参数来深度定制 PostgreSQL 集群
管理
    管理 PostgreSQL 集群、实例、用户、数据库
剧本
    使用 Ansible 剧本进行控制原语操作
备份恢复
    备份与时间点恢复 (PITR)
迁移
    零停机蓝绿部署迁移
监控
    监控现有的 PostgreSQL 或 RDS 实例
仪表板
    使用 Grafana 仪表板可视化信息

1 - 架构

PostgreSQL 集群架构和概念

实体关系

Pigsty 的 PGSQL 模块中有四种核心实体类型:

  • 集群:一个自治的 PostgreSQL 业务单元,其他实体的顶层命名空间
  • 服务:集群能力的抽象,流量路由,通过不同的节点端口暴露服务
  • 实例:一个 PostgreSQL 服务器,由单个节点上的一组运行进程和文件组成
  • 节点:硬件资源的抽象,可以是裸机、虚拟机或 k8s pod

架构

以下是在 配置清单 中描述的 PostgreSQL 集群 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

它定义了一个如上所示的 高可用 PostgreSQL 集群,该集群中的相关实体包括:

  • 1 个 PostgreSQL 集群:pg-test
  • 2 个实例角色:primaryreplica
  • 3 个 PostgreSQL 实例:pg-test-1pg-test-2pg-test-3
  • 3 个节点:10.10.10.1110.10.10.1210.10.10.13
  • 4 个 PostgreSQL 服务,默认自动生成:

高可用

PostgreSQL 集群由 Patroni 管理, 这是一个经过实战验证的 PostgreSQL 高可用解决方案。 它将在多个节点上设置 PostgreSQL 复制,并在主节点宕机时执行自动故障转移。

备份由 pgBackRest 处理,这是一个强大的 PostgreSQL 备份工具, 支持增量备份/恢复、压缩、加密,备份到本地磁盘或 S3 / MinIO。

pgbouncer 是一个轻量级连接池,可以在高并发情况下提高性能。 它与 Postgres 服务器 1:1 部署,默认被主库/从库服务使用。

服务HAProxy 暴露,这是一个高性能的 TCP/HTTP 负载均衡器,它是 NODE 模块的一部分。 4 个 默认服务幂等的方式在所有集群节点上自动暴露。

应用程序可以访问任何 haproxy 来访问 Postgres 集群,流量将根据 patroni 健康检查端点路由到正确的实例。 因此故障转移对应用程序是透明的。

patroni 需要您的部署中有一个正常工作的 ETCD,pgbackrest 可以使用可选的 MinIO 作为集中备份存储; 监控导出器将收集指标和日志到 Infra 模块。


组件

PGSQL 节点 由以下组件组成(部分可以禁用):

组件 端口 描述
postgres 5432 由 Patroni 管理的 PostgreSQL 服务器进程
pgbouncer 6432 Pgbouncer 连接池
pgbackrest - 备份和时间点恢复工具
patroni 8008 Patroni 高可用组件,管理 postgres
primary @ haproxy 5433 主库连接池:读写服务
replica @ haproxy 5434 从库连接池:只读服务
default @ haproxy 5436 主库直连服务
offline @ haproxy 5438 离线直连:离线读取服务
pg_exporter 9630 PostgreSQL 监控指标导出器
pgbouncer_exporter 9631 pgbouncer 监控指标导出器
pgbackrest_exporter 9854 pgbackrest 监控指标导出器
vip-manager - 绑定 VIP 到主库

交互

同时,基础设施节点 由以下与 PGSQL 交互的组件组成:

组件 端口 域名 描述
nginx 80 h.pigsty Web 服务门户(YUM/APT 仓库)
alertmanager 9059 a.pigsty 告警聚合和分发
prometheus 9058 p.pigsty 监控时间序列数据库
grafana 3000 g.pigsty 可视化平台
lok 3100 - 日志收集服务器
pushgateway 9091 - 收集一次性作业指标
blackbox_exporter 9115 - 黑盒探测
dnsmasq 53 - DNS 服务器
chronyd 123 - NTP 时间服务器
ansible - - 运行剧本
  • 集群 DNS 由基础设施节点上的 DNSMASQ 解析
  • 集群 VIP 由 vip-manager 管理,绑定到集群主库
    • vip-manager 将直接从 etcd 集群获取由 patroni 写入的集群领导者信息
  • 集群服务由节点上的 Haproxy 暴露,服务通过节点端口(543x)区分
    • Haproxy 端口 9101:监控指标、统计信息和管理页面
    • Haproxy 端口 5433:路由到主库 pgbouncer 的默认服务:primary
    • Haproxy 端口 5434:路由到从库 pgbouncer 的默认服务:replica
    • Haproxy 端口 5436:路由到主库 postgres 的默认服务:default
    • Haproxy 端口 5438:路由到离线 postgres 的默认服务:offline
    • HAProxy 将根据 patroni 提供的健康检查信息路由流量
  • Pgbouncer 是监听端口 6432 的连接池
    • 通过本地 unix socket 与 Postgres 服务器 1:1 部署
    • 生产流量(主库/从库)默认通过 pgbouncer
    • 通过将 pg_default_service_dest 设置为 postgres 来绕过 primary/replica 服务的 pgbouncer
    • 默认/离线服务将始终绕过 pgbouncer 并直接连接到目标 Postgres
  • Postgres 在端口 5432 提供关系数据库服务
    • 在多个节点上安装 PGSQL 模块将自动基于复制形成高可用集群
    • PostgreSQL 默认由 patroni 监督
  • Patroni 将默认在端口 8008 监督 PostgreSQL 服务器
    • Patroni 将 postgres 服务器作为子进程生成
    • Patroni 使用 etcd 作为 DCS:配置存储、故障检测和领导者选举
    • Patroni 将通过健康检查提供 Postgres 信息,由 HAProxy 使用
    • Patroni 指标将被基础设施节点上的 prometheus 抓取
  • PG Exporter 将在端口 9630 暴露 postgres 指标
  • Pgbouncer Exporter 将在端口 9631 暴露 pgbouncer 指标
    • Pgbouncer 的指标将被基础设施节点上的 prometheus 抓取
  • pgBackRest 默认在本地仓库上工作(pgbackrest_method
    • 如果使用 local(默认)作为备份仓库,主库的 pg_fs_backup 用作本地备份仓库
    • 如果使用 minio,pgBackRest 将在专用 MinIO 集群上创建仓库
  • Postgres 相关日志(postgres、pgbouncer、patroni、pgbackrest)由 promtail 在端口 9080 暴露
    • Promtail 将日志发送到基础设施节点上的 Loki

完整实体关系图

一个 Pigsty 部署对应一个 配置清单 文件和一个 基础设施。 一个 Pigsty 部署中可能有多个数据库集群。

一个集群/实例可能有多个数据库,数据库包含表和其他对象(查询、索引、函数、序列…)。

2 - 配置

描述和配置 PostgreSQL 集群

您可以定义不同类型的实例和集群。

  • 身份参数:用于描述 PostgreSQL 集群的参数
  • 命名规范:用于描述 PostgreSQL 集群的参数
  • 主库:定义单实例集群
  • 从库:定义具有一个主库和一个从库的基本高可用集群
  • 离线库:为 OLAP/ETL/交互查询定义专用实例
  • 同步从库:启用同步提交以确保无数据丢失
  • 法定人数提交:使用法定人数同步提交获得更高的一致性级别
  • 备用集群:克隆现有集群并跟随它
  • 延迟集群:克隆现有集群用于紧急数据恢复
  • Citus 集群:定义 Citus 分布式数据库集群

身份参数

描述 PostgreSQL 集群需要 4必需参数:

名称 类型 级别 描述
inventory_hostname ip 实例 PG 节点 IPv4 地址
pg_cluster string 集群 PG 数据库集群名称
pg_seq number 实例 PG 数据库实例 ID
pg_role enum 实例 PG 数据库实例角色
  • pg_cluster:集群名称,在集群级别配置
  • pg_role:在实例级别配置,标识实例的角色
    • primary 角色将此实例标记为集群领导者(初始时)
    • replica 是默认角色,将此实例标记为普通只读从库
    • offline 将此实例标记为服务于 offline 服务的特殊只读从库
  • pg_seq:用于在集群内标识实例,一个非负整数
    • 从 0 或 1 开始,按顺序递增分配,一旦分配就不要更改
    • {{ pg_cluster }}-{{ pg_seq }} 用于唯一标识实例,即 pg_instance
    • {{ pg_cluster }}-{{ pg_role }} 用于标识集群内的服务,即 pg_service
  • pg_shardpg_group 用于水平分片集群,仅适用于 citus 和 greenplum

这些身份将在整个系统中使用,例如,指标可能如下所示:

pg_up{cls="pg-test", ins="pg-test-1", ip="10.10.10.11", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-2", ip="10.10.10.12", job="pgsql"}
pg_up{cls="pg-test", ins="pg-test-3", ip="10.10.10.13", job="pgsql"}

分片集群

您可以使用可选的 pg_shardpg_group 参数来标识水平分片集群:

名称 类型 级别 描述
pg_shard string C 集群的 PG 数据库分片名称
pg_group number C 集群的 PG 数据库分片索引

例如,使用 citus、greenplum 或手动分片进行水平分片:

pg-citus:
  hosts:
    10.10.10.10: { pg_group: 0, pg_cluster: pg-citus0 ,pg_seq: 1, pg_role: primary }
    10.10.10.11: { pg_group: 0, pg_cluster: pg-citus0 ,pg_seq: 2, pg_role: replica }
    10.10.10.12: { pg_group: 1, pg_cluster: pg-citus1 ,pg_seq: 1, pg_role: primary }
    10.10.10.13: { pg_group: 2, pg_cluster: pg-citus2 ,pg_seq: 1, pg_role: primary }
  vars:
    pg_mode: citus          # PostgreSQL 集群模式:citus
    pg_shard: pg-citus      # citus 分片名称:pg-citus

命名规范

  • 集群名称应为有效的域名,匹配 [a-zA-Z0-9-]+,且 ≤ 40 字符
  • 服务名称以集群名称为前缀,以单个单词为后缀,用 - 连接
  • 实例名称以集群名称为前缀,以整数为后缀,用 - 连接
  • 节点由其主要 IPv4 地址标识,主机名用作次要标识符
实体 命名示例
集群 pg-metapg-test
服务 pg-meta-primarypg-test-replicapg-test-offlinepg-test-standbypg-meta-default
实例 pg-meta-1pg-test-1pg-test-2pg-test-3
节点 10.10.10.1010.10.10.1110.10.10.1210.10.10.13

版本策略

Pigsty 遵循 PostgreSQL 版本策略 并"官方"支持以下主要版本。

主版本 小版本 注释 扩展 RPM 扩展 DEB
18 18.1 最新稳定版本(推荐 392 390
17 17.7 次要稳定版本(推荐 418 413
16 16.11 2023-09-14 首次发布 420 412
15 15.15 2022-10-13 首次发布 422 414
14 14.20 2021-09-30 首次发布 410 402
13 13.23 2020-09-24 首次发布,即将结束支持 382 371

Pigsty 支持 PG 13 - 18。较低的主版本(12-)“可能"有效,但不保证。 对于遗留 PG 版本支持,请考虑我们的 专业服务

要使用不同的主版本,请配置 pg_version 变量。 可以使用 -v <ver> 选项全局 配置。 只要它们在本地/上游仓库中可用,就不需要进一步更改。

pg-v13:
  hosts: { 10.10.10.13: { pg_seq: 1 ,pg_role: primary } }
  vars:
    pg_cluster: pg-v13
    pg_version: 13

pg-v14:
  hosts: { 10.10.10.14: { pg_seq: 1 ,pg_role: primary } }
  vars:
    pg_cluster: pg-v14
    pg_version: 14

pg-v15:
  hosts: { 10.10.10.15: { pg_seq: 1 ,pg_role: primary } }
  vars:
    pg_cluster: pg-v15
    pg_version: 15

pg-v16:
  hosts: { 10.10.10.16: { pg_seq: 1 ,pg_role: primary } }
  vars:
    pg_cluster: pg-v16
    pg_version: 16

pg-v17:
  hosts: { 10.10.10.17: { pg_seq: 1 ,pg_role: primary } }
  vars:
    pg_cluster: pg-v17
    pg_version: 17

主库

让我们从最简单的情况开始,单例元数据库:

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-test

使用以下命令在 10.10.10.11 节点上创建主数据库实例。

bin/pgsql-add pg-test

从库

要添加物理从库,您可以将新实例分配给 pg-test,并将 pg_role 设置为 replica

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

您可以 创建 整个集群或 添加 从库到现有集群:

bin/pgsql-add pg-test               # 一次性初始化整个集群
bin/pgsql-add pg-test 10.10.10.12   # 向现有集群添加从库

离线库

离线实例是专用从库,用于服务慢查询、ETL、OLAP 流量和交互查询等。

要添加离线实例,分配一个新实例并将 pg_role 设置为 offline

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: offline } # <--- 新添加的
  vars:
    pg_cluster: pg-test

离线实例的工作方式类似于普通从库实例,但它在 pg-test-replica 服务中用作备份服务器。也就是说,只有当所有 replica 实例都宕机时,离线和主实例才会提供服务。

您可以使用 pg_default_hba_rulespg_hba_rules 对离线实例进行临时访问控制。它将应用于离线实例和任何带有 pg_offline_query 标志的实例。


同步从库

Pigsty 默认使用异步流复制,可能有小的复制延迟(10KB / 10ms)。当主库失效时可能出现小的数据丢失窗口(可通过 pg_rpo 控制),但对于大多数场景这是可以接受的。

但在一些关键场景(例如金融交易)中,数据丢失是完全不可接受的,或者需要读写一致性。在这种情况下,您可以启用同步提交来确保这一点。

要启用同步从库模式,您可以在 pg_conf 中简单使用 crit.yml 模板:

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_conf: crit.yml   # <--- 使用 crit 模板

要在现有集群上启用同步从库,配置 集群并启用 synchronous_mode

$ pg edit-config pg-test    # 在管理节点上使用管理员用户运行
+++
-synchronous_mode: false    # <--- 旧值
+synchronous_mode: true     # <--- 新值
 synchronous_mode_strict: false

Apply these changes? [y/N]: y

如果 synchronous_mode: truesynchronous_standby_names 参数将由 patroni 管理。它将从所有可用从库中选择一个同步从库,并将其名称写入主库的配置文件。


法定人数提交

当启用 同步从库 时,PostgreSQL 将选择一个从库作为备用实例,所有其他从库作为候选。主库将等待备用实例刷新到磁盘后再确认提交,备用实例将始终拥有最新数据而没有任何延迟。

但是,您可以通过法定人数提交实现更高/更低的一致性级别(与可用性权衡)。

例如,要让所有 2 个从库确认提交:

synchronous_mode: true          # 确保启用同步模式
synchronous_node_count: 2       # 至少需要 2 个节点确认提交

如果您有更多从库并希望有更多同步从库,请相应增加 synchronous_node_count。注意在您 添加移除 从库时相应调整 synchronous_node_count

postgres synchronous_standby_names 参数将由 patroni 管理:

synchronous_standby_names = '2 ("pg-test-3","pg-test-2")'

经典的法定人数提交是使用大多数从库来确认提交。

synchronous_mode: quorum        # 使用法定人数提交
postgresql:
  parameters:                   # 更改 PostgreSQL 参数 `synchronous_standby_names`,使用 `ANY n ()` 记号
    synchronous_standby_names: 'ANY 1 (*)'  # 您可以指定备用名称列表,或使用 `*` 匹配所有

备用集群

您可以克隆现有集群并创建 备用集群,用于迁移、水平拆分、多可用区部署或灾难恢复。

备用集群的定义与任何其他普通集群相同,除了在主实例上定义了 pg_upstream

例如,您有一个 pg-test 集群,要创建备用集群 pg-test2,配置清单可能如下所示:

# 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 } # <--- 在这里定义 pg_upstream
    10.10.10.13: { pg_seq: 2, pg_role: replica }
  vars: { pg_cluster: pg-test2 }

pg-test2-1pg-test2 的主库将是 pg-test 的从库,并在 pg-test2 中充当备用领导者

只需确保在备份集群的主库上配置了 pg_upstream 参数,以自动从原始上游拉取备份。

bin/pgsql-add pg-test     # 创建原始集群
bin/pgsql-add pg-test2    # 创建备份集群

延迟集群

延迟集群是一种特殊类型的备用集群,用于尽快恢复"意外删除"的数据。

例如,如果您希望有一个集群 pg-testdelay,其数据与 1 天前的 pg-test 集群相同:

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

# pg-testdelay 是 pg-test 的延迟集群
pg-testdelay:
  hosts:
    10.10.10.12: { pg_seq: 1, pg_role: primary , pg_upstream: 10.10.10.11, pg_delay: 1d }
    10.10.10.13: { pg_seq: 2, pg_role: replica }
  vars: { pg_cluster: pg-test2 }

您也可以在现有 备用集群配置 复制延迟。

$ pg edit-config pg-testdelay
 standby_cluster:
   create_replica_methods:
   - basebackup
   host: 10.10.10.11
   port: 5432
+  recovery_min_apply_delay: 1h    # <--- 在这里添加延迟

Apply these changes? [y/N]: y

当某些元组和表被意外删除时,您可以将此延迟集群推进到适当的时间点并从中选择数据。

它需要更多资源,但比 PITR 更快且影响更小。


Citus 集群

Pigsty 有原生 citus 支持。请查看 conf/citus.yml 示例。

要定义 citus 集群,您必须指定以下参数:

此外,需要允许从本地和其他数据节点进行 ssl 访问的额外 hba 规则。可能如下所示:

all:
  children:
    pg-citus0: # citus 数据节点 0
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0 , pg_group: 0 }
    pg-citus1: # citus 数据节点 1
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1 , pg_group: 1 }
    pg-citus2: # citus 数据节点 2
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus2 , pg_group: 2 }
    pg-citus3: # citus 数据节点 3,带有额外从库
      hosts:
        10.10.10.13: { pg_seq: 1, pg_role: primary }
        10.10.10.14: { pg_seq: 2, pg_role: replica }
      vars: { pg_cluster: pg-citus3 , pg_group: 3 }
  vars:                               # 所有 citus 集群的全局参数
    pg_mode: citus                    # PostgreSQL 集群模式:citus
    pg_shard: pg-citus                # citus 分片名称:pg-citus
    patroni_citus_db: meta            # citus 分布式数据库名称
    pg_dbsu_password: DBUser.Postgres # 所有 citus 集群的数据库超级用户密码访问
    pg_users: [ { name: dbuser_meta ,password: DBUser.Meta ,pgbouncer: true ,roles: [ dbrole_admin ] } ]
    pg_databases: [ { name: meta ,extensions: [ { name: citus }, { name: postgis }, { name: timescaledb } ] } ]
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32 ,auth: ssl ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra        ,auth: ssl ,title: 'all user ssl access from intranet'  }

您可以在协调器节点上创建分布式表和引用表。自 citus 11.2 以来,任何数据节点都可以用作协调器节点。

SELECT create_distributed_table('pgbench_accounts', 'aid'); SELECT truncate_local_data_after_distributing_table($$public.pgbench_accounts$$);
SELECT create_reference_table('pgbench_branches')         ; SELECT truncate_local_data_after_distributing_table($$public.pgbench_branches$$);
SELECT create_reference_table('pgbench_history')          ; SELECT truncate_local_data_after_distributing_table($$public.pgbench_history$$);
SELECT create_reference_table('pgbench_tellers')          ; SELECT truncate_local_data_after_distributing_table($$public.pgbench_tellers$$);

3 - 参数

使用 121 个参数定制 PostgreSQL 集群

PGSQL 模块有 121 个参数。

章节 数量 描述
PG_ID 11 计算和检查 Postgres 身份 - 用于识别 PGSQL 实体(如实例和服务)的参数
PG_BUSINESS 12 Postgres 业务对象定义 - 业务用户、数据库、服务和身份验证的配置
PG_INSTALL 10 安装 PGSQL 包和扩展 - 数据库用户设置、版本选择和包安装的设置
PG_BOOTSTRAP 35 使用 Patroni 初始化 HA Postgres 集群 - 包括数据目录、网络和高可用性设置的全面集群初始化
PG_PROVISION 9 创建用户、数据库和数据库内对象 - 引导后的数据库对象置备和默认配置
PG_BACKUP 6 使用 pgbackrest 设置备份仓库 - 使用 pgbackrest 的备份和恢复配置
PG_ACCESS 16 暴露 pg 服务,绑定 VIP 和注册 DNS - 服务暴露、负载均衡、VIP 管理和 DNS 注册
PG_MONITOR 18 为 PGSQL 实例添加监控 - 使用各种导出器进行指标收集的监控设置
PG_REMOVE:删除 Postgres 集群
名称 类型 级别 注释
pg_safeguard bool G/C/A 启用时中止删除,默认为 false
pg_rm_data bool G/C/A 删除 PostgreSQL 数据,默认为 true
pg_rm_backup bool G/C/A 删除主实例的 pgBackRest 备份,默认为 true
pg_rm_pkg bool G/C/A 卸载 PostgreSQL 软件包,默认为 true

PG_ID

以下是一些常用的参数,用于标识 PGSQL 实体:实例、服务等…


pg_mode

参数名称: pg_mode, 类型: enum, 层次:C

pgsql 集群模式,默认为 pgsql,即标准 PostgreSQL 集群。

  • pgsql: 标准 PostgreSQL 集群,默认值。
  • citus: 使用 citus 扩展的水平分片集群。
  • mssql: Babelfish MSSQL 线缆协议兼容内核。
  • ivory: IvorySQL Oracle 兼容内核。
  • polar: PolarDB for PostgreSQL 内核。
  • oracle: PolarDB for Oracle 内核。
  • gpsql: Greenplum / Cloudberry

如果 pg_mode 设置为 citusgpsql,则需要 pg_shardpg_group 用于水平分片集群。


pg_cluster

参数名称: pg_cluster, 类型: string, 层次:C

PostgreSQL 集群名称,必选的身份标识参数,没有默认值

集群名将用作资源的命名空间。

集群命名需要遵循特定的命名模式:[a-z][a-z0-9-]*,即,只使用数字与小写字母,且不以数字开头,以符合标识上的不同约束的要求。


pg_seq

参数名称: pg_seq, 类型: int, 层次:I

PostgreSQL 实例序列号,必选的身份标识参数,无默认值。

此实例的序号,在其集群内是唯一分配的,通常使用自然数,从0或1开始分配,通常不会回收重用。


pg_role

参数名称: pg_role, 类型: enum, 层次:I

pgsql 角色,必需,可以是 primary,replica,offline

PostgreSQL 实例的角色,可以是:primaryreplicastandbyoffline

  • primary: 主库,集群中有且仅有一个。
  • replica: 用于承载在线只读流量的副本,可能会有轻微复制延迟(10ms~100ms, 100KB)。
  • standby: 始终与主库同步的特殊副本,没有复制延迟和数据丢失。(目前与 replica 相同)
  • offline: 用于承接离线只读流量的离线副本,如统计分析/ETL/个人查询等。

身份参数,必需参数,实例级参数。


pg_instances

参数名称: pg_instances, 类型: dict, 层次:I

使用 {port:ins_vars} 的形式在一台主机上定义多个 PostgreSQL 实例。

此参数是为在单个节点上的多实例部署保留的参数,Pigsty 尚未实现此功能,并强烈建议独占节点部署。


pg_upstream

参数名称: pg_upstream, 类型: ip, 层次:I

备份集群或级联从库的上游实例 IP 地址。

在集群的 primary 实例上设置 pg_upstream ,表示此集群是一个备份集群,该实例将作为 standby leader,从上游集群接收并应用更改。

对非 primary 实例设置 pg_upstream 参数将指定一个具体实例作为物理复制的上游,如果与主实例 ip 地址不同,此实例将成为 级联副本 。确保上游 IP 地址是同一集群中的另一个实例是用户的责任。


pg_shard

参数名称: pg_shard, 类型: string, 层次:C

PostgreSQL 水平分片名称,对于分片集群来说(例如 citus 集群),这是的必选标识参数。

当多个标准的 PostgreSQL 集群一起以水平分片方式为同一业务提供服务时,Pigsty 将此组集群标记为 水平分片集群

pg_shard 是分片组名称。它通常是 pg_cluster 的前缀。

例如,如果我们有一个分片组 pg-citus,并且其中有4个集群,它们的标识参数将是:

cls pg_shard: pg-citus
cls pg_group = 0:   pg-citus0
cls pg_group = 1:   pg-citus1
cls pg_group = 2:   pg-citus2
cls pg_group = 3:   pg-citus3

pg_group

参数名称: pg_group, 类型: int, 层次:C

PostgreSQL 水平分片集群的分片索引号,对于分片集群来说(例如 citus 集群),这是的必选标识参数。

此参数与 pg_shard 配对使用,通常可以使用非负整数作为索引号。


gp_role

参数名称: gp_role, 类型: enum, 层次:C

PostgreSQL 集群的 Greenplum/Matrixdb 角色,可以是 mastersegment

  • master: 标记 postgres 集群为 greenplum 主实例(协调节点),这是默认值。
  • segment 标记 postgres 集群为 greenplum 段集群(数据节点)。

此参数仅用于 Greenplum/MatrixDB 数据库 (pg_modegpsql),对于普通的 PostgreSQL 集群没有意义。


pg_exporters

参数名称: pg_exporters, 类型: dict, 层次:C

额外用于监控远程 PostgreSQL 实例的 Exporter 定义,默认值:{}

如果您希望监控远程 PostgreSQL 实例,请在监控系统所在节点(Infra节点)集群上的 pg_exporters 参数中定义它们,并使用 pgsql-monitor.yml 剧本来完成部署。

pg_exporters: # list all remote instances here, alloc a unique unused local port as k
    20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 }
    20004: { pg_cluster: pg-foo, pg_seq: 2, pg_host: 10.10.10.11 }
    20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.12 }
    20003: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.13 }

pg_offline_query

参数名称: pg_offline_query, 类型: bool, 层次:I

设置为 true 以在此实例上启用离线查询,默认为 false

当某个 PostgreSQL 实例启用此参数时, 属于 dbrole_offline 分组的用户可以直接连接到该 PostgreSQL 实例上执行离线查询(慢查询,交互式查询,ETL/分析类查询)。

带有此标记的实例在效果上类似于为实例设置 pg_role = offline ,唯一的区别在于 offline 实例默认不会承载 replica 服务的请求,是作为专用的离线/分析从库实例而存在的。

如果您没有富余的实例可以专门用于此目的,则可以挑选一台普通的从库,在实例层次启用此参数,以便在需要时承载离线查询。


PG_BUSINESS

定制集群模板:用户,数据库,服务,权限规则。

用户需重点关注此部分参数,因为这里是业务声明自己所需数据库对象的地方。

默认的数据库用户及其凭据,强烈建议在生产环境中修改这些用户的密码。

# postgres business object definition, overwrite in group vars
pg_users: []                      # postgres business users
pg_databases: []                  # postgres business databases
pg_services: []                   # postgres business services
pg_hba_rules: []                  # business hba rules for postgres
pgb_hba_rules: []                 # business hba rules for pgbouncer
# global credentials, overwrite in global vars
pg_dbsu_password: ''              # dbsu password, empty string means no dbsu password by default
pg_replication_username: replicator
pg_replication_password: DBUser.Replicator
pg_admin_username: dbuser_dba
pg_admin_password: DBUser.DBA
pg_monitor_username: dbuser_monitor
pg_monitor_password: DBUser.Monitor

pg_users

参数名称: pg_users, 类型: user[], 层次:C

PostgreSQL 业务用户列表,需要在 PG 集群层面进行定义。默认值为:[] 空列表。

每一个数组元素都是一个 用户/角色 定义,例如:

- name: dbuser_meta               # 必需,`name` 是用户定义的唯一必选字段
  password: DBUser.Meta           # 可选,密码,可以是 scram-sha-256 哈希字符串或明文
  login: true                     # 可选,默认情况下可以登录
  superuser: false                # 可选,默认为 false,是超级用户吗?
  createdb: false                 # 可选,默认为 false,可以创建数据库吗?
  createrole: false               # 可选,默认为 false,可以创建角色吗?
  inherit: true                   # 可选,默认情况下,此角色可以使用继承的权限吗?
  replication: false              # 可选,默认为 false,此角色可以进行复制吗?
  bypassrls: false                # 可选,默认为 false,此角色可以绕过行级安全吗?
  pgbouncer: true                 # 可选,默认为 false,将此用户添加到 pgbouncer 用户列表吗?(使用连接池的生产用户应该显式定义为 true)
  connlimit: -1                   # 可选,用户连接限制,默认 -1 禁用限制
  expire_in: 3650                 # 可选,此角色过期时间:从创建时 + n天计算(优先级比 expire_at 更高)
  expire_at: '2030-12-31'         # 可选,此角色过期的时间点,使用 YYYY-MM-DD 格式的字符串指定一个特定日期(优先级没 expire_in 高)
  comment: pigsty admin user      # 可选,此用户/角色的说明与备注字符串
  roles: [dbrole_admin]           # 可选,默认角色为:dbrole_{admin,readonly,readwrite,offline}
  parameters: {}                  # 可选,使用 `ALTER ROLE SET` 针对这个角色,配置角色级的数据库参数
  pool_mode: transaction          # 可选,默认为 transaction 的 pgbouncer 池模式,用户级别
  pool_connlimit: -1              # 可选,用户级别的最大数据库连接数,默认 -1 禁用限制
  search_path: public             # 可选,根据 postgresql 文档的键值配置参数(例如:使用 pigsty 作为默认 search_path)

pg_databases

参数名称: pg_databases, 类型: database[], 层次:C

PostgreSQL 业务数据库列表,需要在 PG 集群层面进行定义。默认值为:[] 空列表。

每一个数组元素都是一个 业务数据库 定义,例如:

- name: meta                      # 必选,`name` 是数据库定义的唯一必选字段
  baseline: cmdb.sql              # 可选,数据库 sql 的基线定义文件路径(ansible 搜索路径中的相对路径,如 files/)
  pgbouncer: true                 # 可选,是否将此数据库添加到 pgbouncer 数据库列表?默认为 true
  schemas: [pigsty]               # 可选,要创建的附加模式,由模式名称字符串组成的数组
  extensions:                     # 可选,要安装的附加扩展: 扩展对象的数组
    - { name: postgis , schema: public }  # 可以指定将扩展安装到某个模式中,也可以不指定(不指定则安装到 search_path 首位模式中)
    - { name: timescaledb }               # 例如有的扩展会创建并使用固定的模式,就不需要指定模式。
    - vector                              # 你也可以直接使用字符串指定扩展名称
  comment: pigsty meta database   # 可选,数据库的说明与备注信息
  owner: postgres                 # 可选,数据库所有者,默认为 postgres
  template: template1             # 可选,要使用的模板,默认为 template1,目标必须是一个模板数据库
  encoding: UTF8                  # 可选,数据库编码,默认为 UTF8(必须与模板数据库相同)
  locale: C                       # 可选,数据库地区设置,默认为 C(必须与模板数据库相同)
  lc_collate: C                   # 可选,数据库 collate 排序规则,默认为 C(必须与模板数据库相同),没有理由不建议更改。
  lc_ctype: C                     # 可选,数据库 ctype 字符集,默认为 C(必须与模板数据库相同)
  tablespace: pg_default          # 可选,默认表空间,默认为 'pg_default'
  allowconn: true                 # 可选,是否允许连接,默认为 true。显式设置 false 将完全禁止连接到此数据库
  revokeconn: false               # 可选,撤销公共连接权限。默认为 false,设置为 true 时,属主和管理员之外用户的 CONNECT 权限会被回收
  register_datasource: true       # 可选,是否将此数据库注册到 grafana 数据源?默认为 true,显式设置为 false 会跳过注册
  connlimit: -1                   # 可选,数据库连接限制,默认为 -1 ,不限制,设置为正整数则会限制连接数。
  pool_auth_user: dbuser_meta     # 可选,连接到此 pgbouncer 数据库的所有连接都将使用此用户进行验证(启用 pgbouncer_auth_query 才有用)
  pool_mode: transaction          # 可选,数据库级别的 pgbouncer 池化模式,默认为 transaction
  pool_size: 64                   # 可选,数据库级别的 pgbouncer 默认池子大小,默认为 64
  pool_size_reserve: 32           # 可选,数据库级别的 pgbouncer 池子保留空间,默认为 32,当默认池子不够用时,最多再申请这么多条突发连接。
  pool_size_min: 0                # 可选,数据库级别的 pgbouncer 池的最小大小,默认为 0
  pool_max_db_conn: 100           # 可选,数据库级别的最大数据库连接数,默认为 100

在每个数据库定义对象中,只有 name 是必选字段,其他的字段都是可选项。


pg_services

参数名称: pg_services, 类型: service[], 层次:C

PostgreSQL 服务列表,需要在 PG 集群层面进行定义。默认值为:[] ,空列表。

用于在数据库集群层面定义额外的服务,数组中的每一个对象定义了一个服务,一个完整的服务定义样例如下:

- name: standby                   # 必选,服务名称,最终的 svc 名称会使用 `pg_cluster` 作为前缀,例如:pg-meta-standby
  port: 5435                      # 必选,暴露的服务端口(作为 kubernetes 服务节点端口模式)
  ip: "*"                         # 可选,服务绑定的 IP 地址,默认情况下为所有 IP 地址
  selector: "[]"                  # 必选,服务成员选择器,使用 JMESPath 来筛选配置清单
  backup: "[? pg_role == `primary`]"  # 可选,服务成员选择器(备份),也就是当默认选择器选中的实例都宕机后,服务才会由这里选中的实例成员来承载
  dest: default                   # 可选,目标端口,default|postgres|pgbouncer|<port_number>,默认为 'default',Default的意思就是使用 pg_default_service_dest 的取值来最终决定
  check: /sync                    # 可选,健康检查 URL 路径,默认为 /,这里使用 Patroni API:/sync ,只有同步备库和主库才会返回 200 健康状态码
  maxconn: 5000                   # 可选,允许的前端连接最大数,默认为5000
  balance: roundrobin             # 可选,haproxy 负载均衡算法(默认为 roundrobin,其他选项:leastconn)
  options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

请注意,本参数用于在集群层面添加额外的服务。如果您想在全局定义所有 PostgreSQL 数据库都要提供的服务,可以使用 pg_default_services 参数。


pg_hba_rules

参数名称: pg_hba_rules, 类型: hba[], 层次:C

数据库集群/实例的客户端IP黑白名单规则。默认为:[] 空列表。

对象数组,每一个对象都代表一条规则, hba 规则对象的定义形式如下:

- title: allow intranet password access
  role: common
  rules:
    - host   all  all  10.0.0.0/8      md5
    - host   all  all  172.16.0.0/12   md5
    - host   all  all  192.168.0.0/16  md5
  • title: 规则的标题名称,会被渲染为 HBA 文件中的注释。
  • rules:规则数组,每个元素是一条标准的 HBA 规则字符串。
  • role :规则的应用范围,哪些实例角色会启用这条规则?
  • common:对于所有实例生效
  • primary, replica,offline: 只针对特定的角色 pg_role 实例生效。
  • 特例:role: 'offline' 的规则除了会应用在 pg_role : offline 的实例上,对于带有 pg_offline_query 标记的实例也生效。

除了上面这种原生 HBA 规则定义形式,Pigsty 还提供了另外一种更为简便的别名形式:

- addr: 'intra'    # world|intra|infra|admin|local|localhost|cluster|<cidr>
  auth: 'pwd'      # trust|pwd|ssl|cert|deny|<official auth method>
  user: 'all'      # all|${dbsu}|${repl}|${admin}|${monitor}|<user>|<group>
  db: 'all'        # all|replication|....
  rules: []        # raw hba string precedence over above all
  title: allow intranet password access

pg_default_hba_rules 与本参数基本类似,但它是用于定义全局的 HBA 规则,而本参数通常用于定制某个集群/实例的 HBA 规则。


pgb_hba_rules

参数名称: pgb_hba_rules, 类型: hba[], 层次:C

Pgbouncer 业务HBA规则,默认值为: [], 空数组。

此参数与 pg_hba_rules 基本类似,都是 hba 规则对象的数组,区别在于本参数是为 Pgbouncer 准备的。

pgb_default_hba_rules 与本参数基本类似,但它是用于定义全局连接池 HBA 规则,而本参数通常用于定制某个连接池集群/实例的 HBA 规则。


pg_replication_username

参数名称: pg_replication_username, 类型: username, 层次:G

PostgreSQL 物理复制用户名,默认使用 replicator,不建议修改此参数。


pg_replication_password

参数名称: pg_replication_password, 类型: password, 层次:G

PostgreSQL 物理复制用户密码,默认值为:DBUser.Replicator

警告:请在生产环境中修改此密码!


pg_admin_username

参数名称: pg_admin_username, 类型: username, 层次:G

PostgreSQL / Pgbouncer 管理员名称,默认为:dbuser_dba

这是全局使用的数据库管理员,具有数据库的 Superuser 权限与连接池的流量管理权限,请务必控制使用范围。


pg_admin_password

参数名称: pg_admin_password, 类型: password, 层次:G

PostgreSQL / Pgbouncer 管理员密码,默认为: DBUser.DBA

警告:请在生产环境中修改此密码!


pg_monitor_username

参数名称: pg_monitor_username, 类型: username, 层次:G

PostgreSQL/Pgbouncer 监控用户名,默认为:dbuser_monitor

这是一个用于监控的数据库/连接池用户,不建议修改此用户名。

但如果您的现有数据库使用了不同的监控用户,可以在指定监控目标时使用此参数传入使用的监控用户名。


pg_monitor_password

参数名称: pg_monitor_password, 类型: password, 层次:G

PostgreSQL/Pgbouncer 监控用户使用的密码,默认为:DBUser.Monitor

请尽可能不要在密码中使用 @:/ 这些容易与 URL 分隔符混淆的字符,减少不必要的麻烦。

警告:请在生产环境中修改此密码!


pg_dbsu_password

参数名称: pg_dbsu_password, 类型: password, 层次:G/C

PostgreSQL pg_dbsu 超级用户密码,默认是空字符串,即不为其设置密码。

我们不建议为 dbsu 配置密码登陆,这会增大攻击面。例外情况是:pg_mode = citus,这时候需要为每个分片集群的 dbsu 配置密码,以便在分片集群内部进行连接。


PG_INSTALL

本节负责安装 PostgreSQL 及其扩展。如果您希望安装不同大版本与扩展插件,修改 pg_versionpg_extensions 即可,不过请注意,并不是所有扩展都在所有大版本可用。

pg_dbsu: postgres                 # os 数据库超级用户名称,默认为 postgres,最好不要更改
pg_dbsu_uid: 26                   # os 数据库超级用户 uid 和 gid,默认为 26,适用于默认的 postgres 用户和组
pg_dbsu_sudo: limit               # 数据库超级用户 sudo 权限,可选 none,limit,all,nopass。默认为 limit
pg_dbsu_home: /var/lib/pgsql      # postgresql 主目录,默认为 `/var/lib/pgsql`
pg_dbsu_ssh_exchange: true        # 是否在相同的 pgsql 集群中交换 postgres 数据库超级用户的 ssh 密钥
pg_version: 18                    # 要安装的 postgres 主版本,默认为 18
pg_bin_dir: /usr/pgsql/bin        # postgres 二进制目录,默认为 `/usr/pgsql/bin`
pg_log_dir: /pg/log/postgres      # postgres 日志目录,默认为 `/pg/log/postgres`
pg_packages:                      # 待安装的软件包列表,可以使用别名
  - pgsql-main pgsql-common
pg_extensions: []                 # 待安装的扩展列表,可以使用别名

pg_dbsu

参数名称: pg_dbsu, 类型: username, 层次:C

PostgreSQL 使用的操作系统 dbsu 用户名, 默认为 postgres,改这个用户名是不太明智的。

不过在特定情况下,您可能会使用到不同于 postgres 的用户名,例如在安装配置 Greenplum / MatrixDB 时,需要使用 gpadmin / mxadmin 作为相应的操作系统超级用户。


pg_dbsu_uid

参数名称: pg_dbsu_uid, 类型: int, 层次:C

操作系统数据库超级用户的 uid 和 gid,26 是 PGDG RPM 默认的 postgres 用户 UID/GID。

对于 Debian/Ubuntu 系统,没有默认值,且 26 号用户经常被占用。因此Pigsty 在检测到安装环境为 Debian 系,且 uid 为 26 时,会自动使用替换的 pg_dbsu_uid = 543


pg_dbsu_sudo

参数名称: pg_dbsu_sudo, 类型: enum, 层次:C

数据库超级用户的 sudo 权限,可以是 nonelimitallnopass。默认为 limit

  • none: 无 Sudo 权限
  • limit: 有限的 sudo 权限,用于执行与数据库相关的组件的 systemctl 命令(默认选项)。
  • all: 完全的 sudo 权限,需要密码。
  • nopass: 不需要密码的完全 sudo 权限(不推荐)。
  • 默认值为 limit,只允许执行 sudo systemctl <start|stop|reload> <postgres|patroni|pgbouncer|...>

可以使用 sudo 管理的服务列表:

  • patroni
  • pgbouncer
  • postgres
  • pg_exporter
  • pgbackrest
  • pgbouncer_exporter
  • pgbackrest_exporter
  • vip-manager
  • haproxy (仅限reload)

pg_dbsu_home

参数名称: pg_dbsu_home, 类型: path, 层次:C

postgresql 主目录,默认为 /var/lib/pgsql,与官方的 pgdg RPM 保持一致。


pg_dbsu_ssh_exchange

参数名称: pg_dbsu_ssh_exchange, 类型: bool, 层次:C

是否在交换操作系统 dbsu 用户的 ssh 密钥?

默认值为 true,意味着数据库超级用户可以互相 ssh 访问。

对于严格限制 ssh 访问的场景,您可以将其设置为 false

请注意,SSH 密钥交换发生在同时执行剧本的实例之间,如果您针对一个 PostgreSQL 集群运行 pgsql 角色,密钥交换将发生在这个集群中的所有实例之间。 如果您针对所有 PostgreSQL 集群运行 pgsql 角色,密钥交换将发生在 所有 实例之间,对于大规模集群,O(n2) 复杂度交换可能导致严重的组合爆炸。 如果任何参与交换的实例没有 pg_dbsu 用户,与该实例相关的密钥交换将失败,但不影响其他实例的密钥交换。


pg_version

参数名称: pg_version, 类型: enum, 层次:C

要安装的 postgres 主版本,默认为 18

请注意,PostgreSQL 的物理流复制不能跨主要版本,因此最好不要在实例级别上配置此项。

您可以使用 pg_packagespg_extensions 中的参数来为特定的 PG 大版本安装不同的软件包与扩展。


pg_bin_dir

参数名称: pg_bin_dir, 类型: path, 层次:C

PostgreSQL 二进制程序目录,默认为 /usr/pgsql/bin

默认值是在安装过程中手动创建的软链接,指向安装的特定的 Postgres 版本目录。

例如 /usr/pgsql -> /usr/pgsql-17。在 Ubuntu/Debian 上则指向 /usr/lib/postgresql/15/bin

更多详细信息,请查看 PGSQL 文件结构


pg_log_dir

参数名称: pg_log_dir, 类型: path, 层次:C

PostgreSQL 日志目录,默认为:/pg/log/postgresPromtail 会使用此变量收集 PostgreSQL 日志。

请注意,如果日志目录 pg_log_dir 以数据库目录 pg_data 作为前缀,则不会显式创建(数据库目录初始化时自动创建)。


pg_packages

参数名称: pg_packages, 类型: string[], 层次:C

要安装的 PostgreSQL 软件包(rpm/deb),这是一个由软件包名组成的数组,每个元素都是逗号或空格分割的 PG 软件包名或别名(Alias)。

默认值为:[ pgsql-main pgsql-common ]

这里的默认值是两个别名,分通过 别名翻译 为当前 PG 大版本对应的主要 RPM/DEB 包名,以及 PG 版本无关的通用组件(例如 Patroni,PgBackrest 等)

从 Pigsty v3 开始,您可以在本参数中使用roles/node_id/vars 中系统对应配置指定的别名列表。

使用包别名的好处是,您无需操心 PostgreSQL 相关软件包在不同系统平台上的包名,架构,以及大版本号,从而屏蔽了不同 OS 之间的区别:

定义在这里的软件包会首先经过 package_map 的翻译,然后经过 PG 大版本号的替换,最后安装实际的 RPM/DEB 包。

您也可以直接指定最终安装的 RPM/DEB 包名称,包名中的 ${pg_version}$v 版本号占位符将被替换为具体的大版本号 pg_version


pg_extensions

参数名称: pg_extensions, 类型: string[], 层次:G/C

要安装的 PostgreSQL 扩展包(rpm/deb),这是一个由扩展包名组成的数组,每个元素都是逗号或空格分割的 PG 扩展包名。

本参数在形式上与 pg_packages 一致,但是通常用于指定需要安装的扩展插件,而且在这里指定的软件包会升级到可用的最新版本。

pg_extensions: []

完整可用的扩展列表,已经在 Pigsty 默认生成的配置文件中给出,用户按需使用即可。

完整列表请参考:roles/node_id/vars 与 Pigsty 扩展目录


PG_BOOTSTRAP

使用 Patroni 引导拉起 PostgreSQL 集群,并设置 1:1 对应的 Pgbouncer 连接池。

它还会使用 PG_PROVISION 中定义的默认角色、用户、权限、模式、扩展来初始化数据库集群

pg_data: /pg/data                 # postgres 数据目录,默认值为 `/pg/data`
pg_fs_main: /data/postgres        # postgres 主数据盘挂载点/路径,默认值为 `/data/postgres`
pg_fs_bkup: /data/backups         # postgres 备份数据盘挂载点/路径,默认值为 `/data/backups`
pg_storage_type: SSD              # postgres 主数据盘存储介质类型,默认值为 `SSD`
pg_dummy_filesize: 64MiB          # 紧急情况下占位符文件 `/pg/dummy` 的大小,默认值为 `64MiB`
pg_listen: '0.0.0.0'              # postgres/pgbouncer 监听地址,默认值为 `0.0.0.0`
pg_port: 5432                     # postgres 监听端口,默认值为 `5432`
pg_localhost: /var/run/postgresql # postgres 本地连接的 Unix 套接字目录,默认值为 `/var/run/postgresql`
patroni_enabled: true             # 如果禁用,在初始化期间将不会创建 postgres 集群
patroni_mode: default             # patroni 工作模式:default,pause,remove
pg_namespace: /pg                 # etcd 中的顶级键命名空间,由 patroni 和 vip 使用
patroni_port: 8008                # patroni 监听端口,默认为 8008
patroni_log_dir: /pg/log/patroni  # patroni 日志目录,默认为 `/pg/log/patroni`
patroni_ssl_enabled: false        # 是否使用 SSL 保护 patroni RestAPI 通信?
patroni_watchdog_mode: off        # patroni 看门狗模式:automatic,required,off。默认为 off
patroni_username: postgres        # patroni restapi 用户名,默认为 `postgres`
patroni_password: Patroni.API     # patroni restapi 密码,默认为 `Patroni.API`
pg_primary_db: postgres           # 主数据库名称,用于 citus 等,默认为 postgres
pg_parameters: {}                 # postgresql.auto.conf 中的额外参数
pg_files: []                      # 要复制到 postgres 数据目录的额外文件(例如许可证)
pg_conf: oltp.yml                 # 配置模板:oltp,olap,crit,tiny。默认为 `oltp.yml`
pg_max_conn: auto                 # postgres 最大连接数,`auto` 将使用推荐值
pg_shared_buffer_ratio: 0.25      # postgres 共享缓冲区比例,默认为 0.25,范围 0.1~0.4
pg_rto: 30                        # 恢复时间目标(秒),默认为 `30s`
pg_rpo: 1048576                   # 恢复点目标(字节),默认最多 `1MiB`
pg_libs: 'pg_stat_statements, auto_explain'  # 预加载库,默认为 `pg_stat_statements,auto_explain`
pg_delay: 0                       # 备用集群领导者的复制应用延迟
pg_checksum: true                 # 为 postgres 集群启用数据校验和?
pg_pwd_enc: scram-sha-256         # 密码加密算法:md5,scram-sha-256
pg_encoding: UTF8                 # 数据库集群编码,默认为 `UTF8`
pg_locale: C                      # 数据库集群区域设置,默认为 `C`
pg_lc_collate: C                  # 数据库集群排序规则,默认为 `C`
pg_lc_ctype: C                    # 数据库字符类型,默认为 `C`
#pgsodium_key: ""                 # pgsodium key, 64 hex digits, default to sha256(pg_cluster)
#pgsodium_getkey_script: ""       # pgsodium getkey script path, pgsodium_getkey by default

pg_data

参数名称: pg_data, 类型: path, 层次:C

Postgres 数据目录,默认为 /pg/data

这是一个指向底层实际数据目录的符号链接,在多处被使用,请不要修改它。参阅 PGSQL文件结构 获取详细信息。


pg_fs_main

参数名称: pg_fs_main, 类型: path, 层次:C

PostgreSQL 主数据盘的挂载点/文件系统路径,默认为/data/postgres

默认值:/data/postgres,它将被用作 PostgreSQL 主数据目录。

建议使用 NVME SSD 作为 PostgreSQL 主数据存储,Pigsty默认为SSD存储进行了优化,但是也支持HDD。

您可以更改pg_storage_typeHDD以针对HDD存储进行优化。


pg_fs_bkup

参数名称: pg_fs_bkup, 类型: path, 层次:C

PostgreSQL 备份数据盘的挂载点/文件系统路径,默认为/data/backup

如果您使用的是默认的 pgbackrest_method = local,建议为备份存储使用一个单独的磁盘。

备份磁盘应足够大,以容纳所有的备份,至少足以容纳3个基础备份+2天的WAL归档。 通常容量不是什么大问题,因为您可以使用便宜且大的机械硬盘作为备份盘。

建议为备份存储使用一个单独的磁盘,否则 Pigsty 将回退到主数据磁盘,并占用主数据盘的容量与IO。


pg_storage_type

参数名称: pg_storage_type, 类型: enum, 层次:C

PostgreSQL 数据存储介质的类型:SSDHDD,默认为SSD

默认值:SSD,它会影响一些调优参数,如 random_page_costeffective_io_concurrency


pg_dummy_filesize

参数名称: pg_dummy_filesize, 类型: size, 层次:C

/pg/dummy的大小,默认值为64MiB,用于紧急使用的64MB磁盘空间。

当磁盘已满时,删除占位符文件可以为紧急使用释放一些空间,建议生产使用至少8GiB


pg_listen

参数名称: pg_listen, 类型: ip, 层次:C

PostgreSQL / Pgbouncer 的监听地址,默认为0.0.0.0(所有ipv4地址)。

您可以在此变量中使用占位符,例如:'${ip},${lo}''${ip},${vip},${lo}'

  • ${ip}:转换为 inventory_hostname,它是配置清单中定义的首要内网IP地址。
  • ${vip}:如果启用了pg_vip_enabled,将使用pg_vip_address的主机部分。
  • ${lo}:将替换为127.0.0.1

对于高安全性要求的生产环境,建议限制监听的IP地址。


pg_port

参数名称: pg_port, 类型: port, 层次:C

PostgreSQL 服务器监听的端口,默认为 5432


pg_localhost

参数名称: pg_localhost, 类型: path, 层次:C

本地主机连接 PostgreSQL 使用的 Unix套接字目录,默认值为/var/run/postgresql

PostgreSQL 和 Pgbouncer 本地连接的Unix套接字目录,pg_exporter 和 patroni 都会优先使用 Unix 套接字访问 PostgreSQL。


pg_namespace

参数名称: pg_namespace, 类型: path, 层次:C

etcd 中使用的顶级命名空间,由 patroni 和 vip-manager 使用,默认值是:/pg,不建议更改。


patroni_enabled

参数名称: patroni_enabled, 类型: bool, 层次:C

是否启用 Patroni ?默认值为:true

如果禁用,则在初始化期间不会创建Postgres集群。Pigsty将跳过拉起 patroni的任务,当试图向现有的postgres实例添加一些组件时,可以使用此参数。


patroni_mode

参数名称: patroni_mode, 类型: enum, 层次:C

Patroni 工作模式:defaultpauseremove。默认值:default

  • default:正常使用 Patroni 引导 PostgreSQL 集群
  • pause:与default相似,但在引导后进入维护模式
  • remove:使用Patroni初始化集群,然后删除Patroni并使用原始 PostgreSQL。

patroni_port

参数名称: patroni_port, 类型: port, 层次:C

patroni监听端口,默认为8008,不建议更改。

Patroni API服务器在此端口上监听健康检查和API请求。


patroni_log_dir

参数名称: patroni_log_dir, 类型: path, 层次:C

patroni日志目录,默认为/pg/log/patroni,由promtail收集。


patroni_ssl_enabled

参数名称: patroni_ssl_enabled, 类型: bool, 层次:G

使用SSL保护patroni RestAPI通信吗?默认值为false

此参数是一个全局标志,只能在部署之前预先设置。因为如果为 patroni 启用了SSL,您将必须使用 HTTPS 而不是 HTTP 执行健康检查、获取指标,调用API。


patroni_watchdog_mode

参数名称: patroni_watchdog_mode, 类型: string, 层次:C

patroni看门狗模式:automaticrequiredoff,默认值为 off

在主库故障的情况下,Patroni 可以使用看门狗 来强制关机旧主库节点以避免脑裂。

  • off:不使用看门狗。完全不进行 Fencing (默认行为)
  • automatic:如果内核启用了softdog模块并且看门狗属于dbsu,则启用 watchdog
  • required:强制启用 watchdog,如果softdog不可用则拒绝启动 Patroni/PostgreSQL。

默认值为off,您不应该在 Infra节点 启用看门狗,数据一致性优先于可用性的关键系统,特别是与钱有关的业务集群可以考虑打开此选项。

请注意,如果您的所有访问流量都使用 HAproxy 健康检查服务接入,正常是不存在脑裂风险的。


patroni_username

参数名称: patroni_username, 类型: username, 层次:C

Patroni REST API 用户名,默认为postgres,与patroni_password 配对使用。

Patroni的危险 REST API (比如重启集群)由额外的用户名/密码保护,查看配置集群Patroni RESTAPI以获取详细信息。


patroni_password

参数名称: patroni_password, 类型: password, 层次:C

Patroni REST API 密码,默认为Patroni.API

警告:务必生产环境中修改此参数!


pg_primary_db

参数名称: pg_primary_db, 类型: string, 层次:C

指定集群中的主数据库名称,用于 citus 等业务数据库,默认为 postgres

例如,在使用 Patroni 管理高可用的 Citus 集群时,您必须选择一个 “主数据库”。

此外,在这里指定的数据库名称,将在 PGSQL 模块安装完成后,显示在打印的连接串中。


pg_parameters

参数名称: pg_parameters, 类型: dict, 层次:G/C/I

可用于指定并管理 postgresql.auto.conf 中的配置参数。

当集群所有实例完成初始化后,pg_param 任务将会把本字典中的 key / value 键值对依次覆盖写入 /pg/data/postgresql.auto.conf 中。

注意:请不要手工修改该配置文件,或通过 ALTER SYSTEM 修改集群配置参数,修改会在下一次配置同步时被覆盖。

该变量的优先级大于 Patroni / DCS 中的集群配置(即优先级高于集群配置,由 Patroni edit-config 编辑的配置),因此通常可以在实例级别覆盖集群默认参数。

当您的集群成员有着不同的规格(不推荐的行为!)时,您可以通过本参数对每个实例的配置进行精细化管理。

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary , pg_parameters: { shared_buffers: '5GB' } }
    10.10.10.12: { pg_seq: 2, pg_role: replica , pg_parameters: { shared_buffers: '4GB' } }
    10.10.10.13: { pg_seq: 3, pg_role: replica , pg_parameters: { shared_buffers: '3GB' } }

请注意,一些 重要的集群参数(对主从库参数值有要求)是 Patroni 直接通过命令行参数管理的,具有最高优先级,无法通过此方式覆盖,对于这些参数,您必须使用 Patroni edit-config 进行管理与配置。

在主从上必须保持一致的 PostgreSQL 参数(不一致会导致从库无法启动!):

  • wal_level
  • max_connections
  • max_locks_per_transaction
  • max_worker_processes
  • max_prepared_transactions
  • track_commit_timestamp

在主从上最好保持一致的参数(考虑到主从切换的可能性):

  • listen_addresses
  • port
  • cluster_name
  • hot_standby
  • wal_log_hints
  • max_wal_senders
  • max_replication_slots
  • wal_keep_segments
  • wal_keep_size

您可以设置不存在的参数(例如来自扩展的 GUC,从而配置 ALTER SYSTEM 无法修改的“尚未存在”的参数),但将现有配置修改为非法值可能会导致 PostgreSQL 无法启动,请谨慎配置!


pg_files

参数名称: pg_files, 类型: path[], 层次:C

用于指定需要拷贝至PGDATA目录的文件列表,默认为空数组:[]

在本参数中指定的文件将会被拷贝至 {{ pg_data }} 目录下,这主要用于下发特殊商业版本 PostgreSQL 内核要求的 License 文件。

目前仅有 PolarDB (Oracle兼容)内核需要许可证文件,例如,您可以将 license.lic 文件放置在 files/ 目录下,并在 pg_files 中指定:

pg_files: [ license.lic ]

pg_conf

参数名称: pg_conf, 类型: enum, 层次:C

配置模板:{oltp,olap,crit,tiny}.yml,默认为oltp.yml

  • tiny.yml:为小节点、虚拟机、小型演示优化(1-8核,1-16GB)
  • oltp.yml:为OLTP工作负载和延迟敏感应用优化(4C8GB+)(默认模板)
  • olap.yml:为OLAP工作负载和吞吐量优化(4C8G+)
  • crit.yml:为数据一致性和关键应用优化(4C8G+)

默认值:oltp.yml,但是配置程序将在当前节点为小节点时将此值设置为 tiny.yml

您可以拥有自己的模板,只需将其放在templates/<mode>.yml下,并将此值设置为模板名称即可使用。


pg_max_conn

参数名称: pg_max_conn, 类型: int, 层次:C

PostgreSQL 服务器最大连接数。你可以选择一个介于 50 到 5000 之间的值,或使用 auto 选择推荐值。

默认值为 auto,会根据 pg_confpg_default_service_dest 来设定最大连接数。

  • tiny: 250
  • olap: 500
  • crit: 500 (pgbouncer) / 1000 (postgres)
  • oltp: 500 (pgbouncer) / 1000 (postgres)

不建议将此值设定为超过 5000,否则你还需要手动增加 haproxy 服务的连接限制。

Pgbouncer 的事务池可以缓解过多的 OLTP 连接问题,因此默认情况下不建议设置很大的连接数。

对于 OLAP 场景, pg_default_service_dest 修改为 postgres 可以绕过连接池。


pg_shared_buffer_ratio

参数名称: pg_shared_buffer_ratio, 类型: float, 层次:C

Postgres 共享缓冲区内存比例,默认为 0.25,正常范围在 0.1~0.4 之间。

默认值:0.25,意味着节点内存的 25% 将被用作 PostgreSQL 的分片缓冲区。如果您想为 PostgreSQL 启用大页,那么此参数值应当适当小于 node_hugepage_ratio

将此值设定为大于 0.4(40%)通常不是好主意,但在极端情况下可能有用。

注意,共享缓冲区只是 PostgreSQL 中共享内存的一部分,要计算总共享内存,使用 show shared_memory_size_in_huge_pages;


pg_rto

参数名称: pg_rto, 类型: int, 层次:C

以秒为单位的恢复时间目标(RTO)。这将用于计算 Patroni 的 TTL 值,默认为 30 秒。

如果主实例在这么长时间内失踪,将触发新的领导者选举,此值并非越低越好,它涉及到利弊权衡:

减小这个值可以减少集群故障转移期间的不可用时间(无法写入), 但会使集群对短期网络抖动更加敏感,从而增加误报触发故障转移的几率。

您需要根据网络状况和业务约束来配置这个值,在故障几率和故障影响之间做出权衡, 默认值是 30s,它将影响以下的 Patroni 参数:

# 获取领导者租约的 TTL(以秒为单位)。将其视为启动自动故障转移过程之前的时间长度。默认值:30
ttl: {{ pg_rto }}

# 循环将休眠的秒数。默认值:10,这是 patroni 检查循环间隔
loop_wait: {{ (pg_rto / 3)|round(0, 'ceil')|int }}

# DCS 和 PostgreSQL 操作重试的超时时间(以秒为单位)。比这短的 DCS 或网络问题不会导致 Patroni 降级领导。默认值:10
retry_timeout: {{ (pg_rto / 3)|round(0, 'ceil')|int }}

# 主实例在触发故障转移之前允许从故障中恢复的时间(以秒为单位),最大 RTO:2 倍循环等待 + primary_start_timeout
primary_start_timeout: {{ (pg_rto / 3)|round(0, 'ceil')|int }}

pg_rpo

参数名称: pg_rpo, 类型: int, 层次:C

以字节为单位的恢复点目标(RPO),默认值:1048576

默认为 1MiB,这意味着在故障转移期间最多可以容忍 1MiB 的数据丢失。

当主节点宕机并且所有副本都滞后时,你必须做出一个艰难的选择,在可用性和一致性之间进行权衡

  • 提升一个从库成为新的主库,并尽快将系统恢复服务,但要付出可接受的数据丢失代价(例如,少于 1MB)。
  • 等待主库重新上线(可能永远不会),或人工干预以避免任何数据丢失。

你可以使用 crit.yml conf 模板来确保在故障转移期间没有数据丢失,但这会牺牲一些性能。


pg_libs

参数名称: pg_libs, 类型: string, 层次:C

预加载的动态共享库,默认为 pg_stat_statements,auto_explain,这是两个 PostgreSQL 自带的扩展,强烈建议启用。

对于现有集群,您可以直接配置集群shared_preload_libraries 参数并应用生效。

如果您想使用 TimescaleDB 或 Citus 扩展,您需要将 timescaledbcitus 添加到此列表中。timescaledbcitus 应当放在这个列表的最前面,例如:

citus,timescaledb,pg_stat_statements,auto_explain

其他需要动态加载的扩展也可以添加到这个列表中,例如 pg_cronpgml 等,通常 citustimescaledb 有着最高的优先级,应该添加到列表的最前面。


pg_delay

参数名称: pg_delay, 类型: interval, 层次:I

延迟备库复制延迟,默认值:0

如果此值被设置为一个正值,备用集群主库在应用 WAL 变更之前将被延迟这个时间。设置为 1h 意味着该集群中的数据将始终滞后原集群一个小时。

查看 延迟备用集群 以获取详细信息。


pg_checksum

参数名称: pg_checksum, 类型: bool, 层次:C

为 PostgreSQL 集群启用数据校验和吗?v3.7.0 默认值是 true

这个参数只能在 PGSQL 部署之前设置(但你可以稍后手动启用它)。

如果使用 pg_conf crit.yml 模板,无论此参数如何,都会始终启用数据校验和,以确保数据完整性。


pg_pwd_enc

参数名称: pg_pwd_enc, 类型: enum, 层次:C

密码加密算法:md5scram-sha-256,默认值:scram-sha-256

前者已经不再安全,如果你与旧客户端有兼容性问题,你可以将其设置为 md5


pg_encoding

参数名称: pg_encoding, 类型: enum, 层次:C

数据库集群编码,默认为 UTF8

除非你非常清楚自己在做什么,否则不建议使用其他非 UTF8 的编码。


pg_locale

参数名称: pg_locale, 类型: enum, 层次:C

PostgreSQL 使用的本地化规则集,默认为 C。会在数据库初始化时作为参数传递给 initdb 命令。

configure 检测到当前 PG 版本大于等于 17,或者当前系统明确支持 C.utf8 时,会自动配置此参数为 C.UTF-8

当 PostgreSQL 版本大于等于 17 时, CC.UTF-8 配置将使用 PostgreSQL 内部自带的 Locale Providier。

除非你非常清楚自己在做什么,否则强烈建议您使用默认的 CC.UTF-8 配置。

通常应当与 pg_lc_collatepg_lc_ctype 配置保持一致。


pg_lc_collate

参数名称: pg_lc_collate, 类型: enum, 层次:C

PostgreSQL 使用的本地化排序规则集,默认为 C,一旦确定,无法在集群层面修改。

configure 检测到当前 PG 版本大于等于 17,或者当前系统明确支持 C.utf8 时,会自动配置此参数为 C.UTF-8

配置规则与 pg_locale 一致,但针对排序规则。


pg_lc_ctype

参数名称: pg_lc_ctype, 类型: enum, 层次:C

PostgreSQL 使用的本地化字符集定义 CTYPE,默认为 C,一旦确定,无法在集群层面修改。

configure 检测到当前 PG 版本大于等于 17,或者当前系统明确支持 C.utf8 时,会自动配置此参数为 C.UTF-8

配置规则与 pg_locale 一致,但针对字符类型。


pgsodium_key

参数名称: pgsodium_key, 类型: string, 层次:C

默认值未定义,将使用 pg_cluster 的 SHA256 哈希值作为密钥。

你可以提供自定义的 pgsodium 密钥,应该是 64 位十六进制数字字符串。

密钥将被写入 /pg/conf/pgsodium.key


pgsodium_getkey_script

参数名称: pgsodium_getkey_script, 类型: path, 层次:C

默认值为 pgsodium_getkey,它将 roles/pgsql/templates/pgsodium_getkey 渲染到 /pg/bin/pgsodium_getkey

默认的 getkey 脚本只是从 /pg/conf/pgsodium.key 读取 pgsodium_key 并返回它。 如果你的密钥由外部系统(如 KMS、IAM 等)管理,你可以实现自己的 getkey 脚本从那里获取密钥:示例


PG_PROVISION

如果说 PG_BOOTSTRAP 是创建一个新的集群,那么 PG_PROVISION 就是在集群中创建默认的对象,包括:

pg_provision: true                # provision postgres cluster after bootstrap
pg_init: pg-init                  # provision init script for cluster template, `pg-init` by default
pg_default_roles:                 # default roles and users in postgres cluster
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly]               ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite]  ,comment: role for object creation }
  - { name: postgres     ,superuser: true                                          ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
  - { name: dbuser_monitor   ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
pg_default_privileges:            # 管理员用户创建时的默认权限
  - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
  - GRANT SELECT     ON TABLES    TO dbrole_readonly
  - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
  - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
  - GRANT SELECT     ON TABLES    TO dbrole_offline
  - GRANT SELECT     ON SEQUENCES TO dbrole_offline
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
  - GRANT INSERT     ON TABLES    TO dbrole_readwrite
  - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
  - GRANT DELETE     ON TABLES    TO dbrole_readwrite
  - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
  - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
  - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
  - GRANT REFERENCES ON TABLES    TO dbrole_admin
  - GRANT TRIGGER    ON TABLES    TO dbrole_admin
  - GRANT CREATE     ON SCHEMAS   TO dbrole_admin
pg_default_schemas: [ monitor ]   # 默认模式
pg_default_extensions:            # 默认扩展
  - { name: pg_stat_statements ,schema: monitor }
  - { name: pgstattuple        ,schema: monitor }
  - { name: pg_buffercache     ,schema: monitor }
  - { name: pageinspect        ,schema: monitor }
  - { name: pg_prewarm         ,schema: monitor }
  - { name: pg_visibility      ,schema: monitor }
  - { name: pg_freespacemap    ,schema: monitor }
  - { name: postgres_fdw       ,schema: public  }
  - { name: file_fdw           ,schema: public  }
  - { name: btree_gist         ,schema: public  }
  - { name: btree_gin          ,schema: public  }
  - { name: pg_trgm            ,schema: public  }
  - { name: intagg             ,schema: public  }
  - { name: intarray           ,schema: public  }
  - { name: pg_repack }
pg_reload: true                   # HBA变化后是否重载配置?
pg_default_hba_rules:             # postgres 默认 HBA 规则集
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' }
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' }
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    }
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     }
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet'}
pgb_default_hba_rules:            # pgbouncer 默认 HBA 规则集
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' }
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' }

pg_provision

参数名称: pg_provision, 类型: bool, 层次:C

在集群拉起后,完整本节定义的 PostgreSQL 集群置备工作。默认值为true

如果禁用,不会置备 PostgreSQL 集群。对于一些特殊的 “PostgreSQL” 集群,比如 Greenplum,可以关闭此选项跳过置备阶段。


pg_init

参数名称: pg_init, 类型: string, 层次:G/C

用于初始化数据库模板的Shell脚本位置,默认为 pg-init,该脚本会被拷贝至/pg/bin/pg-init后执行。

该脚本位于 roles/pgsql/templates/pg-init

你可以在该脚本中添加自己的逻辑,或者提供一个新的脚本放置在 templates/ 目录下,并将 pg_init 设置为新的脚本名称。使用自定义脚本时请保留现有的初始化逻辑。


pg_default_roles

参数名称: pg_default_roles, 类型: role[], 层次:G/C

Postgres 集群中的默认角色和用户。

Pigsty有一个内置的角色系统,请查看PGSQL访问控制:角色系统了解详情。

pg_default_roles:                 # default roles and users in postgres cluster
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly]               ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite]  ,comment: role for object creation }
  - { name: postgres     ,superuser: true                                          ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
  - { name: dbuser_monitor   ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

pg_default_privileges

参数名称: pg_default_privileges, 类型: string[], 层次:G/C

每个数据库中的默认权限(DEFAULT PRIVILEGE)设置:

pg_default_privileges:            # 管理员用户创建时的默认权限
  - GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
  - GRANT SELECT     ON TABLES    TO dbrole_readonly
  - GRANT SELECT     ON SEQUENCES TO dbrole_readonly
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
  - GRANT USAGE      ON SCHEMAS   TO dbrole_offline
  - GRANT SELECT     ON TABLES    TO dbrole_offline
  - GRANT SELECT     ON SEQUENCES TO dbrole_offline
  - GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
  - GRANT INSERT     ON TABLES    TO dbrole_readwrite
  - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
  - GRANT DELETE     ON TABLES    TO dbrole_readwrite
  - GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
  - GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
  - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
  - GRANT REFERENCES ON TABLES    TO dbrole_admin
  - GRANT TRIGGER    ON TABLES    TO dbrole_admin
  - GRANT CREATE     ON SCHEMAS   TO dbrole_admin

Pigsty 基于默认角色系统提供了相应的默认权限设置,请查看PGSQL访问控制:权限了解详情。


pg_default_schemas

参数名称: pg_default_schemas, 类型: string[], 层次:G/C

要创建的默认模式,默认值为:[ monitor ],这将在所有数据库上创建一个monitor模式,用于放置各种监控扩展、表、视图、函数。


pg_default_extensions

参数名称: pg_default_extensions, 类型: extension[], 层次:G/C

要在所有数据库中默认创建启用的扩展列表,默认值:

pg_default_extensions: # default extensions to be created
  - { name: pg_stat_statements ,schema: monitor }
  - { name: pgstattuple        ,schema: monitor }
  - { name: pg_buffercache     ,schema: monitor }
  - { name: pageinspect        ,schema: monitor }
  - { name: pg_prewarm         ,schema: monitor }
  - { name: pg_visibility      ,schema: monitor }
  - { name: pg_freespacemap    ,schema: monitor }
  - { name: postgres_fdw       ,schema: public  }
  - { name: file_fdw           ,schema: public  }
  - { name: btree_gist         ,schema: public  }
  - { name: btree_gin          ,schema: public  }
  - { name: pg_trgm            ,schema: public  }
  - { name: intagg             ,schema: public  }
  - { name: intarray           ,schema: public  }
  - { name: pg_repack }

唯一的三方扩展是 pg_repack,这对于数据库维护很重要,所有其他扩展都是内置的 PostgreSQL Contrib 扩展插件。

监控相关的扩展默认安装在 monitor 模式中,该模式由pg_default_schemas创建。


pg_reload

参数名称: pg_reload, 类型: bool, 层次:A

在hba更改后重新加载 PostgreSQL,默认值为true

当您想在应用HBA更改之前进行检查时,将其设置为false以禁用自动重新加载配置。


pg_default_hba_rules

参数名称: pg_default_hba_rules, 类型: hba[], 层次:G/C

PostgreSQL 基于主机的认证规则,全局默认规则定义。默认值为:

pg_default_hba_rules:             # postgres default host-based authentication rules
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' }
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' }
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    }
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     }
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet'}

默认值为常见场景提供了足够的安全级别,请查看PGSQL身份验证了解详情。

本参数为 HBA规则对象组成的数组,在形式上与 pg_hba_rules 完全一致。 建议在全局配置统一的 pg_default_hba_rules,针对特定集群使用 pg_hba_rules 进行额外定制。两个参数中的规则都会依次应用,后者优先级更高。


pgb_default_hba_rules

参数名称: pgb_default_hba_rules, 类型: hba[], 层次:G/C

Pgbouncer 默认的基于主机的认证规则,数组或 hba 规则对象。

默认值提供了一套对于常见场景足够的安全级别,查看 PGSQL Authentication 了解详情。

pgb_default_hba_rules:            # pgbouncer default host-based authentication rules
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' }
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' }

默认的Pgbouncer HBA规则很简单:

  1. 允许从本地使用密码登陆
  2. 允许从内网网断使用密码登陆

用户可以按照自己的需求进行定制。

本参数在形式上与 pgb_hba_rules 完全一致,建议在全局配置统一的 pgb_default_hba_rules,针对特定集群使用 pgb_hba_rules 进行额外定制。两个参数中的规则都会依次应用,后者优先级更高。


PG_BACKUP

本节定义了用于 pgBackRest 的变量,它被用于 PGSQL 时间点恢复 PITR 。

查看 PGSQL 备份 & PITR 以获取详细信息。

pgbackrest_enabled: true          # 在 pgsql 主机上启用 pgBackRest 吗?
pgbackrest_clean: true            # 初始化时删除 pg 备份数据?
pgbackrest_log_dir: /pg/log/pgbackrest # pgbackrest 日志目录,默认为 `/pg/log/pgbackrest`
pgbackrest_method: local          # pgbackrest 仓库方法:local, minio, [用户定义...]
pgbackrest_repo:                  # pgbackrest 仓库:https://pgbackrest.org/configuration.html#section-repository
  local:                          # 默认使用本地 posix 文件系统的 pgbackrest 仓库
    path: /pg/backup              # 本地备份目录,默认为 `/pg/backup`
    retention_full_type: count    # 按计数保留完整备份
    retention_full: 2             # 使用本地文件系统仓库时,最多保留 3 个完整备份,至少保留 2 个
  minio:                          # pgbackrest 的可选 minio 仓库
    type: s3                      # minio 是与 s3 兼容的,所以使用 s3
    s3_endpoint: sss.pigsty       # minio 端点域名,默认为 `sss.pigsty`
    s3_region: us-east-1          # minio 区域,默认为 us-east-1,对 minio 无效
    s3_bucket: pgsql              # minio 桶名称,默认为 `pgsql`
    s3_key: pgbackrest            # pgbackrest 的 minio 用户访问密钥
    s3_key_secret: S3User.Backup  # pgbackrest 的 minio 用户秘密密钥
    s3_uri_style: path            # 对 minio 使用路径风格的 uri,而不是主机风格
    path: /pgbackrest             # minio 备份路径,默认为 `/pgbackrest`
    storage_port: 9000            # minio 端口,默认为 9000
    storage_ca_file: /etc/pki/ca.crt  # minio ca 文件路径,默认为 `/etc/pki/ca.crt`
    block: y                      # 启用块增量备份
    bundle: y                     # 将小文件捆绑在一起
    bundle_limit: 20MiB           # 文件捆绑限制,20MiB 用于对象存储
    bundle_size: 128MiB           # 文件捆绑目标大小,128MiB 用于对象存储
    cipher_type: aes-256-cbc      # 为远程备份仓库启用 AES 加密
    cipher_pass: pgBackRest       # AES 加密密码,默认为 'pgBackRest'
    retention_full_type: time     # 在 minio 仓库上按时间保留完整备份
    retention_full: 14            # 保留过去 14 天的完整备份

pgbackrest_enabled

参数名称: pgbackrest_enabled, 类型: bool, 层次:C

是否在 PGSQL 节点上启用 pgBackRest?默认值为: true

在使用本地文件系统备份仓库(local)时,只有集群主库才会真正启用 pgbackrest。其他实例只会初始化一个空仓库。


pgbackrest_clean

参数名称: pgbackrest_clean, 类型: bool, 层次:C

初始化时删除 PostgreSQL 备份数据吗?默认值为 true


pgbackrest_log_dir

参数名称: pgbackrest_log_dir, 类型: path, 层次:C

pgBackRest 日志目录,默认为 /pg/log/pgbackrestpromtail 日志代理会引用此参数收集日志。


pgbackrest_method

参数名称: pgbackrest_method, 类型: enum, 层次:C

pgBackRest 仓库方法:默认可选项为:localminio 或其他用户定义的方法,默认为 local

此参数用于确定用于 pgBackRest 的仓库,所有可用的仓库方法都在 pgbackrest_repo 中定义。

Pigsty 默认使用 local 备份仓库,这将在主实例的 /pg/backup 目录上创建一个备份仓库。底层存储路径由 pg_fs_bkup 指定。


pgbackrest_init_backup

name: pgbackrest_init_backup, type: bool, level: C

Take a full backup after pgBackRest is initialized? default value is true.

An initial pgbackrest backup is created after repo init if:

  • pgbackrest_init_backup is true (and pgbackrest_enabled is true of course)
  • The /etc/pgbackrest/initial.done marker file doesn’t exist (will be created after the initial backup is done).

If you don’t want to take an initial full backup at all, just set this parameter tofalse.


pgbackrest_repo

参数名称: pgbackrest_repo, 类型: dict, 层次:G/C

pgBackRest 仓库文档:https://pgbackrest.org/configuration.html#section-repository

默认值包括两种仓库方法:localminio,定义如下:

pgbackrest_repo:                  # pgbackrest 仓库:https://pgbackrest.org/configuration.html#section-repository
  local:                          # 默认使用本地 posix 文件系统的 pgbackrest 仓库
    path: /pg/backup              # 本地备份目录,默认为 `/pg/backup`
    retention_full_type: count    # 按计数保留完整备份
    retention_full: 2             # 使用本地文件系统仓库时,最多保留 3 个完整备份,至少保留 2 个
  minio:                          # pgbackrest 的可选 minio 仓库
    type: s3                      # minio 是与 s3 兼容的,所以使用 s3
    s3_endpoint: sss.pigsty       # minio 端点域名,默认为 `sss.pigsty`
    s3_region: us-east-1          # minio 区域,默认为 us-east-1,对 minio 无效
    s3_bucket: pgsql              # minio 桶名称,默认为 `pgsql`
    s3_key: pgbackrest            # pgbackrest 的 minio 用户访问密钥
    s3_key_secret: S3User.Backup  # pgbackrest 的 minio 用户秘密密钥
    s3_uri_style: path            # 对 minio 使用路径风格的 uri,而不是主机风格
    path: /pgbackrest             # minio 备份路径,默认为 `/pgbackrest`
    storage_port: 9000            # minio 端口,默认为 9000
    storage_ca_file: /etc/pki/ca.crt  # minio ca 文件路径,默认为 `/etc/pki/ca.crt`
    block: y                      # 启用块增量备份
    bundle: y                     # 将小文件捆绑在一起
    bundle_limit: 20MiB           # 文件捆绑限制,20MiB 用于对象存储
    bundle_size: 128MiB           # 文件捆绑目标大小,128MiB 用于对象存储
    cipher_type: aes-256-cbc      # 为远程备份仓库启用 AES 加密
    cipher_pass: pgBackRest       # AES 加密密码,默认为 'pgBackRest'
    retention_full_type: time     # 在 minio 仓库上按时间保留完整备份
    retention_full: 14            # 保留过去 14 天的完整备份

您可以定义新的备份仓库,例如使用 AWS S3,GCP 或其他云供应商的 S3 兼容存储服务。

在备份仓库定义参数中,你可以使用 ${pg_cluster} 变量来引用集群名称,例如作为备份路径或加密密钥的一部分。 但如果你有跨集群 PITR 的需求,则应该保持备份仓库路径与加密密钥相同。


PG_ACCESS

本节介绍如何将PostgreSQL服务暴露给外部世界,包括:

  • 使用haproxy在不同的端口上暴露不同的PostgreSQL服务
  • 使用vip-manager将可选的L2 VIP绑定到主实例
  • 在基础设施节点上使用dnsmasq注册集群/实例DNS记录
pgbouncer_enabled: true           # if disabled, pgbouncer will not be launched on pgsql host
pgbouncer_port: 6432              # pgbouncer listen port, 6432 by default
pgbouncer_log_dir: /pg/log/pgbouncer  # pgbouncer log dir, `/pg/log/pgbouncer` by default
pgbouncer_auth_query: false       # query postgres to retrieve unlisted business users?
pgbouncer_poolmode: transaction   # pooling mode: transaction,session,statement, transaction by default
pgbouncer_sslmode: disable        # pgbouncer client ssl mode, disable by default

pg_weight: 100          #INSTANCE # relative load balance weight in service, 100 by default, 0-255
pg_default_service_dest: pgbouncer # default service destination if svc.dest='default'
pg_default_services:              # postgres default service definitions
  - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
  - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
  - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
  - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}
pg_vip_enabled: false             # 为pgsql主要实例启用l2 vip吗? 默认为false
pg_vip_address: 127.0.0.1/24      # `<ipv4>/<mask>`格式的vip地址,如果启用vip则需要
pg_vip_interface: eth0            # vip网络接口监听,默认为eth0
pg_dns_suffix: ''                 # pgsql dns后缀,默认为空
pg_dns_target: auto               # auto、primary、vip、none或特定的ip

pgbouncer_enabled

name: pgbouncer_enabled, type: bool, level: C

default value is true, if disabled, pgbouncer will not be launched on pgsql host


pgbouncer_port

name: pgbouncer_port, type: port, level: C

pgbouncer listen port, 6432 by default


pgbouncer_log_dir

name: pgbouncer_log_dir, type: path, level: C

pgbouncer log dir, /pg/log/pgbouncer by default, referenced by promtail the logging agent.


pgbouncer_auth_query

name: pgbouncer_auth_query, type: bool, level: C

query postgres to retrieve unlisted business users? default value is false

If enabled, pgbouncer user will be authenticated against postgres databases with SELECT username, password FROM monitor.pgbouncer_auth($1), otherwise, only the users with pgbouncer: true will be allowed to connect to pgbouncer.


pgbouncer_poolmode

name: pgbouncer_poolmode, type: enum, level: C

Pgbouncer pooling mode: transaction, session, statement, transaction by default

  • session: Session-level pooling with the best compatibility.
  • transaction: Transaction-level pooling with better performance (lots of small conns), could break some session level features such as notify/listen, etc…
  • statements: Statement-level pooling which is used for simple read-only queries.

If your application has some compatibility issues with pgbouncer, you can try to change this value to session instead.


pgbouncer_sslmode

name: pgbouncer_sslmode, type: enum, level: C

pgbouncer client ssl mode, disable by default

default values: disable, beware that this may have a huge performance impact on your pgbouncer.

  • disable: Plain TCP. If a client requests TLS, it’s ignored. Default.
  • allow: If a client requests TLS, it is used. If not, plain TCP is used. If the client presents a client certificate, it is not validated.
  • prefer: Same as allow.
  • require: Client must use TLS. If not, the client connection is rejected. If the client presents a client certificate, it is not validated.
  • verify-ca: Client must use TLS with valid client certificate.
  • verify-full: Same as verify-ca.

pgbouncer_ignore_param

name: pgbouncer_ignore_param, type: string[], level: G/C

default values: [ extra_float_digits, application_name, TimeZone, DateStyle, IntervalStyle, search_path ]

This will be used as value of ignore_startup_parameters in pgbouncer.


pg_weight

参数名称: pg_weight, 类型: int, 层次:G

服务中的相对负载均衡权重,默认为100,范围0-255。

默认值: 100。您必须在实例变量中定义它,并重载服务以生效。


pg_service_provider

参数名称: pg_service_provider, 类型: string, 层次:G/C

专用的haproxy节点组名,或默认为本地节点的空字符串。

如果指定,PostgreSQL服务将注册到专用的haproxy节点组,而不是当下的 PGSQL 集群节点。

请记住为每个服务在专用的 haproxy 节点上分配唯一的端口!

例如,如果我们在3节点的 pg-test 集群上定义以下参数:

pg_service_provider: infra       # use load balancer on group `infra`
pg_default_services:             # alloc port 10001 and 10002 for pg-test primary/replica service
  - { name: primary ,port: 10001 ,dest: postgres  ,check: /primary   ,selector: "[]" }
  - { name: replica ,port: 10002 ,dest: postgres  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }

pg_default_service_dest

参数名称: pg_default_service_dest, 类型: enum, 层次:G/C

当定义一个服务时,如果 svc.dest='default',此参数将用作默认值。

默认值: pgbouncer,意味着 5433 读写服务和 5434 只读服务将默认将流量路由到 pgbouncer。

如果您不想使用 pgbouncer,将其设置为 postgres。流量将直接路由到 postgres。


pg_default_services

参数名称: pg_default_services, 类型: service[], 层次:G/C

postgres默认服务定义

默认值是四个默认服务定义,如PGSQL Service所述

pg_default_services:               # postgres default service definitions
  - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
  - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
  - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
  - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

pg_vip_enabled

参数名称: pg_vip_enabled, 类型: bool, 层次:C

为 PGSQL 集群启用 L2 VIP吗?默认值是false,表示不创建 L2 VIP。

启用 L2 VIP 后,会有一个 VIP 绑定在集群主实例节点上,由 vip-manager 管理,根据 etcd 中的数据进行判断。

L2 VIP只能在相同的L2网络中使用,这可能会对您的网络拓扑产生额外的限制。


pg_vip_address

参数名称: pg_vip_address, 类型: cidr4, 层次:C

如果启用vip,则需要<ipv4>/<mask>格式的vip地址。

默认值: 127.0.0.1/24。这个值由两部分组成:ipv4mask,用/分隔。


pg_vip_interface

参数名称: pg_vip_interface, 类型: string, 层次:C/I

vip network interface to listen, eth0 by default.

L2 VIP 监听的网卡接口,默认为 eth0

它应该是您节点的首要网卡名,即您在配置清单中使用的IP地址。

如果您的节点有多块名称不同的网卡,您可以在实例变量上进行覆盖:

pg-test:
    hosts:
        10.10.10.11: {pg_seq: 1, pg_role: replica ,pg_vip_interface: eth0 }
        10.10.10.12: {pg_seq: 2, pg_role: primary ,pg_vip_interface: eth1 }
        10.10.10.13: {pg_seq: 3, pg_role: replica ,pg_vip_interface: eth2 }
    vars:
      pg_vip_enabled: true          # 为这个集群启用L2 VIP,默认绑定到主实例
      pg_vip_address: 10.10.10.3/24 # L2网络CIDR: 10.10.10.0/24, vip地址: 10.10.10.3
      # pg_vip_interface: eth1      # 如果您的节点有统一的接口,您可以在这里定义它

pg_dns_suffix

参数名称: pg_dns_suffix, 类型: string, 层次:C

PostgreSQL DNS 名称后缀,默认为空字符串。

在默认情况下,PostgreQL 集群名会作为 DNS 域名注册到 Infra 节点的 dnsmasq 中对外提供解析。

您可以通过本参数指定一个域名后缀,这样会使用 {{ pg_cluster }}{{ pg_dns_suffix }} 作为集群 DNS 名称。

例如,如果您将 pg_dns_suffix 设置为 .db.vip.company.tld,那么 pg-test 的集群 DNS 名称将是 pg-test.db.vip.company.tld


pg_dns_target

参数名称: pg_dns_target, 类型: enum, 层次:C

可以是:autoprimaryvipnone或一个特定的IP地址,它将是集群DNS记录的解析目标IP地址。

默认值: auto,如果pg_vip_enabled,将绑定到pg_vip_address,否则会回退到集群主实例的 IP 地址。

  • vip:绑定到pg_vip_address
  • primary:解析为集群主实例IP地址
  • auto:如果 pg_vip_enabled,解析为 pg_vip_address,或回退到集群主实例ip地址。
  • none:不绑定到任何ip地址
  • <ipv4>:绑定到指定的IP地址

PG_EXPORTER

PG Exporter 用于监控 PostgreSQL 数据库与 Pgbouncer 连接池的状态。

pg_exporter_enabled: true              # 在 pgsql 主机上启用 pg_exporter 吗?
pg_exporter_config: pg_exporter.yml    # pg_exporter 配置文件名
pg_exporter_cache_ttls: '1,10,60,300'  # pg_exporter 收集器 ttl 阶段(秒),默认为 '1,10,60,300'
pg_exporter_port: 9630                 # pg_exporter 监听端口,默认为 9630
pg_exporter_params: 'sslmode=disable'  # pg_exporter dsn 的额外 url 参数
pg_exporter_url: ''                    # 如果指定,将覆盖自动生成的 pg dsn
pg_exporter_auto_discovery: true       # 启用自动数据库发现?默认启用
pg_exporter_exclude_database: 'template0,template1,postgres' # 在自动发现过程中不会被监控的数据库的 csv 列表
pg_exporter_include_database: ''       # 在自动发现过程中将被监控的数据库的 csv 列表
pg_exporter_connect_timeout: 200       # pg_exporter 连接超时(毫秒),默认为 200
pg_exporter_options: ''                # 覆盖 pg_exporter 的额外选项
pgbouncer_exporter_enabled: true       # 在 pgsql 主机上启用 pgbouncer_exporter 吗?
pgbouncer_exporter_port: 9631          # pgbouncer_exporter 监听端口,默认为 9631
pgbouncer_exporter_url: ''             # 如果指定,将覆盖自动生成的 pgbouncer dsn
pgbouncer_exporter_options: ''         # 覆盖 pgbouncer_exporter 的额外选项
pgbackrest_exporter_enabled: true      # 在 pgsql 主机上启用 pgbackrest_exporter 吗?
pgbackrest_exporter_port: 9854         # pgbackrest_exporter 监听端口,默认为 9854
pgbackrest_exporter_options: ''        # 覆盖 pgbackrest_exporter 的额外选项

pg_exporter_enabled

参数名称: pg_exporter_enabled, 类型: bool, 层次:C

是否在 PGSQL 节点上启用 pg_exporter?默认值为:true

PG Exporter 用于监控 PostgreSQL 数据库实例,如果不想安装 pg_exporter 可以设置为 false


pg_exporter_config

参数名称: pg_exporter_config, 类型: string, 层次:C

pg_exporter 配置文件名,PG Exporter 和 PGBouncer Exporter 都会使用这个配置文件。默认值:pg_exporter.yml

如果你想使用自定义配置文件,你可以在这里定义它。你的自定义配置文件应当放置于 files/<name>.yml

例如,当您希望监控一个远程的 PolarDB 数据库实例时,可以使用样例配置:files/polar_exporter.yml


pg_exporter_cache_ttls

参数名称: pg_exporter_cache_ttls, 类型: string, 层次:C

pg_exporter 收集器 TTL 阶梯(秒),默认为 1,10,60,300

默认值:1,10,60,300,它将为不同的度量收集器使用不同的TTL值: 1s, 10s, 60s, 300s。

PG Exporter 内置了缓存机制,避免多个 Prometheus 重复抓取对数据库产生不当影响,所有指标收集器按 TTL 分为四类:

ttl_fast: "{{ pg_exporter_cache_ttls.split(',')[0]|int }}"         # critical queries
ttl_norm: "{{ pg_exporter_cache_ttls.split(',')[1]|int }}"         # common queries
ttl_slow: "{{ pg_exporter_cache_ttls.split(',')[2]|int }}"         # slow queries (e.g table size)
ttl_slowest: "{{ pg_exporter_cache_ttls.split(',')[3]|int }}"      # ver slow queries (e.g bloat)

例如,在默认配置下,存活类指标默认最多缓存 1s,大部分普通指标会缓存 10s(应当与 prometheus_scrape_interval 相同)。 少量变化缓慢的查询会有 60s 的TTL,极个别大开销监控查询会有 300s 的TTL。


pg_exporter_port

参数名称: pg_exporter_port, 类型: port, 层次:C

pg_exporter 监听端口号,默认值为:9631


pg_exporter_params

参数名称: pg_exporter_params, 类型: string, 层次:C

pg_exporter 所使用 DSN 中额外的 URL PATH 参数。

默认值:sslmode=disable,它将禁用用于监控连接的 SSL(因为默认使用本地 unix 套接字)。


pg_exporter_url

参数名称: pg_exporter_url, 类型: pgurl, 层次:C

如果指定了本参数,将会覆盖自动生成的 PostgreSQL DSN,使用指定的 DSN 连接 PostgreSQL 。默认值为空字符串。

如果没有指定此参数,PG Exporter 默认会使用以下的连接串访问 PostgreSQL :

postgres://{{ pg_monitor_username }}:{{ pg_monitor_password }}@{{ pg_host }}:{{ pg_port }}/postgres{% if pg_exporter_params != '' %}?{{ pg_exporter_params }}{% endif %}

当您想监控一个远程的 PostgreSQL 实例时,或者需要使用不同的监控用户/密码,配置选项时,可以使用这个参数。


pg_exporter_auto_discovery

参数名称: pg_exporter_auto_discovery, 类型: bool, 层次:C

启用自动数据库发现吗? 默认启用:true

PG Exporter 默认会连接到 DSN 中指定的数据库 (默认为管理数据库 postgres) 收集全局指标,如果您希望收集所有业务数据库的指标,可以开启此选项。 PG Exporter 会自动发现目标 PostgreSQL 实例中的所有数据库,并在这些数据库中收集 库级监控指标


pg_exporter_exclude_database

参数名称: pg_exporter_exclude_database, 类型: string, 层次:C

如果启用了数据库自动发现(默认启用),在这个参数指定的列表中的数据库将不会被监控。 默认值为: template0,template1,postgres,即管理数据库 postgres 与模板数据库会被排除在自动监控的数据库之外。

作为例外,DSN 中指定的数据库不受此参数影响,例如,PG Exporter 如果连接的是 postgres 数据库,那么即使 postgres 在此列表中,也会被监控。


pg_exporter_include_database

参数名称: pg_exporter_include_database, 类型: string, 层次:C

如果启用了数据库自动发现(默认启用),在这个参数指定的列表中的数据库才会被监控。默认值为空字符串,即不启用此功能。

参数的形式是由逗号分隔的数据库名称列表,例如:db1,db2,db3

此参数相对于 pg_exporter_exclude_database 有更高的优先级,相当于白名单模式。如果您只希望监控特定的数据库,可以使用此参数。


pg_exporter_connect_timeout

参数名称: pg_exporter_connect_timeout, 类型: int, 层次:C

pg_exporter 连接超时(毫秒),默认为 200 (单位毫秒)

当 PG Exporter 尝试连接到 PostgreSQL 数据库时,最多会等待多长时间?超过这个时间,PG Exporter 将会放弃连接并报错。

默认值 200毫秒 对于绝大多数场景(例如:同可用区监控)都是足够的,但是如果您监控的远程 PostgreSQL 位于另一个大洲,您可能需要增加此值以避免连接超时。


pg_exporter_options

参数名称: pg_exporter_options, 类型: arg, 层次:C

传给 PG Exporter 的命令行参数,默认值为:"" 空字符串。

当使用空字符串时,会使用默认的命令参数:

{% if pg_exporter_port != '' %}
PG_EXPORTER_OPTS='--web.listen-address=:{{ pg_exporter_port }} {{ pg_exporter_options }}'
{% else %}
PG_EXPORTER_OPTS='--web.listen-address=:{{ pg_exporter_port }} --log.level=info'
{% endif %}

注意,请不要在本参数中覆盖 pg_exporter_port 的端口配置。


pgbouncer_exporter_enabled

参数名称: pgbouncer_exporter_enabled, 类型: bool, 层次:C

在 PGSQL 节点上,是否启用 pgbouncer_exporter ?默认值为:true


pgbouncer_exporter_port

参数名称: pgbouncer_exporter_port, 类型: port, 层次:C

pgbouncer_exporter 监听端口号,默认值为:9631


pgbouncer_exporter_url

参数名称: pgbouncer_exporter_url, 类型: pgurl, 层次:C

如果指定了本参数,将会覆盖自动生成的 pgbouncer DSN,使用指定的 DSN 连接 pgbouncer。默认值为空字符串。

如果没有指定此参数,Pgbouncer Exporter 默认会使用以下的连接串访问 Pgbouncer:

postgres://{{ pg_monitor_username }}:{{ pg_monitor_password }}@:{{ pgbouncer_port }}/pgbouncer?host={{ pg_localhost }}&sslmode=disable

当您想监控一个远程的 Pgbouncer 实例时,或者需要使用不同的监控用户/密码,配置选项时,可以使用这个参数。


pgbouncer_exporter_options

参数名称: pgbouncer_exporter_options, 类型: arg, 层次:C

传给 Pgbouncer Exporter 的命令行参数,默认值为:"" 空字符串。

当使用空字符串时,会使用默认的命令参数:

{% if pgbouncer_exporter_options != '' %}
PG_EXPORTER_OPTS='--web.listen-address=:{{ pgbouncer_exporter_port }} {{ pgbouncer_exporter_options }}'
{% else %}
PG_EXPORTER_OPTS='--web.listen-address=:{{ pgbouncer_exporter_port }} --log.level=info'
{% endif %}

注意,请不要在本参数中覆盖 pgbouncer_exporter_port 的端口配置。


pgbackrest_exporter_enabled

参数名称: pgbackrest_exporter_enabled, 类型: bool, 层次:C

在 PGSQL 节点上,是否启用 pgbackrest_exporter ?默认值为:true

如果 pgbackrest_enabledfalse,则本参数因短路无效。


pgbackrest_exporter_port

参数名称: pgbackrest_exporter_port, 类型: port, 层次:C

pgbackrest_exporter 监听端口号,默认值为:9854


pgbackrest_exporter_options

参数名称: pgbackrest_exporter_options, 类型: arg, 层次:C

传给 Pgbouncer Exporter 的命令行参数,默认值为:"" 空字符串。


PG_REMOVE

这些参数控制 pgsql-rm.yml,并与 v3.7.0 的 roles/pg_remove/defaults/main.yml 保持一致。

pg_safeguard: false               # 显式启用时中止删除
pg_rm_data: true                  # 删除 PostgreSQL 数据
pg_rm_backup: true                # 删除主实例的 pgBackRest 备份
pg_rm_pkg: true                   # 卸载 PostgreSQL 软件包

pg_safeguard

参数名称:pg_safeguard,类型:bool,层级:G/C/A

设为 true 时,pgsql-rm.yml 会在修改集群前中止。v3.7.0 默认值为 false


pg_rm_data

参数名称:pg_rm_data,类型:bool,层级:G/C/A

删除 PostgreSQL 数据,默认值为 true;设为 false 可保留数据目录。


pg_rm_backup

参数名称:pg_rm_backup,类型:bool,层级:G/C/A

删除主实例时一并删除 pgBackRest 备份仓库,默认值为 true;设为 false 可保留备份。


pg_rm_pkg

参数名称:pg_rm_pkg,类型:bool,层级:G/C/A

删除时卸载 PostgreSQL 与扩展软件包。v3.7.0 角色默认值为 true;设为 false 可保留已安装的软件包。

4 - 管理

数据库管理任务标准操作指南(SOP)

如何使用 Pigsty 维护现有的 PostgreSQL 集群?

以下是常见 PostgreSQL 管理任务的标准操作程序:


快捷命令

PGSQL 剧本和快捷命令:

bin/pgsql-add   <cls>                   # 创建 PostgreSQL 集群 <cls>
bin/pgsql-user  <cls> <username>        # 在集群 <cls> 上创建用户 <username>
bin/pgsql-db    <cls> <dbname>          # 在集群 <cls> 上创建数据库 <dbname>
bin/pgsql-svc   <cls> [...ip]           # 重载集群 <cls> 的 PostgreSQL 服务
bin/pgsql-hba   <cls> [...ip]           # 重载集群 <cls> 的 postgres/pgbouncer HBA 规则
bin/pgsql-add   <cls> [...ip]           # 为集群 <cls> 添加从库
bin/pgsql-rm    <cls> [...ip]           # 从集群 <cls> 移除从库
bin/pgsql-rm    <cls>                   # 移除 PostgreSQL 集群 <cls>

Patroni 管理命令和快捷方式:

pg list        <cls>                    # 打印集群信息
pg edit-config <cls>                    # 编辑集群配置
pg reload      <cls> [ins]              # 重载集群配置
pg restart     <cls> [ins]              # 重启 PostgreSQL 集群
pg reinit      <cls> [ins]              # 重新初始化集群成员
pg pause       <cls>                    # 进入维护模式(无自动故障转移)
pg resume      <cls>                    # 退出维护模式
pg switchover  <cls>                    # 在集群 <cls> 上执行主从切换
pg failover    <cls>                    # 在集群 <cls> 上执行故障转移

pgBackRest 备份与恢复命令和快捷方式:

pb info                                 # 打印 pgbackrest 仓库信息
pg-backup                               # 进行备份,增量备份,或在必要时进行完整备份
pg-backup full                          # 进行完整备份
pg-backup diff                          # 进行差异备份
pg-backup incr                          # 进行增量备份
pg-pitr -i                              # 恢复到最新备份完成的时间(不常用)
pg-pitr --time="2022-12-30 14:44:44+08" # 恢复到特定时间点(在删除数据库、删除表的情况下)
pg-pitr --name="my-restore-point"       # 恢复到由 pg_create_restore_point 创建的命名恢复点
pg-pitr --lsn="0/7C82CB8" -X            # 恢复到 LSN 之前
pg-pitr --xid="1234567" -X -P           # 恢复到特定事务 ID 之前,然后提升
pg-pitr --backup=latest                 # 恢复到最新备份集
pg-pitr --backup=20221108-105325        # 恢复到特定备份集,可通过 pgbackrest info 检查

Systemd 组件快速参考:

systemctl stop patroni                  # start stop restart reload
systemctl stop pgbouncer                # start stop restart reload
systemctl stop pg_exporter              # start stop restart reload
systemctl stop pgbouncer_exporter       # start stop restart reload
systemctl stop node_exporter            # start stop restart
systemctl stop haproxy                  # start stop restart reload
systemctl stop vip-manager              # start stop restart reload
systemctl stop postgres                 # 仅当 patroni_mode == 'remove' 时

创建集群

要创建新的 Postgres 集群,首先在配置清单中定义它,然后使用以下命令初始化:

bin/node-add <cls>                # 为集群 <cls> 初始化节点           # ./node.yml  -l <cls>
bin/pgsql-add <cls>               # 初始化集群 <cls> 的 PostgreSQL 实例  # ./pgsql.yml -l <cls>

注意,请先执行 bin/node-add,然后执行 bin/pgsql-add,PGSQL 只能在受管节点上工作。


创建用户

要在现有 Postgres 集群上创建新的业务用户,将用户定义添加到 all.children.<cls>.pg_users,然后按如下方式创建用户:

bin/pgsql-user <cls> <username>   # ./pgsql-user.yml -l <cls> -e username=<username>

创建数据库

要在现有 Postgres 集群上创建新的数据库用户,将数据库定义添加到 all.children.<cls>.pg_databases,然后按如下方式创建数据库:

bin/pgsql-db <cls> <dbname>       # ./pgsql-db.yml -l <cls> -e dbname=<dbname>

注意:如果数据库指定了拥有者,该用户应该已经存在,否则您需要先 创建用户


重载服务

服务是由 HAProxy 服务的暴露访问点。

此任务用于集群成员发生变化时,例如 添加/移除 从库、主从切换/故障转移或暴露新服务或更新现有服务的配置(例如负载均衡权重)。

要在整个代理集群或特定实例上创建新服务或重载现有服务:

bin/pgsql-svc <cls>               # pgsql.yml -l <cls> -t pg_service -e pg_reload=true
bin/pgsql-svc <cls> [ip...]       # pgsql.yml -l ip... -t pg_service -e pg_reload=true

重载 HBA 规则

此任务用于您的 Postgres/Pgbouncer HBA 规则发生变化时,您可能需要重载 HBA 以应用更改。

如果您有任何特定于角色的 HBA 规则,您可能也需要在主从切换/故障转移后重载 HBA。

要在整个集群或特定实例上重载 postgres 和 pgbouncer HBA 规则:

bin/pgsql-hba <cls>               # pgsql.yml -l <cls> -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true
bin/pgsql-hba <cls> [ip...]       # pgsql.yml -l ip... -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true

配置集群

要更改现有 Postgres 集群的配置,您必须在使用管理员用户的管理节点上发起控制命令:

pg edit-config <cls>              # 使用 patronictl 交互式配置集群

更改 patroni 参数和 postgresql.parameters,使用向导保存并应用更改。


添加从库

要向现有 Postgres 集群添加新的从库,您必须将其定义添加到配置清单:all.children.<cls>.hosts,然后:

bin/node-add <ip>                 # 为新从库初始化节点 <ip>
bin/pgsql-add <cls> <ip>          # 在 <ip> 上为集群 <cls> 初始化 PostgreSQL 实例

这将把节点 <ip> 添加到 pigsty 并将其初始化为集群 <cls> 的从库。

集群服务将被 重载 以采纳新成员。


移除从库

要从现有 PostgreSQL 集群中移除从库:

bin/pgsql-rm <cls> <ip...>        # ./pgsql-rm.yml -l <ip>

这将从集群 <cls> 中移除实例 <ip>。集群服务将被 重载 以从负载均衡器中踢出被移除的实例。


移除集群

要移除整个 Postgres 集群,只需运行:

bin/pgsql-rm <cls>                # ./pgsql-rm.yml -l <cls>

主从切换

您可以使用 patroni 命令执行 PostgreSQL 集群主从切换。

pg switchover <cls>   # 交互模式,您可以使用以下选项跳过
pg switchover --leader pg-test-1 --candidate=pg-test-2 --scheduled=now --force pg-test

备份集群

要使用 pgBackRest 创建备份,以本地数据库超级用户身份运行:

pg-backup                         # 进行 PostgreSQL 基础备份
pg-backup full                    # 进行完整备份
pg-backup diff                    # 进行差异备份
pg-backup incr                    # 进行增量备份
pb info                           # 检查备份信息

详情请查看 备份PITR


恢复集群

要将集群恢复到之前的时间点(PITR),以本地数据库超级用户身份运行:

pg-pitr -i                              # 恢复到最新备份完成的时间(不常用)
pg-pitr --time="2022-12-30 14:44:44+08" # 恢复到特定时间点(在删除数据库、删除表的情况下)
pg-pitr --name="my-restore-point"       # 恢复到由 pg_create_restore_point 创建的命名恢复点
pg-pitr --lsn="0/7C82CB8" -X            # 恢复到 LSN 之前
pg-pitr --xid="1234567" -X -P           # 恢复到特定事务 ID 之前,然后提升
pg-pitr --backup=latest                 # 恢复到最新备份集
pg-pitr --backup=20221108-105325        # 恢复到特定备份集,可通过 pgbackrest info 检查

然后按照指导向导操作,详情请查看备份和 PITR


添加软件包

要添加更新版本的 RPM 软件包,您必须将它们添加到 repo_packagesrepo_url_packages

然后使用 ./infra.yml -t repo_build 子任务在基础设施节点上重建仓库,然后您可以使用 ansible 模块 package 安装这些软件包:

ansible pg-test -b -m package -a "name=pg_cron_15,topn_15,pg_stat_monitor_15*"  # 安装一些软件包

安装扩展

如果您想在 PostgreSQL 集群上安装扩展,将它们添加到 pg_extensions 并确保它们被安装:

./pgsql.yml -t pg_ext     # 安装扩展

一些扩展需要在 shared_preload_libraries 中加载,您可以将它们添加到 pg_libs,或 配置 现有集群。

最后,在集群主实例上执行 CREATE EXTENSION <extname>; 来安装它。

详情请查看 PGSQL 扩展:安装


小版本升级

要执行小版本的服务器版本升级/降级,您必须首先将软件包 添加 到 yum/apt 仓库。

然后从所有从库执行滚动升级/降级,然后切换集群以升级主库。

ansible <cls> -b -a "yum upgrade/downgrade -y <pkg>"    # 升级/降级软件包
pg restart --force <cls>                                # 重启集群

大版本升级

实现大版本升级的最简单方法是使用新版本创建新集群,然后使用逻辑复制和蓝绿部署进行 迁移

您也可以执行就地大版本升级,但不建议这样做,特别是当安装了某些扩展时。但这是可能的。

假设您想将 PostgreSQL 14 升级到 15,您必须将软件包 添加 到 yum/apt 仓库,并保证扩展也具有完全相同的版本。

./pgsql.yml -t pg_pkg -e pg_version=15                         # 为 PostgreSQL 15 安装软件包
sudo su - postgres; mkdir -p /data/postgres/pg-meta-15/data/   # 为 15 准备目录
pg_upgrade -b /usr/pgsql-14/bin/ -B /usr/pgsql-15/bin/ -d /data/postgres/pg-meta-14/data/ -D /data/postgres/pg-meta-15/data/ -v -c # 预检
pg_upgrade -b /usr/pgsql-14/bin/ -B /usr/pgsql-15/bin/ -d /data/postgres/pg-meta-14/data/ -D /data/postgres/pg-meta-15/data/ --link -j8 -v -c
rm -rf /usr/pgsql; ln -s /usr/pgsql-15 /usr/pgsql;             # 修复二进制链接
mv /data/postgres/pg-meta-14 /data/postgres/pg-meta-15         # 重命名数据目录
rm -rf /pg; ln -s /data/postgres/pg-meta-15 /pg                # 修复数据目录链接

4.1 - 参数优化

调整 postgres 参数

Pigsty 默认提供了四套场景化参数模板,可以通过 pg_conf 参数指定并使用。

  • tiny.yml:为小节点、虚拟机、小型演示优化(1-8核,1-16GB)
  • oltp.yml:为OLTP工作负载和延迟敏感应用优化(4C8GB+)(默认模板)
  • olap.yml:为OLAP工作负载和吞吐量优化(4C8G+)
  • crit.yml:为数据一致性和关键应用优化(4C8G+)

Pigsty 会针对这四种默认场景,采取不同的参数优化策略,如下所示:


内存参数调整

Pigsty 默认会检测系统的内存大小,并以此为依据设定最大连接数量与内存相关参数。

默认情况下,Pigsty 使用 25% 的内存作为 PostgreSQL 共享缓冲区,剩余的 75% 作为操作系统缓存。

默认情况下,如果用户没有设置一个 pg_max_conn 最大连接数,Pigsty 会根据以下规则使用默认值:

  • oltp: 500 (pgbouncer) / 1000 (postgres)
  • crit: 500 (pgbouncer) / 1000 (postgres)
  • tiny: 300
  • olap: 300

其中对于 OLTP 与 CRIT 模版来说,如果服务没有指向 pgbouncer 连接池,而是直接连接 postgres 数据库,最大连接会翻倍至 1000 条。

决定最大连接数后,work_mem 会根据共享内存数量 / 最大连接数计算得到,并限定在 64MB ~ 1GB 的范围内。

{% if pg_max_conn != 'auto' and pg_max_conn|int >= 20 %}{% set pg_max_connections = pg_max_conn|int %}{% else %}{% if pg_default_service_dest|default('postgres') == 'pgbouncer' %}{% set pg_max_connections = 500 %}{% else %}{% set pg_max_connections = 1000 %}{% endif %}{% endif %}
{% set pg_max_prepared_transactions = pg_max_connections if 'citus' in pg_libs else 0 %}
{% set pg_max_locks_per_transaction = (2 * pg_max_connections)|int if 'citus' in pg_libs or 'timescaledb' in pg_libs else pg_max_connections %}
{% set pg_shared_buffers = (node_mem_mb|int * pg_shared_buffer_ratio|float) | round(0, 'ceil') | int %}
{% set pg_maintenance_mem = (pg_shared_buffers|int * 0.25)|round(0, 'ceil')|int %}
{% set pg_effective_cache_size = node_mem_mb|int - pg_shared_buffers|int  %}
{% set pg_workmem =  ([ ([ (pg_shared_buffers / pg_max_connections)|round(0,'floor')|int , 64 ])|max|int , 1024])|min|int %}

CPU参数调整

在 PostgreSQL 中,有 4 个与并行查询相关的重要参数,Pigsty 会自动根据当前系统的 CPU 核数进行参数优化。 在所有策略中,总并行进程数量(总预算)通常设置为 CPU 核数 + 8,且保底为 16 个,从而为逻辑复制与扩展预留足够的后台 worker 数量,OLAP 和 TINY 模板根据场景略有不同。

OLTP 设置逻辑 范围限制
max_worker_processes max(100% CPU + 8, 16) 核数 + 4,保底 12,
max_parallel_workers max(ceil(50% CPU), 2) 1/2 CPU 上取整,最少两个
max_parallel_maintenance_workers max(ceil(33% CPU), 2) 1/3 CPU 上取整,最少两个
max_parallel_workers_per_gather min(max(ceil(20% CPU), 2),8) 1/5 CPU 下取整,最少两个,最多 8 个
OLAP 设置逻辑 范围限制
max_worker_processes max(100% CPU + 12, 20) 核数 + 12,保底 20,
max_parallel_workers max(ceil(80% CPU, 2)) 4/5 CPU 上取整,最少两个
max_parallel_maintenance_workers max(ceil(33% CPU), 2) 1/3 CPU 上取整,最少两个
max_parallel_workers_per_gather max(floor(50% CPU), 2) 1/2 CPU 上取整,最少两个
CRIT 设置逻辑 范围限制
max_worker_processes max(100% CPU + 8, 16) 核数 + 8,保底 16,
max_parallel_workers max(ceil(50% CPU), 2) 1/2 CPU 上取整,最少两个
max_parallel_maintenance_workers max(ceil(33% CPU), 2) 1/3 CPU 上取整,最少两个
max_parallel_workers_per_gather 0, 按需启用
TINY 设置逻辑 范围限制
max_worker_processes max(100% CPU + 4, 12) 核数 + 4,保底 12,
max_parallel_workers max(ceil(50% CPU) 1) 50% CPU 下取整,最少1个
max_parallel_maintenance_workers max(ceil(33% CPU), 1) 33% CPU 下取整,最少1个
max_parallel_workers_per_gather 0, 按需启用

请注意,CRIT 和 TINY 模板直接通过设置 max_parallel_workers_per_gather = 0 关闭了并行查询。 用户可以按需在需要时设置此参数以启用并行查询。

OLTP 和 CRIT 模板都额外设置了以下参数,将并行查询的 Cost x 2,以降低使用并行查询的倾向。

parallel_setup_cost: 2000           # double from 100 to increase parallel cost
parallel_tuple_cost: 0.2            # double from 0.1 to increase parallel cost
min_parallel_table_scan_size: 16MB  # double from 8MB to increase parallel cost
min_parallel_index_scan_size: 1024  # double from 512 to increase parallel cost

请注意 max_worker_processes 参数的调整必须在重启后才能生效。此外,当从库的本参数配置值高于主库时,从库将无法启动。 此参数必须通过 patroni 配置管理进行调整,该参数由 Patroni 管理,用于确保主从配置一致,避免在故障切换时新从库无法启动。


存储空间参数

Pigsty 默认检测 /data/postgres 主数据目录所在磁盘的总空间,并以此作为依据指定下列参数:

min_wal_size: {{ ([pg_size_twentieth, 200])|min }}GB                  # 1/20 disk size, max 200GB
max_wal_size: {{ ([pg_size_twentieth * 4, 2000])|min }}GB             # 2/10 disk size, max 2000GB
max_slot_wal_keep_size: {{ ([pg_size_twentieth * 6, 3000])|min }}GB   # 3/10 disk size, max 3000GB
temp_file_limit: {{ ([pg_size_twentieth, 200])|min }}GB               # 1/20 of disk size, max 200GB
  • temp_file_limit 默认为磁盘空间的 5%,封顶不超过 200GB。
  • min_wal_size 默认为磁盘空间的 5%,封顶不超过 200GB。
  • max_wal_size 默认为磁盘空间的 20%,封顶不超过 2TB。
  • max_slot_wal_keep_size 默认为磁盘空间的 30%,封顶不超过 3TB。

作为特例, OLAP 模板允许 20% 的 temp_file_limit ,封顶不超过 2TB

4.2 - 维护保养

常见系统维护任务

要确保 Pigsty 与 PostgreSQL 集群健康稳定运行,需要进行一些例行维护保养工作。


定期查阅监控

Pigsty 提供了开箱即用的监控平台,我们建议您每天浏览一次监控大盘,关注系统状态。 极端情况下,我们建议您每周至少查阅一次监控,关注出现的告警事件,这样可以提前规避绝大多数故障与问题。

这里列举了 Pigsty 中预先定义的 告警规则 列表。


故障切换善后

Pigsty 的高可用架构允许 PostgreSQL 集群自动进行主从切换,这意味着运维与 DBA 无需即时介入与响应。 然而用户仍然需要在合适的时机(例如第二天工作日)进行以下善后工作,包括:

  • 调查并确认故障出现的原因,避免再次出现
  • 视情况恢复集群原本的主从拓扑,或者修改配置清单以匹配新的主从状态。
  • 通过 bin/pgsql-svc 刷新负载均衡器配置,更新服务的路由状态
  • 通过 bin/pgsql-hba 刷新集群的 HBA 规则,避免主从特定的规则漂移
  • 如果有必要,使用 bin/pgsql-rm 移除故障服务器,并通过 bin/pgsql-add 扩容一台新从库

表膨胀治理

长时间运行的 PostgreSQL 会出现 “表膨胀” / “索引膨胀” 现象, 导致系统性能劣化。

定期使用 pg_repack 对表与索引进行在线重建,有助于维护 PostgreSQL 的良好性能表现。 Pigsty 已经默认在所有数据库中安装并启用了此扩展,因此您可以直接使用。

您可以通过 Pigsty 的 PGCAT Database - Table Bloat 面板, 确认数据库中的表膨胀情况与索引膨胀情况。并选择膨胀率较高(膨胀率高于 50% 的较大表)的表与索引,使用 pg_repack 进行在线重整:

pg_repack dbname -t schema.table

重整期间不会影响正常读写,但重整完毕之后的 切换瞬间 需要获取表上的 AccessExclusive 锁阻塞一切访问。 因此对于高吞吐量业务,建议在业务低峰期或者维护窗口进行。更多细节,请参考:关系膨胀的治理


VACUUM FREEZE

冻结过期事务ID(VACUUM FREEZE)是PostgreSQL重要的维护任务,用于防止事务ID (XID) 用尽导致停机。 尽管 PostgreSQL 已经提供了自动垃圾回收(AutoVacuum)机制,然而对于高标准的生产环境, 我们依然建议结合自动和手动两种方式,定期执行全库级别的 VACUUM FREEZE ,以确保 XID 安全。

4.3 - 故障排查

常见故障与分析排查思路

本文档列举了 PostgreSQL 和 Pigsty 中可能出现的故障,以及定位,处理,分析问题的 SOP。


磁盘空间写满

磁盘空间写满是最常见的故障类型。

现象

当数据库所在磁盘空间耗尽时,PostgreSQL 将无法正常工作,可能出现以下现象:数据库日志反复报错“no space left on device”(磁盘空间不足), 新数据无法写入,甚至 PostgreSQL 可能触发 PANIC 强制关闭。

Pigsty 带有 NodeFsSpaceFull 告警规则,当文件系统可用空间不足 10% 时触发告警。 使用监控系统 NODE Instance 面板查阅 FS 指标面板定位问题。

诊断

您也可以登录数据库节点,使用 df -h 查看各挂载盘符使用率,确定哪个分区被写满。 对于数据库节点,重点检查以下目录及其大小,以判断是哪个类别的文件占满了空间:

  • 数据目录/pg/data/base):存放表和索引的数据文件,大量写入与临时文件需要关注
  • WAL目录(如 pg/data/pg_wal):存放 PG WAL,WAL 堆积/复制槽保留是常见的磁盘写满原因。
  • 数据库日志目录(如 pg/log):如果 PG 日志未及时轮转写大量报错写入,也可能占用大量空间。
  • 本地备份目录(如 data/backups):使用 pgBackRest 等在本机保存备份时,也有可能撑满磁盘。

如果问题出在 Pigsty 管理节点或监控节点,还需考虑:

  • 监控数据:Prometheus 的时序指标和 Loki 日志存储都会占用磁盘,可检查保留策略。
  • 对象存储数据:Pigsty 集成的 MinIO 对象存储可能会被用于 PG 备份保存。

明确占用空间最大的目录后,可进一步使用 du -sh <目录> 深入查找特定大型文件或子目录。

处理

磁盘写满属于紧急问题,需立即采取措施释放空间并保证数据库继续运行。 当数据盘并未与系统盘区分时,写满磁盘可能导致 Shell 命令无法执行。这种情况下,可以删除 /pg/dummy 占位文件,释放少量应急空间以便 shell 命令恢复正常。 如果数据库由于 pg_wal 写满已经宕机,清理空间后需要重启数据库服务并仔细检查数据完整性。


事务号回卷

PostgreSQL 循环使用 32 位事务ID (XID),耗尽时会出现“事务号回卷”故障(XID Wraparound)。

现象

第一阶段的典型征兆是 PGSQL Persist - Age Usage 面板年龄饱和度进入警告区域。 数据库日志开始出现:WARNING: database "postgres" must be vacuumed within xxxxxxxx transactions 字样的信息。

若问题持续恶化,PostgreSQL 会进入保护模式:当剩余事务ID不到约100万时数据库切换为只读模式;达到上限约21亿(2^31)时则拒绝任何新事务并迫使服务器停机以避免数据错误。

诊断

PostgreSQL 与 Pigsty 默认启用自动垃圾回收(AutoVacuum),因此此类故障出现通常有更深层次的根因。 常见的原因包括:超长事务(SAGE),Autovacuum 配置失当,复制槽阻塞,资源不足,存储引擎/扩展BUG,磁盘坏快。

首先定位年龄最大的数据库,然后可通过 Pigsty PGCAT Database - Tables 面板来确认表的年龄分布。 同时查阅数据库错误日志,通常可以找到定位根因的线索。

处理

  1. 立即冻结老事务:如果数据库尚未进入只读保护状态,立刻对受影响的库执行一次手动 VACUUM FREEZE。可以从老化最严重的表开始逐个冻结,而不是整库一起做,以加快效果。使用超级用户连接数据库,针对识别出的 relfrozenxid 最大的表运行 VACUUM FREEZE 表名;,优先冻结那些XID年龄最大的表元组。这样可以迅速回收大量事务ID空间。
  2. 单用户模式救援:如果数据库已经拒绝写入或宕机保护,此时需要启动数据库到单用户模式执行冻结操作。在单用户模式下运行 VACUUM FREEZE database_name; 对整个数据库进行冻结清理。完成后再以多用户模式重启数据库。这样做可以解除回卷锁定,让数据库重新可写。需要注意在单用户模式下操作要非常谨慎,并确保有足够的事务ID余量完成冻结。
  3. 备用节点接管:在某些复杂场景(例如遭遇硬件问题导致 vacuum 无法完成),可考虑提升集群中的只读备节点为主,以获取一个相对干净的环境来处理冻结。例如主库因坏块导致无法 vacuum,此时可以手动Failover提升备库为新的主库,再对其进行紧急 vacuum freeze。确保新主库已冻结老事务后,再将负载切回来。

连接耗尽

PostgreSQL 有一个最大连接数配置 (max_connections),当客户端连接数超过此上限时,新的连接请求将被拒绝。典型现象是在应用端看到数据库无法连接,并报出类似 FATAL: remaining connection slots are reserved for non-replication superuser connectionstoo many clients already 的错误。 这表示普通连接数已用完,仅剩下保留给超管或复制的槽位

诊断

连接耗尽通常由客户端大量并发请求引起。您可以通过 PGCAT Instance / PGCAT Database / PGCAT Locks 直接查阅数据库当前的活跃会话。 并判断是什么样的查询填满了系统,并进行进一步的处理。特别需要关注是否存在大量 Idle in Transaction 状态的连接以及长时间运行的事务(以及慢查询)。

处理

杀查询:对于已经耗尽导致业务受阻的情况,通常立即使用 pg_terminate_backend(pid) 进行紧急降压。 对于使用连接池的情况,则可以调整连接池大小参数,并执行 reload 重载的方式减少数据库层面的连接数量。

您也可以修改 max_connections 参数为更大的值,但本参数需要重启数据库后才能生效。


etcd 配额写满

etcd 配额写满将导致 PG 高可用控制面失效,无法进行配置变更。

诊断

Pigsty 在实现高可用时使用 etcd 作为分布式配置存储(DCS),etcd 自身有一个存储配额(默认约为2GB)。 当 etcd 存储用量达到配额上限时,etcd 将拒绝写入操作,报错 “etcdserver: mvcc: database space exceeded”。在这种情况下,Patroni 无法向 etcd 写入心跳或更新配置,从而导致集群管理功能失效。

解决

在 Pigsty v2.0.0 - v2.5.1 之间的版本默认受此问题影响。Pigsty v2.6.0 为部署的 etcd 新增了自动压实的配置项,如果您仅将其用于 PG 高可用租约,则常规用例下不会再有此问题。


有缺陷的存储引擎

目前,TimescaleDB 的试验性存储引擎 Hypercore 被证实存在缺陷,已经出现 VACUUM 无法回收出现 XID 回卷故障的案例。 请使用该功能的用户及时迁移至 PostgreSQL 原生表或者 TimescaleDB 默认引擎

详细介绍:《PG新存储引擎故障案例

4.4 - 误删处理

处理误删数据,误删表,误删数据库

误删数据

如果是小批量 DELETE 误操作,可以考虑使用 pg_surgery 或者 pg_dirtyread 扩展进行原地手术恢复。

-- 立即关闭此表上的 Auto Vacuum 并中止 Auto Vacuum 本表的 worker 进程
ALTER TABLE public.some_table SET (autovacuum_enabled = off, toast.autovacuum_enabled = off);

CREATE EXTENSION pg_dirtyread;
SELECT * FROM pg_dirtyread('tablename') AS t(col1 type1, col2 type2, ...);

如果被删除的数据已经被 VACUUM 回收,那么使用通用的误删处理流程。

误删对象

当出现 DROP/DELETE 类误操作,通常按照以下流程决定恢复方案。

  1. 确认此数据是否可以通过业务系统或其他数据系统找回,如果可以,直接从业务侧修复。
  2. 确认是否有延迟从库,如果有,推进延迟从库至误删时间点,查询出来恢复。
  3. 如果数据已经确认删除,确认备份信息,恢复范围是否覆盖误删时间点,如果覆盖,开始 PITR
  4. 确认是整集群原地 PITR 回滚,还是新开服务器重放,还是用从库来重放,并执行恢复策略

误删集群

如果出现整个数据库集群通过 Pigsty 管理命令被误删的情况,例如错误的执行 pgsql-rm.yml 剧本或 bin/pgsql-rm 命令。 除非您指定了 pg_rm_backup 参数为 false,否则备份会与数据库集群一起被删除。

说明

警告:在这种情况,您的数据将无法找回!请务必三思而后行!

建议:对于生产环境,您可以在配置清单中全局配置此参数为 false,在移除集群时保留备份。

5 - 剧本

Pigsty 提供的 Ansible 剧本

如何使用 Ansible playbook 管理 PostgreSQL 集群

Pigsty 有一系列 PostgreSQL playbook:


安全防护

如果您担心意外删除 PostgreSQL 集群,可以启用安全防护功能。

pg_safeguard 参数设置为 true 将阻止 pgsql-rm.yml 运行。

在 Pigsty v3.5 之前,pgsql.yml 可能会误删数据库,请谨慎使用!

Pigsty v3.5 从 pgsql.yml 中删除了 pg 清除逻辑, 所以现在删除 PostgreSQL 的唯一方法是运行 pgsql-rm.yml


pgsql.yml

pgsql.yml 用于初始化 HA PostgreSQL 集群或添加新副本。

asciicast

此 playbook 包含以下子任务

pg_install              : # 安装 postgres 包和扩展
  - pg_dbsu             : # 为 postgres dbsu 设置操作系统用户 sudo
    - pg_dbsu_create    : # 交换 dbsu ssh 密钥
    - pg_dbsu_sudo      : # 交换 dbsu ssh 密钥
    - pg_ssh            : # 交换 dbsu ssh 密钥
  - pg_pkg              : # 安装 postgres 包
    - pg_ext            : # 安装 postgres 扩展包
  - pg_link             : # 将 pgsql 版本 bin 链接到 /usr/pgsql
  - pg_path             : # 将 pgsql bin 添加到系统路径
  - pg_dir              : # 创建 postgres 目录并设置 fhs
  - pg_bin              : # 同步 /pg/bin 脚本
  - pg_alias            : # 写入 pgsql/psql 别名
  - pg_dummy            : # 创建虚拟占位符文件
pg_bootstrap            : # 引导 postgres 集群
  - pg_config           : # 生成 postgres 配置
    - pg_conf           : # 生成 patroni 配置
    - pg_key            : # 生成 pgsodium 密钥
  - pg_cert             : # 为 postgres 颁发证书
    - pg_cert_private   : # 检查 pg 私钥是否存在
    - pg_cert_issue     : # 签署 pg 服务器证书
    - pg_cert_copy      : # 将密钥和证书复制到 pg 节点
  - pg_launch           : # 启动 patroni 主实例和副本(patroni)
    - pg_watchdog       : # 为 postgres 授予看门狗权限
    - pg_primary        : # 启动 patroni/postgres 主实例
    - pg_init           : # 使用角色/模板初始化 pg 集群
    - pg_pass           : # 将 .pgpass 文件写入 pg 主目录
    - pg_replica        : # 启动 patroni/postgres 副本
    - pg_hba            : # 生成 pg HBA 规则
    - patroni_reload    : # 重新加载 patroni 配置
    - pg_patroni        : # 如有必要暂停或删除 patroni
pg_provision            : # 置备 postgres 业务用户和数据库
 - pg_user              : # 置备 postgres 业务用户
    - pg_user_config    : # 渲染创建用户 sql
    - pg_user_create    : # 在 postgres 上创建用户
 - pg_db                : # 置备 postgres 业务数据库
    - pg_db_config      : # 渲染创建数据库 sql
    - pg_db_create      : # 在 postgres 上创建数据库
pg_backup               : # 初始化 postgres PITR 备份
  - pgbackrest          : # 为备份设置 pgbackrest
    - pgbackrest_config : # 生成 pgbackrest 配置
    - pgbackrest_init   : # 初始化 pgbackrest 仓库
    - pgbackrest_backup : # 引导后进行初始备份
pg_access               : # 初始化 postgres 服务访问、池、dns、vip、svc
 - pgbouncer            : # 部署 pgbouncer sidecar 与 postgres
   - pgbouncer_dir      : # 创建 pgbouncer 目录
   - pgbouncer_config   : # 生成 pgbouncer 配置
     -  pgbouncer_hba   : # 生成 pgbouncer hba 配置
     -  pgbouncer_user  : # 生成 pgbouncer 用户列表
   -  pgbouncer_launch  : # 启动 pgbouncer 池化服务
   -  pgbouncer_reload  : # 重新加载 pgbouncer 配置
 - pg_vip               : # 使用 vip-manager 将 vip 绑定到 pgsql 主实例
   - pg_vip_config      : # 生成 vip-manager 配置
   - pg_vip_launch      : # 启动 vip-manager 以绑定 vip
 - pg_dns               : # 将 dns 名称注册到基础设施 dnsmasq
   - pg_dns_ins         : # 注册 pg 实例名称
   - pg_dns_cls         : # 注册 pg 集群名称
 - pg_service           : # 使用 haproxy 暴露 pgsql 服务
   - pg_service_config  : # 生成 pg 服务的本地 haproxy 配置
   - pg_service_reload  : # 使用 haproxy 暴露 postgres 服务
pg_monitor              : # 设置 pgsql 监控并注册到基础设施
  - pg_exporter         : # 配置和启动 pg_exporter
  - pgbouncer_exporter  : # 配置和启动 pgbouncer_exporter
  - pgbackrest_exporter : # 配置和启动 pgbackrest_exporter
  - register_prometheus : # 将 pg 注册为 prometheus 监控目标
  - register_grafana    : # 将 pg 数据库注册为 grafana 数据源

使用此 playbook 的管理任务

先初始化主实例再初始化副本
  • 副本初始化后,您可能需要运行重新加载 HBA 规则追加副本
  • 包装脚本 pgsql-add 会执行此操作,详情请查看 SOP:添加实例
  • 如果您在整个集群上运行此操作,则无需担心此问题。
在备用集群之前初始化上游集群
  • 如果您正在初始化备用集群,您应该确保上游集群已经初始化。

pgsql-rm.yml

playbook pgsql-rm.yml 可以删除 PostgreSQL 集群,或从集群中删除特定副本。

asciicast

此 playbook 包含以下子任务

pg_monitor               : # 删除 prometheus、grafana、nginx 中的注册
  - prometheus           : # 从 prometheus 中删除监控目标
  - grafana              : # 从 grafana 中删除数据源
  - pg_exporter          : # 删除 pg_exporter(postgres 监控)
  - pgbouncer_exporter   : # 删除 pgbouncer_exporter(pgbouncer 监控)
  - pgbackrest_exporter  : # 删除 pgbackrest_exporter(pgbackrest 监控)
pg_access                : # 删除 pg 服务访问
  - dns                  : # 删除 pg dns 记录
  - vip                  : # 删除 vip-manager
  - pg_service           : # 从 haproxy 删除 pg 服务
  - pgbouncer            : # 删除 pgbouncer 连接中间件
postgres                 : # 删除 postgres 实例
  - pg_replica           : # 删除所有副本
  - pg_primary           : # 删除主实例
  - pg_meta              : # 从 dcs 删除元数据
pg_backup                : # 删除备份仓库(使用 `pg_rm_backup=false` 禁用)
pg_data                  : # 删除 postgres 数据(使用 `pg_rm_data=false` 禁用)
pg_pkg                   : # 卸载 pg 包(使用 `pg_rm_pkg=false` 禁用)
 - pg_ext                : # 单独卸载 postgres 扩展

一些参数可以影响此 playbook 的行为:

# 删除 pgsql 集群 `pg-test`
./pgsql-rm.yml                          # 删除所有 postgres 集群(非常危险)
./pgsql-rm.yml -l pg-test               # 删除集群 `pg-test`
./pgsql-rm.yml -e pg_safeguard=false    # 强制禁用安全防护,强制运行此 playbook
./pgsql-rm.yml -e pg_rm_data=false        # 保留数据目录,不要删除它(保留数据)
./pgsql-rm.yml -e pg_rm_backup=false      # 默认不清除 postgres 数据(保留备份仓库)
./pgsql-rm.yml -e pg_rm_pkg=false     # 默认不卸载 postgres 包(保留包)

使用此 playbook 的管理任务

关于此 playbook 的一些注意事项

当仍有副本时,不要直接在单个集群主实例上运行此 playbook
  • 否则,其余副本将触发自动故障转移。
  • 如果您在删除主实例之前删除所有副本,就不会有问题。
  • 如果您在整个集群上运行此操作,则无需担心此问题。
从集群中删除副本后重新加载服务
  • 它是一个死服务器,所以不会影响集群服务。
  • 但您应该及时重新加载服务以确保环境与配置清单之间的一致性。
  • 删除副本时,它仍然在 haproxy 负载均衡器的配置文件中。

pgsql-db.yml

剧本 pgsql-db.yml 可以向现有 PostgreSQL 集群添加新业务数据库。

查看管理 SOP:创建数据库


pgsql-user.yml

剧本 pgsql-user.yml 可以向现有 PostgreSQL 集群添加新业务用户。

查看管理 SOP:创建用户


pgsql-pitr.yml

剧本 pgsql-pitr.yml 可以在现有 PostgreSQL 集群上执行 时间点恢复 (PITR)。

查看管理 SOP: 备份恢复


pgsql-pitr.yml

剧本 pgsql-pitr.yml 可以向现有 PostgreSQL 集群添加新业务用户。

查看管理 SOP:时间点恢复


pgsql-monitor.yml

剧本 pgsql-monitor.yml 可以将现有/远程 postgres / RDS 实例纳入监控。

查看管理 SOP:监控 Postgres


pgsql-migration.yml

剧本 pgsql-migration.yml 可以为现有 PostgreSQL 集群生成迁移手册和脚本。

查看管理 SOP:数据库迁移

6 - 监控

监控现有 PostgreSQL 或 RDS

概述

Pigsty 使用现代可观测性栈进行 PostgreSQL 监控:

  • Grafana 用于指标可视化和 PostgreSQL 数据源。
  • Prometheus 用于 PostgreSQL / Pgbouncer / Patroni / HAProxy / Node 指标
  • Loki 用于 PostgreSQL / Pgbouncer / Patroni / pgBackRest 日志
  • 开箱即用的 PostgreSQL 和其他一切的仪表板

指标

PostgreSQL 的指标由收集器文件定义:pg_exporter.yml。Prometheus 记录规则和告警评估将进一步处理它:files/prometheus/rules/pgsql.yml

有三个身份标签:clsinsip,它们将附加到所有指标和日志。节点和 haproxy 将尝试重用相同的身份以提供一致的指标和日志。

{ cls: pg-meta, ins: pg-meta-1, ip: 10.10.10.10 }
{ cls: pg-meta, ins: pg-test-1, ip: 10.10.10.11 }
{ cls: pg-meta, ins: pg-test-2, ip: 10.10.10.12 }
{ cls: pg-meta, ins: pg-test-3, ip: 10.10.10.13 }

日志

PostgreSQL 相关日志默认由 promtail 收集并发送到基础设施节点上的 Loki。

目标

Prometheus 监控目标在 /etc/prometheus/targets/pgsql/ 下的静态文件中定义。每个实例都有一个对应的文件。以 pg-meta-1 为例:

# pg-meta-1 [primary] @ 10.10.10.10
- labels: { cls: pg-meta, ins: pg-meta-1, ip: 10.10.10.10 }
  targets:
    - 10.10.10.10:9630    # <--- PostgreSQL 指标的 pg_exporter
    - 10.10.10.10:9631    # <--- Pgbouncer 指标的 pg_exporter
    - 10.10.10.10:8008    # <--- patroni 指标

当全局标志 patroni_ssl_enabled 设置时,patroni 目标将作为 /etc/prometheus/targets/patroni/<ins>.yml 管理,因为它需要不同的抓取端点(https)。

当集群被 bin/pgsql-rmpgsql-rm.yml 删除时,Prometheus 监控目标将被删除。您可以使用 playbook 子任务,或手动删除它们:

bin/pgmon-rm <ins>      # 从所有基础设施节点删除 prometheus 目标

远程 RDS 目标作为 /etc/prometheus/targets/pgrds/<cls>.yml 管理。它将由 pgsql-monitor.yml playbook 或 bin/pgmon-add 脚本创建。


监控模式

在 Pigsty 中有三种监控 PostgreSQL 实例的方式:

项目 \ 级别 L1 L2 L3
名称 远程数据库服务 现有部署 完全托管部署
简称 RDS MANAGED FULL
场景 仅连接字符串 URL 可 SSH sudo 由 Pigsty 创建的实例
PGCAT 功能 ✅ 完全可用 ✅ 完全可用 ✅ 完全可用
PGSQL 功能 ✅ 仅 PG 指标 ✅ PG 和节点指标 ✅ 完全支持
连接池指标 ❌ 不可用 ⚠️ 可选 ✅ 预配置
负载均衡器指标 ❌ 不可用 ⚠️ 可选 ✅ 预配置
PGLOG 功能 ❌ 不可用 ⚠️ 可选 ⚠️ 可选
PG Exporter ⚠️ 在基础设施节点上 ✅ 在数据库节点上 ✅ 在数据库节点上
Node Exporter ❌ 未部署 ✅ 在数据库节点上 ✅ 在数据库节点上
对数据库节点的入侵 ✅ 非入侵 ⚠️ 安装导出器 ⚠️ 完全由 Pigsty 管理
实例已存在 ✅ 是 ✅ 是 ⚠️ 由 Pigsty 创建
监控用户和视图 ⚠️ 手动设置 ⚠️ 手动设置 ✅ 自动配置
部署使用 Playbook bin/pgmon-add <cls> pgsql.ym/node.yml 的子任务 pgsql.yml
所需权限 来自基础设施节点的可连接 PGURL 数据库节点 SSH 和 sudo 权限 数据库节点 SSH 和 sudo 权限
功能概述 PGCAT + PGRDS 大部分功能 完整功能

监控现有集群

假设目标数据库节点可以由 Pigsty 管理(可通过 SSH 访问且 sudo 可用)。在这种情况下,您可以使用 pgsql.yml playbook 中的 pg_exporter 任务,以与标准部署相同的方式在目标节点上部署监控组件 PG Exporter。

您还可以使用同一 playbook 的 pgbouncerpgbouncer_exporter 任务在现有实例节点上部署连接池及其监控。此外,您可以使用 node.yml playbook 的 node_exporterhaproxypromtail 任务部署主机监控、负载均衡和日志收集组件,实现与原生 Pigsty 集群相似的用户体验。

现有集群的定义方法与 Pigsty 管理的普通集群非常相似。有选择地运行 pgsql.yml playbook 中的某些任务,而不是运行整个 playbook。

./node.yml  -l <cls> -t node_repo,node_pkg           # 在主机节点上为基础设施节点添加 YUM 源并安装包。
./node.yml  -l <cls> -t node_exporter,node_register  # 配置主机监控并添加到 Prometheus。
./node.yml  -l <cls> -t promtail                     # 配置主机日志收集并发送到 Loki。
./pgsql.yml -l <cls> -t pg_exporter,pg_register      # 配置 PostgreSQL 监控并注册到 Prometheus/Grafana。

由于目标数据库集群已经存在,您必须在目标数据库集群上手动设置监控用户、架构和扩展


监控 RDS

如果您只能通过 PGURL(数据库连接字符串)访问目标数据库,您可以参考这里的说明进行配置。在此模式下,Pigsty 在基础设施节点上部署相应的 PG Exporter 以从远程数据库获取指标,如下所示:

------ infra ------
|                 |
|   prometheus    |            v---- pg-foo-1 ----v
|       ^         |  metrics   |         ^        |
|   pg_exporter <-|------------|----  postgres    |
|   (port: 20001) |            | 10.10.10.10:5432 |
|       ^         |            ^------------------^
|       ^         |                      ^
|       ^         |            v---- pg-foo-2 ----v
|       ^         |  metrics   |         ^        |
|   pg_exporter <-|------------|----  postgres    |
|   (port: 20002) |            | 10.10.10.11:5433 |
-------------------            ^------------------^

监控系统将不再有主机/池化器/负载均衡器指标。但 PostgreSQL 指标和目录信息仍然可用。Pigsty 为此有两个专用仪表板:PGRDS 集群PGRDS 实例。概览和数据库级别仪表板被重用。由于 Pigsty 无法管理您的 RDS,您必须提前在目标数据库上设置监控

下面,我们使用沙箱环境作为示例:现在我们假设 pg-meta 集群是要监控的 RDS 实例 pg-foo-1pg-test 集群是要监控的 RDS 集群 pg-bar

  1. 在目标上创建监控架构、用户和权限。详情请参考监控设置

  2. 在配置列表中声明集群。例如,假设我们想要监控"远程" pg-metapg-test 集群:

infra:            # 基础设施集群,用于代理、监控、告警等。
  hosts: { 10.10.10.10: { infra_seq: 1 } }
  vars:           # 在 'infra' 组上为远程 postgres RDS 安装 pg_exporter
    pg_exporters: # 在这里列出所有远程实例,为每个分配一个唯一的未使用本地端口
      20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 , pg_databases: [{ name: meta }] } # 将 meta 数据库注册为 Grafana 数据源

      20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.11 , pg_port: 5432 } # 几种不同的连接字符串拼接方法
      20003: { pg_cluster: pg-bar, pg_seq: 2, pg_host: 10.10.10.12 , pg_exporter_url: 'postgres://dbuser_monitor:[email protected]:5432/postgres?sslmode=disable'}
      20004: { pg_cluster: pg-bar, pg_seq: 3, pg_host: 10.10.10.13 , pg_monitor_username: dbuser_monitor, pg_monitor_password: DBUser.Monitor }

pg_databases 字段中列出的数据库将在 Grafana 中注册为 PostgreSQL 数据源,为 PGCAT 监控面板提供数据支持。如果您不想使用 PGCAT 并在 Grafana 中注册数据库,请将 pg_databases 设置为空数组或留空。

pigsty-monitor.jpg
  1. 执行命令添加监控:bin/pgmon-add <clsname>
bin/pgmon-add pg-foo  # 将 pg-foo 集群纳入监控
bin/pgmon-add pg-bar  # 将 pg-bar 集群纳入监控
  1. 要从监控中删除远程集群,使用 bin/pgmon-rm <clsname>
bin/pgmon-rm pg-foo  # 从 Pigsty 监控中删除 pg-foo
bin/pgmon-rm pg-bar  # 从 Pigsty 监控中删除 pg-bar

您可以使用更多参数来覆盖默认的 pg_exporter 选项。这里有一个使用 Pigsty 监控阿里云 RDS 和 PolarDB 的示例:


监控设置

当您想要监控现有实例时,无论是 RDS 还是自建的 PostgreSQL 实例,您都需要在目标数据库上进行一些配置,以便 Pigsty 可以访问它们。

要将外部现有的 PostgreSQL 实例纳入监控,您需要一个可以访问该实例/集群的连接字符串。任何可访问的连接字符串(业务用户、超级用户)都可以使用,但我们建议使用专用的监控用户以避免权限泄露。

  • 监控用户:默认使用的用户名是 dbuser_monitor。此用户属于 pg_monitor 组,或确保它具有必要的视图权限。
  • 监控 HBA:默认密码是 DBUser.Monitor。您需要确保 HBA 策略允许监控用户从基础设施节点访问数据库。
  • 监控架构:可选但建议为监控视图和扩展创建专用架构 monitor
  • 监控扩展:强烈建议启用内置扩展 pg_stat_statements
  • 监控视图:监控视图是可选的,但可以提供额外的指标。推荐使用。

监控用户

在目标数据库集群上创建一个监控用户。例如,Pigsty 中默认使用 dbuser_monitor

CREATE USER dbuser_monitor;                                       -- 创建监控用户
COMMENT ON ROLE dbuser_monitor IS 'system monitor user';          -- 为监控用户添加注释
GRANT pg_monitor TO dbuser_monitor;                               -- 将系统角色 pg_monitor 授予监控用户

ALTER USER dbuser_monitor PASSWORD 'DBUser.Monitor';              -- 为监控用户设置密码
ALTER USER dbuser_monitor SET log_min_duration_statement = 1000;  -- 设置此值以避免日志洪泛
ALTER USER dbuser_monitor SET search_path = monitor,public;       -- 设置此值以避免 pg_stat_statements 扩展不工作

这里的监控用户应该与 Pigsty 配置清单中的 pg_monitor_usernamepg_monitor_password 一致。


监控 HBA

您还需要配置 pg_hba.conf 以允许监控用户从基础设施/管理节点访问。

# 允许本地角色监控使用密码
local   all  dbuser_monitor                    md5
host    all  dbuser_monitor  127.0.0.1/32      md5
host    all  dbuser_monitor  <admin_ip>/32     md5
host    all  dbuser_monitor  <infra_ip>/32     md5

如果您的 RDS 不支持原始 HBA 格式,请将管理/基础设施节点 IP 添加到白名单。


监控架构

监控架构是可选的,但我们强烈推荐创建一个。

CREATE SCHEMA IF NOT EXISTS monitor;               -- 创建专用监控架构
GRANT USAGE ON SCHEMA monitor TO dbuser_monitor;   -- 允许监控用户使用此架构

监控扩展

监控扩展是可选的,但我们强烈推荐启用 pg_stat_statements 扩展。

请注意,此扩展必须列在 shared_preload_libraries 中才能生效,更改此参数需要重启数据库。

CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "monitor";

您应该在管理数据库中创建此扩展:postgres。如果您的 RDS 不授予数据库 postgresCREATE 权限,您可以在默认的 public 架构中创建该扩展:

CREATE EXTENSION IF NOT EXISTS "pg_stat_statements";
ALTER USER dbuser_monitor SET search_path = monitor,public;

只要您的监控用户可以在没有架构限定的情况下访问 pg_stat_statements 视图,就应该没问题。


监控视图

建议在所有需要监控的数据库中创建监控视图。

监控架构和视图定义

----------------------------------------------------------------------
-- 表膨胀估算:monitor.pg_table_bloat
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_table_bloat CASCADE;
CREATE OR REPLACE VIEW monitor.pg_table_bloat AS
SELECT CURRENT_CATALOG AS datname, nspname, relname , tblid , bs * tblpages AS size,
       CASE WHEN tblpages - est_tblpages_ff > 0 THEN (tblpages - est_tblpages_ff)/tblpages::FLOAT ELSE 0 END AS ratio
FROM (
         SELECT ceil( reltuples / ( (bs-page_hdr)*fillfactor/(tpl_size*100) ) ) + ceil( toasttuples / 4 ) AS est_tblpages_ff,
                tblpages, fillfactor, bs, tblid, nspname, relname, is_na
         FROM (
                  SELECT
                      ( 4 + tpl_hdr_size + tpl_data_size + (2 * ma)
                          - CASE WHEN tpl_hdr_size % ma = 0 THEN ma ELSE tpl_hdr_size % ma END
                          - CASE WHEN ceil(tpl_data_size)::INT % ma = 0 THEN ma ELSE ceil(tpl_data_size)::INT % ma END
                          ) AS tpl_size, (heappages + toastpages) AS tblpages, heappages,
                      toastpages, reltuples, toasttuples, bs, page_hdr, tblid, nspname, relname, fillfactor, is_na
                  FROM (
                           SELECT
                               tbl.oid AS tblid, ns.nspname , tbl.relname, tbl.reltuples,
                               tbl.relpages AS heappages, coalesce(toast.relpages, 0) AS toastpages,
                               coalesce(toast.reltuples, 0) AS toasttuples,
                               coalesce(substring(array_to_string(tbl.reloptions, ' ') FROM 'fillfactor=([0-9]+)')::smallint, 100) AS fillfactor,
                               current_setting('block_size')::numeric AS bs,
                               CASE WHEN version()~'mingw32' OR version()~'64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS ma,
                               24 AS page_hdr,
                               23 + CASE WHEN MAX(coalesce(s.null_frac,0)) > 0 THEN ( 7 + count(s.attname) ) / 8 ELSE 0::int END
                                   + CASE WHEN bool_or(att.attname = 'oid' and att.attnum < 0) THEN 4 ELSE 0 END AS tpl_hdr_size,
                               sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 0) ) AS tpl_data_size,
                               bool_or(att.atttypid = 'pg_catalog.name'::regtype)
                                   OR sum(CASE WHEN att.attnum > 0 THEN 1 ELSE 0 END) <> count(s.attname) AS is_na
                           FROM pg_attribute AS att
                                    JOIN pg_class AS tbl ON att.attrelid = tbl.oid
                                    JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace
                                    LEFT JOIN pg_stats AS s ON s.schemaname=ns.nspname AND s.tablename = tbl.relname AND s.inherited=false AND s.attname=att.attname
                                    LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid
                           WHERE NOT att.attisdropped AND tbl.relkind = 'r' AND nspname NOT IN ('pg_catalog','information_schema')
                           GROUP BY 1,2,3,4,5,6,7,8,9,10
                       ) AS s
              ) AS s2
     ) AS s3
WHERE NOT is_na;
COMMENT ON VIEW monitor.pg_table_bloat IS 'postgres table bloat estimate';

GRANT SELECT ON monitor.pg_table_bloat TO pg_monitor;

----------------------------------------------------------------------
-- 索引膨胀估算:monitor.pg_index_bloat
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_index_bloat CASCADE;
CREATE OR REPLACE VIEW monitor.pg_index_bloat AS
SELECT CURRENT_CATALOG AS datname, nspname, idxname AS relname, tblid, idxid, relpages::BIGINT * bs AS size,
       COALESCE((relpages - ( reltuples * (6 + ma - (CASE WHEN index_tuple_hdr % ma = 0 THEN ma ELSE index_tuple_hdr % ma END)
                                               + nulldatawidth + ma - (CASE WHEN nulldatawidth % ma = 0 THEN ma ELSE nulldatawidth % ma END))
                                  / (bs - pagehdr)::FLOAT  + 1 )), 0) / relpages::FLOAT AS ratio
FROM (
         SELECT nspname,idxname,indrelid AS tblid,indexrelid AS idxid,
                reltuples,relpages,
                current_setting('block_size')::INTEGER                                                               AS bs,
                (CASE WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END)  AS ma,
                24                                                                                                   AS pagehdr,
                (CASE WHEN max(COALESCE(pg_stats.null_frac, 0)) = 0 THEN 2 ELSE 6 END)                               AS index_tuple_hdr,
                sum((1.0 - COALESCE(pg_stats.null_frac, 0.0)) *
                    COALESCE(pg_stats.avg_width, 1024))::INTEGER                                                     AS nulldatawidth
         FROM pg_attribute
                  JOIN (
             SELECT pg_namespace.nspname,
                    ic.relname                                                   AS idxname,
                    ic.reltuples,
                    ic.relpages,
                    pg_index.indrelid,
                    pg_index.indexrelid,
                    tc.relname                                                   AS tablename,
                    regexp_split_to_table(pg_index.indkey::TEXT, ' ') :: INTEGER AS attnum,
                    pg_index.indexrelid                                          AS index_oid
             FROM pg_index
                      JOIN pg_class ic ON pg_index.indexrelid = ic.oid
                      JOIN pg_class tc ON pg_index.indrelid = tc.oid
                      JOIN pg_namespace ON pg_namespace.oid = ic.relnamespace
                      JOIN pg_am ON ic.relam = pg_am.oid
             WHERE pg_am.amname = 'btree' AND ic.relpages > 0 AND nspname NOT IN ('pg_catalog', 'information_schema')
         ) ind_atts ON pg_attribute.attrelid = ind_atts.indexrelid AND pg_attribute.attnum = ind_atts.attnum
                  JOIN pg_stats ON pg_stats.schemaname = ind_atts.nspname
             AND ((pg_stats.tablename = ind_atts.tablename AND pg_stats.attname = pg_get_indexdef(pg_attribute.attrelid, pg_attribute.attnum, TRUE))
                 OR (pg_stats.tablename = ind_atts.idxname AND pg_stats.attname = pg_attribute.attname))
         WHERE pg_attribute.attnum > 0
         GROUP BY 1, 2, 3, 4, 5, 6
     ) est;
COMMENT ON VIEW monitor.pg_index_bloat IS 'postgres index bloat estimate (btree-only)';

GRANT SELECT ON monitor.pg_index_bloat TO pg_monitor;

----------------------------------------------------------------------
-- 关系膨胀:monitor.pg_bloat
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_bloat CASCADE;
CREATE OR REPLACE VIEW monitor.pg_bloat AS
SELECT coalesce(ib.datname, tb.datname)                                                   AS datname,
       coalesce(ib.nspname, tb.nspname)                                                   AS nspname,
       coalesce(ib.tblid, tb.tblid)                                                       AS tblid,
       coalesce(tb.nspname || '.' || tb.relname, ib.nspname || '.' || ib.tblid::RegClass) AS tblname,
       tb.size                                                                            AS tbl_size,
       CASE WHEN tb.ratio < 0 THEN 0 ELSE round(tb.ratio::NUMERIC, 6) END                 AS tbl_ratio,
       (tb.size * (CASE WHEN tb.ratio < 0 THEN 0 ELSE tb.ratio::NUMERIC END)) ::BIGINT    AS tbl_wasted,
       ib.idxid,
       ib.nspname || '.' || ib.relname                                                    AS idxname,
       ib.size                                                                            AS idx_size,
       CASE WHEN ib.ratio < 0 THEN 0 ELSE round(ib.ratio::NUMERIC, 5) END                 AS idx_ratio,
       (ib.size * (CASE WHEN ib.ratio < 0 THEN 0 ELSE ib.ratio::NUMERIC END)) ::BIGINT    AS idx_wasted
FROM monitor.pg_index_bloat ib
         FULL OUTER JOIN monitor.pg_table_bloat tb ON ib.tblid = tb.tblid;

COMMENT ON VIEW monitor.pg_bloat IS 'postgres relation bloat detail';
GRANT SELECT ON monitor.pg_bloat TO pg_monitor;

----------------------------------------------------------------------
-- monitor.pg_index_bloat_human
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_index_bloat_human CASCADE;
CREATE OR REPLACE VIEW monitor.pg_index_bloat_human AS
SELECT idxname                            AS name,
       tblname,
       idx_wasted                         AS wasted,
       pg_size_pretty(idx_size)           AS idx_size,
       round(100 * idx_ratio::NUMERIC, 2) AS idx_ratio,
       pg_size_pretty(idx_wasted)         AS idx_wasted,
       pg_size_pretty(tbl_size)           AS tbl_size,
       round(100 * tbl_ratio::NUMERIC, 2) AS tbl_ratio,
       pg_size_pretty(tbl_wasted)         AS tbl_wasted
FROM monitor.pg_bloat
WHERE idxname IS NOT NULL;
COMMENT ON VIEW monitor.pg_index_bloat_human IS 'postgres index bloat info in human-readable format';
GRANT SELECT ON monitor.pg_index_bloat_human TO pg_monitor;


----------------------------------------------------------------------
-- monitor.pg_table_bloat_human
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_table_bloat_human CASCADE;
CREATE OR REPLACE VIEW monitor.pg_table_bloat_human AS
SELECT tblname                                          AS name,
       idx_wasted + tbl_wasted                          AS wasted,
       pg_size_pretty(idx_wasted + tbl_wasted)          AS all_wasted,
       pg_size_pretty(tbl_wasted)                       AS tbl_wasted,
       pg_size_pretty(tbl_size)                         AS tbl_size,
       tbl_ratio,
       pg_size_pretty(idx_wasted)                       AS idx_wasted,
       pg_size_pretty(idx_size)                         AS idx_size,
       round(idx_wasted::NUMERIC * 100.0 / idx_size, 2) AS idx_ratio
FROM (SELECT datname,
             nspname,
             tblname,
             coalesce(max(tbl_wasted), 0)                         AS tbl_wasted,
             coalesce(max(tbl_size), 1)                           AS tbl_size,
             round(100 * coalesce(max(tbl_ratio), 0)::NUMERIC, 2) AS tbl_ratio,
             coalesce(sum(idx_wasted), 0)                         AS idx_wasted,
             coalesce(sum(idx_size), 1)                           AS idx_size
      FROM monitor.pg_bloat
      WHERE tblname IS NOT NULL
      GROUP BY 1, 2, 3
     ) d;
COMMENT ON VIEW monitor.pg_table_bloat_human IS 'postgres table bloat info in human-readable format';
GRANT SELECT ON monitor.pg_table_bloat_human TO pg_monitor;


----------------------------------------------------------------------
-- 活动概览:monitor.pg_session
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_session CASCADE;
CREATE OR REPLACE VIEW monitor.pg_session AS
SELECT coalesce(datname, 'all') AS datname, numbackends, active, idle, ixact, max_duration, max_tx_duration, max_conn_duration
FROM (
         SELECT datname,
                count(*)                                         AS numbackends,
                count(*) FILTER ( WHERE state = 'active' )       AS active,
                count(*) FILTER ( WHERE state = 'idle' )         AS idle,
                count(*) FILTER ( WHERE state = 'idle in transaction'
                    OR state = 'idle in transaction (aborted)' ) AS ixact,
                max(extract(epoch from now() - state_change))
                FILTER ( WHERE state = 'active' )                AS max_duration,
                max(extract(epoch from now() - xact_start))      AS max_tx_duration,
                max(extract(epoch from now() - backend_start))   AS max_conn_duration
         FROM pg_stat_activity
         WHERE backend_type = 'client backend'
           AND pid <> pg_backend_pid()
         GROUP BY ROLLUP (1)
         ORDER BY 1 NULLS FIRST
     ) t;
COMMENT ON VIEW monitor.pg_session IS 'postgres activity group by session';
GRANT SELECT ON monitor.pg_session TO pg_monitor;


----------------------------------------------------------------------
-- 顺序扫描:monitor.pg_seq_scan
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_seq_scan CASCADE;
CREATE OR REPLACE VIEW monitor.pg_seq_scan AS
SELECT schemaname                                                        AS nspname,
       relname,
       seq_scan,
       seq_tup_read,
       seq_tup_read / seq_scan                                           AS seq_tup_avg,
       idx_scan,
       n_live_tup + n_dead_tup                                           AS tuples,
       round(n_live_tup * 100.0::NUMERIC / (n_live_tup + n_dead_tup), 2) AS live_ratio
FROM pg_stat_user_tables
WHERE seq_scan > 0
  and (n_live_tup + n_dead_tup) > 0
ORDER BY seq_scan DESC;
COMMENT ON VIEW monitor.pg_seq_scan IS 'table that have seq scan';
GRANT SELECT ON monitor.pg_seq_scan TO pg_monitor;

7 - 答疑

常见问题解答

因 postgres 存在而中止

当您在运行 PostgreSQL 的节点上运行 pgsql.yml 时会发生这种情况。 如果有正在运行的 PostgreSQL 实例,您可以使用 pgsql-rm.yml 剧本显式移除它:

./pgsql-rm.yml -l <cls_to_remove>    # 移除集群 'cls_to_remove'

因启用 pg_safeguard 而中止

禁用 pg_safeguard 以移除 PostgreSQL 实例。

如果启用了 pg_safeguard,您无法使用 bin/pgsql-rmpgsql-rm.yml 剧本移除正在运行的 PostgreSQL 实例。

要禁用 pg_safeguard,您可以在配置清单中将 pg_safeguard 设置为 false,或将 -e pg_safeguard=false 作为命令行参数传递给剧本:

./pgsql-rm.yml -e pg_safeguard=false -l <cls_to_remove>    # 强制覆盖 pg_safeguard

等待 postgres/patroni 主库失败

这个错误有几个可能的原因,您需要 检查 系统日志来确定实际原因。

这通常发生在集群配置错误,或者之前的主库被不当移除时(例如,DCS 中有相同集群名称的垃圾元数据)。

您必须检查 /pg/log/* 以找到原因。

要从 etcd 删除垃圾元数据,您可以使用 etcdctl del --prefix /pg/<cls>,操作时请谨慎!

  • 1:配置错误。识别不正确的参数,修改它们并应用更改。
  • 2:部署中已存在同名的另一个集群
  • 3:节点上的之前集群,或同名的之前集群未正确移除。
  • 要移除过时的集群元数据,您可以使用 etcdctl del --prefix /pg/<cls> 手动删除残留数据。
  • 4:与您的 PostgreSQL 或节点相关的 RPM 包未成功安装。
  • 5:您的 Watchdog 内核模块未正确启用或加载,但是必需的。
  • 6:指定的语言环境或字符类型 pg_lc_collatepg_lc_ctype 在操作系统中不存在

请随时提交问题或寻求社区帮助。


等待 postgres/patroni 从库失败

立即失败:通常,这是由于配置错误、网络问题、DCS 元数据损坏等导致的,您必须检查 /pg/log 以找出实际原因。

一段时间后失败:这可能是由于源实例数据损坏。查看 PGSQL 常见问题:数据损坏时如何创建从库?

超时:如果 wait for postgres replica 任务需要 30 分钟或更长时间并因超时而失败,这对于大型集群(例如 1TB+,可能需要数小时才能创建从库)是常见的。在这种情况下,底层创建从库过程仍在进行。您可以使用 pg list <cls> 检查集群状态,等待从库追上主库。然后继续以下任务:

./pgsql.yml -t pg_hba,pg_param,pg_backup,pgbouncer,pg_vip,pg_dns,pg_service,pg_exporter,pg_register -l <problematic_replica>

安装 PostgreSQL 13 - 17

要安装 PostgreSQL 13 ~ 17,您必须在配置清单中将 pg_version 设置为 1314151617。(通常在集群级别设置)

pg_version: 16                    # 在此模板中安装 PostgreSQL 16

如何为 PostgreSQL 启用大页面?

使用 node_hugepage_countnode_hugepage_ratio/pg/bin/pg-tune-hugepage

如果您计划启用大页面,请考虑使用 node_hugepage_countnode_hugepage_ratio 并使用 ./node.yml -t node_tune 应用。

在 PostgreSQL 启动之前分配足够的大页面是好的做法,然后使用 pg_tune_hugepage 稍后缩减它们。

如果您的 PostgreSQL 已经在运行,您可以使用 /pg/bin/pg-tune-hugepage 即时启用大页面。请注意,这仅适用于 PostgreSQL 15+

sync; echo 3 > /proc/sys/vm/drop_caches   # 丢弃系统缓存(准备承受性能影响)
sudo /pg/bin/pg-tune-hugepage             # 将 nr_hugepages 写入 /etc/sysctl.d/hugepage.conf
pg restart <cls>                          # 重启 PostgreSQL 以使用大页面

如何在故障转移期间保证零数据丢失?

使用 crit.yml 模板,或设置 pg_rpo0,或使用同步模式 配置集群

考虑使用 同步从库法定人数提交 来保证故障转移期间 0 数据丢失。


如何从磁盘满的情况中恢复?

rm -rf /pg/dummy 将释放一些紧急空间。

pg_dummy_filesize 默认设置为 64MB。考虑在生产环境中将其增加到 8GB 或更大。

它将被放置在与 PGSQL 主数据磁盘相同的磁盘上的 /pg/dummy 中。您可以删除该文件以释放一些紧急空间。至少您可以在该节点上运行一些 shell 脚本。


数据损坏时如何创建从库?

在坏实例上禁用 clonefrom 并重新加载 patroni 配置。

Pigsty 在所有实例的 patroni 配置上设置 cloneform: true 标签,这标记实例可用于克隆从库。

如果此实例有损坏的数据文件,您可以设置 clonefrom: false 以避免从有问题的实例拉取数据。具体操作如下:

$ vi /pg/bin/patroni.yml

tags:
  nofailover: false
  clonefrom: true      # ----------> 改为 false
  noloadbalance: false
  nosync: false
  version:  '15'
  spec: '4C.8G.50G'
  conf: 'oltp.yml'

$ systemctl reload patroni

数据损坏时如何创建从库?

在坏实例上禁用 clonefrom 并重新加载 patroni 配置。

Pigsty 在所有实例的 patroni 配置上设置 cloneform: true 标签,这标记实例可用于克隆从库。

如果此实例有损坏的数据文件,您可以设置 clonefrom: false 以避免从有问题的实例拉取数据。具体操作如下:

$ vi /pg/bin/patroni.yml

tags:
  nofailover: false
  clonefrom: true      # ----------> 改为 false
  noloadbalance: false
  nosync: false
  version:  '15'
  spec: '4C.8G.50G'
  conf: 'oltp.yml'

$ systemctl reload patroni

监控导出器的性能影响

影响不大,每 10 ~ 15 秒 200ms,不会影响数据库性能。

Pigsty 中 prometheus 的默认抓取间隔为 10 秒,确保导出器可以在该时间段内完成抓取。


如何监控现有的 PostgreSQL 实例?

详情请查看 PGSQL 监控


如何从 prometheus 中移除监控目标?

./pgsql-rm.yml -t prometheus -l <cls>     # 移除集群 'cls' 的 prometheus 目标

或者

bin/pgmon-rm <ins>     # 移除 PostgreSQL 实例 'ins' 的 prometheus 目标的快捷方式

8 - 用户

在此上下文中,用户是指通过 SQL CREATE USER / ROLE 创建的逻辑对象

您可以使用 Pigsty 以 IaC 方式管理 PostgreSQL 用户和角色。


定义用户

您可以使用以下参数定义角色/用户,它们都是由用户对象组成的数组:

  • pg_users:在集群级别定义业务用户和角色(集群定义
  • pg_default_roles:定义系统范围的角色和全局用户(全局默认值

前者定义整个环境中共享的全局角色和用户,后者定义特定于单个集群的业务角色和用户。 以下是一些用户定义的示例:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_databases:
      - {name: dbuser_meta     ,password: DBUser.Meta     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
      - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
      - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
      - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
      - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
      - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
      - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
      - {name: dbuser_noco     ,password: DBUser.Noco     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }

用户属性

您可以使用更多属性自定义用户,完整示例如下:

- name: dbuser_meta           # 必需,`name` 是用户定义的唯一必填字段
  password: DBUser.Meta       # 可选,密码,可以是 scram-sha-256 哈希字符串或明文
  login: true                 # 可选,可以登录,默认为 true(新业务角色应该为 false)
  superuser: false            # 可选,是超级用户吗?默认为 false
  createdb: false             # 可选,可以创建数据库吗?默认为 false
  createrole: false           # 可选,可以创建角色吗?默认为 false
  inherit: true               # 可选,此角色可以使用继承的权限吗?默认为 true
  replication: false          # 可选,此角色可以进行复制吗?默认为 false
  bypassrls: false            # 可选,此角色可以绕过行级安全吗?默认为 false
  pgbouncer: true             # 可选,将此用户添加到 pgbouncer 用户列表?默认为 false(生产用户应明确设置为 true)
  connlimit: -1               # 可选,用户连接限制,默认 -1 禁用限制
  expire_in: 3650             # 可选,现在 + n 天后此角色过期(覆盖 expire_at)
  expire_at: '2030-12-31'     # 可选,YYYY-MM-DD '时间戳',此角色过期时间(被 expire_in 覆盖)
  comment: pigsty admin user  # 可选,此用户/角色的注释字符串
  roles: [dbrole_admin]       # 可选,所属角色。默认角色有:dbrole_{admin,readonly,readwrite,offline}
  parameters: {}              # 可选,使用 `ALTER ROLE SET` 的角色级别参数
  pool_mode: transaction      # 可选,用户级别的 pgbouncer 池模式,默认为 transaction
  pool_connlimit: -1          # 可选,用户级别的最大数据库连接数,默认 -1 禁用限制
  search_path: public         # 键值配置参数,根据 postgresql 文档(例如:使用 pigsty 作为默认 search_path)
  • 唯一必需的字段是 name,它应该是 PostgreSQL 中有效且唯一的用户名。
  • 角色不需要 password,但对于可登录用户可能是必需的。
  • password 可以是明文或 scram-sha-256 / md5 哈希字符串。
  • 用户/角色定义顺序很重要,pg_default_roles 在前,pg_users 在后,按顺序排列。
  • 确保角色/组定义在其成员之前。
  • 角色属性loginsuperusercreatedbcreateroleinheritreplicationbypassrls
  • pgbouncer 默认禁用。明确设置为 true 以在 pgbouncer 中启用它。

ACL 系统

Pigsty 具有电池包含的 ACL 系统,可以通过将角色分配给用户来轻松使用:

  • dbrole_readonly:全局只读访问角色
  • dbrole_readwrite:全局读写访问角色
  • dbrole_admin:对象创建角色
  • dbrole_offline:受限只读访问角色(离线实例)

如果您希望重新设计您的 ACL 系统,请检查以下参数和 SQL 模板。


创建用户

pg_default_rolespg_users 中定义的用户和角色将在模块安装期间逐一自动创建。 它只在集群领导者,即主实例上运行。

要在现有集群上创建用户, 将新用户/角色定义添加到 all.children.<cls>.pg_users,并使用 bin/pgsql-user 工具或 pgsql-user.yml playbook 创建数据库:

bin/pgsql-user <cls>   <dbname>         # bin 工具脚本
bin/pgsql-user pg-meta dbuser_meta      # 示例:在 pg-meta 集群中创建 dbuser_meta 用户
./pgsql-user.yml -l <cls>   -e username=<dbname> # 实际 playbook
./pgsql-user.yml -l pg-meta -e username=meta     # 示例:在 pg-meta 集群中创建 dbuser_meta 用户

创建用户是幂等操作,意味着可以多次安全运行。

使用 Pigsty 创建用户/角色

Pigsty 将管理 pgbouncer 用户列表,因此请使用 Pigsty playbook/工具创建业务数据库。 查看创建用户 SOP 了解详细信息。 如果您不使用 pgbouncer 或能够自己维护它,您可以以任何您喜欢的方式创建用户。

在创建数据库之前创建所有者用户

在 PostgreSQL 中,用户属于数据库集群,而不是特定数据库。

如果您的用户是任何数据库的所有者,请确保在创建数据库之前创建用户。


修改用户

修改 PostgreSQL 用户属性与创建用户相同。 通过修改配置清单调整您的用户定义,然后重新运行创建用户

有两个例外:nameroles,需要手动干预:

Pigsty 不直接支持重命名用户

用户名用作用户的标识,因此如果您真的想这样做,请使用标准 SQL:

ALTER USER "old_name" RENAME TO "new_name";
Pigsty 不会撤销成员资格

请注意,修改用户不会删除用户,而是使用 ALTER USER 命令修改用户属性。 它也不会撤销用户权限和组成员资格,并使用 GRANT 命令授予新角色。

查看 PostgreSQL 文档了解更多关于 ALTER USER 的详细信息。


删除用户

出于安全原因,Pigsty 不会自动删除用户,即使您从配置中删除用户定义,Pigsty 也不会删除现有用户。

您需要使用 SQL 命令 DROP USER 手动删除用户:

DROP USER "<username>";

如果您要删除的角色是一个组(有其他用户属于它),您需要首先从组中删除其他用户,然后再删除组:

REVOKE "<rolename>" FROM "<other_user>";

如果您要删除的用户拥有数据库对象,您需要首先将这些对象的所有权更改为另一个用户,然后再删除用户:

REASSIGN OWNED BY "<username>" TO "<another_user>";

查看 PostgreSQL 文档了解更多关于 DROP USERREASSIGN OWNEDREVOKE 的详细信息。


Pgbouncer 用户

Pigsty 帮助管理 pgbouncer 用户列表中的用户,并使其与 postgres 保持同步。 它需要在用户定义中明确设置 pgbouncer: true 标志以注册到 pgbouncer 用户列表中。

系统管理员用户(pg_admin_username)和监控用户(pg_monitor_username) 将始终添加到 pgbouncer 用户列表中用于管理和监控。

配置文件

Pgbouncer 连接池中的用户列在 /etc/pgbouncer/userlist.txt 中,示例:

/etc/pgbouncer/userlist.txt
"postgres" ""
"dbuser_wiki" "SCRAM-SHA-256$4096:+77dyhrPeFDT/TptHs7/7Q==$KeatuohpKIYzHPCt/tqBu85vI11o9mar/by0hHYM2W8=:X9gig4JtjoS8Y/o1vQsIX/gY1Fns8ynTXkbWOjUfbRQ="
"dbuser_view" "SCRAM-SHA-256$4096:DFoZHU/DXsHL8MJ8regdEw==$gx9sUGgpVpdSM4o6A2R9PKAUkAsRPLhLoBDLBUYtKS0=:MujSgKe6rxcIUMv4GnyXJmV0YNbf39uFRZv724+X1FE="
"dbuser_monitor" "SCRAM-SHA-256$4096:fwU97ZMO/KR0ScHO5+UuBg==$CrNsmGrx1DkIGrtrD1Wjexb/aygzqQdirTO1oBZROPY=:L8+dJ+fqlMQh7y4PmVR/gbAOvYWOr+KINjeMZ8LlFww="
"dbuser_meta" "SCRAM-SHA-256$4096:leB2RQPcw1OIiRnPnOMUEg==$eyC+NIMKeoTxshJu314+BmbMFpCcspzI3UFZ1RYfNyU=:fJgXcykVPvOfro2MWNkl5q38oz21nSl1dTtM65uYR1Q="
"dbuser_kong" "SCRAM-SHA-256$4096:bK8sLXIieMwFDz67/0dqXQ==$P/tCRgyKx9MC9LH3ErnKsnlOqgNd/nn2RyvThyiK6e4=:CDM8QZNHBdPf97ztusgnE7olaKDNHBN0WeAbP/nzu5A="
"dbuser_grafana" "SCRAM-SHA-256$4096:HjLdGaGmeIAGdWyn2gDt/Q==$jgoyOB8ugoce+Wqjr0EwFf8NaIEMtiTuQTg1iEJs9BM=:ed4HUFqLyB4YpRr+y25FBT7KnlFDnan6JPVT9imxzA4="
"dbuser_gitea" "SCRAM-SHA-256$4096:l1DBGCc4dtircZ8O8Fbzkw==$tpmGwgLuWPDog8IEKdsaDGtiPAxD16z09slvu+rHE74=:pYuFOSDuWSofpD9OZhG7oWvyAR0PQjJBffgHZLpLHds="
"dbuser_dba" "SCRAM-SHA-256$4096:zH8niABU7xmtblVUo2QFew==$Zj7/pq+ICZx7fDcXikiN7GLqkKFA+X5NsvAX6CMshF0=:pqevR2WpizjRecPIQjMZOm+Ap+x0kgPL2Iv5zHZs0+g="
"dbuser_bytebase" "SCRAM-SHA-256$4096:OMoTM9Zf8QcCCMD0svK5gg==$kMchqbf4iLK1U67pVOfGrERa/fY818AwqfBPhsTShNQ=:6HqWteN+AadrUnrgC0byr5A72noqnPugItQjOLFw0Wk="

用户级别参数在单独的文件中维护:/etc/pgbouncer/useropts.txt,示例:

/etc/pgbouncer/useropts.txt
dbuser_dba                  = pool_mode=session max_user_connections=16
dbuser_monitor              = pool_mode=session max_user_connections=8

当您创建用户时,userlist.txtuseropts.txt 将自动刷新 并通过 systemctl reload pgbouncer 生效,通常不会影响现有连接。

重新加载

要重新加载 pgbouncer 配置,您可以使用 ansible playbook 或 systemctl 命令

./pgsql.yml -t pgbouncer_reload
systemctl reload pgbouncer

管理

Pgbouncer 与 PostgreSQL 使用相同的 dbsu 运行,默认为 postgres 操作系统用户。 您可以使用 pgb 别名通过 dbsu 访问 pgbouncer 管理功能。

postgres
sudo su - postgres
pgb   # 使用管理员用户登录到 pgbouncer 命令行界面

删除 Pgbouncer 用户

如果所有数据库用户都由 Pigsty 管理,您可以重新生成 pgbouncer 用户列表(在配置清单的列表中不包含已删除的用户)并重新加载它:

./pgsql.yml -t pgbouncer_user,pgbouncer_reload -e pg_reload=true

要手动从 pgbouncer 池中删除用户,只需从 /etc/pgbouncer/userlist.txt 中删除相应的行并重新加载 pgbouncer:

systemctl reload pgbouncer

动态用户认证

请注意,pgbouncer_auth_query 参数允许您使用动态查询完成连接池用户认证,这是当您不想在连接池中管理用户时的一种折衷方案。

9 - 数据库

在此上下文中,数据库是指由 SQL CREATE DATABASE 创建的对象。

一个 PostgreSQL 服务器可以同时服务多个数据库。您可以使用 Pigsty 来管理它们。


定义数据库

业务数据库由 pg_databases 定义,这是一个集群级参数。

例如,默认的 meta 数据库在 pg-meta 集群中定义:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_databases:
      - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: postgis, schema: public}, {name: timescaledb}]}
      - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
      - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
      - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
      - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
      - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
      - { name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database }

每个数据库定义是一个包含以下字段的字典:

- name: meta                      # 必需,`name` 是数据库定义的唯一必需字段
  baseline: cmdb.sql              # 可选,数据库 SQL 基线路径(ansible 搜索路径中的相对路径,例如 files/)
  pgbouncer: true                 # 可选,将此数据库添加到 pgbouncer 数据库列表?默认为 true
  schemas: [pigsty]               # 可选,要创建的额外模式,模式名称数组
  extensions:                     # 可选,要安装的额外扩展:`{name[,schema]}` 数组
    - { name: postgis , schema: public }
    - { name: timescaledb }
  comment: pigsty meta database   # 可选,此数据库的注释字符串
  owner: postgres                 # 可选,数据库拥有者,默认为 postgres
  template: template1             # 可选,使用哪个模板,默认为 template1
  encoding: UTF8                  # 可选,数据库编码,默认为 UTF8(必须与模板数据库相同)
  locale: C                       # 可选,数据库区域设置,默认为 C(必须与模板数据库相同)
  lc_collate: C                   # 可选,数据库排序规则,默认为 C(必须与模板数据库相同)
  lc_ctype: C                     # 可选,数据库字符分类,默认为 C(必须与模板数据库相同)
  tablespace: pg_default          # 可选,默认表空间,默认为 'pg_default'
  allowconn: true                 # 可选,允许连接,默认为 true。false 将完全禁用连接
  revokeconn: false               # 可选,撤销公共连接权限。默认为 false(将连接权限留给拥有者并授予授权选项)
  register_datasource: true       # 可选,将此数据库注册到 grafana 数据源?默认为 true
  connlimit: -1                   # 可选,数据库连接限制,默认 -1 禁用限制
  pool_auth_user: dbuser_meta     # 可选,所有到此 pgbouncer 数据库的连接都将由此用户认证
  pool_mode: transaction          # 可选,数据库级别的 pgbouncer 池模式,默认为 transaction
  pool_size: 64                   # 可选,数据库级别的 pgbouncer 池大小,默认为 64
  pool_size_reserve: 32           # 可选,数据库级别的 pgbouncer 池保留大小,默认为 32
  pool_size_min: 0                # 可选,数据库级别的 pgbouncer 池最小大小,默认为 0
  pool_max_db_conn: 100           # 可选,数据库级别的最大数据库连接数,默认为 100

唯一必需的字段是 name,它应该是 PostgreSQL 中有效且唯一的数据库名称。

新创建的数据库默认从 template1 数据库分叉。该模板在集群引导期间由 PG_PROVISION 自定义。

有关数据库级权限的详细信息,请查看 ACL:数据库权限


创建数据库

pg_databases定义 的数据库将在模块安装期间自动创建。 如果您希望在现有集群上 创建数据库,可以使用 bin/pgsql-db 工具。

将新的数据库定义添加到 all.children.<cls>.pg_databases,然后使用以下命令创建该数据库:

bin/pgsql-db <cls> <dbname>    # bin 工具脚本
bin/pgsql-db pg-meta meta      # 示例:在 pg-meta 集群中创建 meta 数据库
./pgsql-db.yml -l <cls> -e dbname=<dbname>    # 实际的剧本
./pgsql-db.yml -l pg-meta -e dbname=meta      # 示例:在 pg-meta 集群中创建 meta 数据库

此剧本通常是幂等的,可以重新运行以刷新数据库定义。 但如果您有复杂的 baseline 模式(如删除操作),则不应在现有数据库上重新运行此剧本。

使用 pigsty 创建 postgres 数据库

Pigsty 将管理 pgbouncer 数据库列表,因此请使用 Pigsty 剧本/工具创建业务数据库。 详情请查看 创建数据库 标准操作程序。 如果您不使用 pgbouncer 或能够自己维护它,可以使用任何方式创建数据库。

创建数据库前先创建拥有者

如果您的数据库有非默认的 owner(默认为数据库超级用户 postgres),请确保拥有者用户在创建数据库之前已存在。 简而言之,始终在创建数据库之前 创建 用户


Pgbouncer 数据库

Pgbouncer 默认启用并充当连接池中间件。

Pigsty 默认将 pg_databases 中的所有数据库添加到 pgbouncer 数据库列表。 您可以通过在数据库 定义 中设置 pgbouncer: false 来禁用特定数据库的 pgbouncer 代理。

使用 Pigsty 工具和剧本 创建数据库 时,Pgbouncer 数据库列表将被更新。 数据库在 /etc/pgbouncer/database.txt 中列出,带有额外的数据库级参数:

/etc/pgbouncer/database.txt
meta     = host=/var/run/postgresql mode=session
grafana  = host=/var/run/postgresql mode=transaction
bytebase = host=/var/run/postgresql auth_user=dbuser_meta
kong     = host=/var/run/postgresql pool_size=32 reserve_pool=64
gitea    = host=/var/run/postgresql min_pool_size=10
wiki     = host=/var/run/postgresql
noco     = host=/var/run/postgresql
mongo    = host=/var/run/postgresql

当您 创建数据库 时,Pgbouncer 数据库列表定义文件将被刷新并通过在线配置重载生效,不会影响现有连接。

要访问 pgbouncer 管理功能,您可以以数据库超级用户(postgres)身份使用 pgb 别名。 查看 pgbouncer 使用方法 了解可用命令:

postgres
sudo su - postgres  # 切换到 postgres 数据库超级用户
pgb                 # 访问 pgbouncer 管理虚拟数据库

/etc/profile.d/pg-alias.sh 中定义了一个工具函数,允许您快速将 pgbouncer 数据库流量重新路由到新主机,可用于零停机时间迁移。

/etc/profile.d/pg-alias.sh
# 将 pgbouncer 流量路由到另一个集群成员
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 - 服务

通过负载均衡、代理、连接池提供可靠的服务访问

服务实现

在 Pigsty 中,服务通过节点上的 haproxy 实现,通过主机节点上的不同端口来区分。

每个节点都启用了 Haproxy 来暴露服务。从数据库角度来看,集群中的节点可能是主节点或副本节点,但从服务角度来看,所有节点都是相同的。这意味着即使您访问副本节点,只要使用正确的服务端口,您仍然可以使用主节点的读写服务。这种设计封装了复杂性:只要您能访问 PostgreSQL 集群上的任何实例,就可以完全访问所有服务。

这种设计类似于 Kubernetes 中的 NodePort 服务。同样,在 Pigsty 中,每个服务都包含这两个核心元素:

  1. 通过 NodePort 暴露的访问端点(端口号,从哪里访问?)
  2. 通过选择器选择的目标实例(实例列表,谁来处理?)

Pigsty 服务交付的边界止于集群的 HAProxy。用户可以通过各种方式访问这些负载均衡器。请参考访问服务

所有服务都通过配置文件声明。例如,默认的 PostgreSQL 服务由 pg_default_services 参数定义:

- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
- { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
- { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
- { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

您也可以在 pg_services 中定义新服务。pg_default_servicespg_services 都是服务定义的数组。


定义服务

默认服务在 pg_default_services 中定义。

您可以在全局或集群级别使用 pg_services 定义额外的 PostgreSQL 服务。

这两个参数都是服务对象的数组。每个服务定义将被渲染为 /etc/haproxy/<svcname>.cfg 中的 haproxy 配置,查看 service.cfg 了解详细信息。

这里是一个额外服务定义的示例:standby

- name: standby                   # 必需,服务名称,实际服务名称将以 `pg_cluster` 为前缀,例如:pg-meta-standby
  port: 5435                      # 必需,服务暴露端口(作为 kubernetes 服务节点端口模式工作)
  ip: "*"                         # 可选,服务绑定 IP 地址,默认为所有 IP 的 `*`
  selector: "[]"                  # 必需,服务成员选择器,使用 JMESPath 过滤清单
  dest: default                   # 可选,目标端口,default|postgres|pgbouncer|<port_number>,默认为 'default'
  check: /sync                    # 可选,健康检查 URL 路径,默认为 /
  backup: "[? pg_role == `primary`]"  # 备份服务器选择器
  maxconn: 3000                   # 可选,最大允许前端连接数
  balance: roundrobin             # 可选,haproxy 负载均衡算法(默认为 roundrobin,其他:leastconn)
  options: 'inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100'

它将被转换为 haproxy 配置文件 /etc/haproxy/pg-test-standby.conf

#---------------------------------------------------------------------
# service: pg-test-standby @ 10.10.10.11:5435
#---------------------------------------------------------------------
# service instances 10.10.10.11, 10.10.10.13, 10.10.10.12
# service backups   10.10.10.11
listen pg-test-standby
    bind *:5435
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /sync  # <--- 对主节点和同步备节点为真
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100 backup   # 主节点用作备份服务器
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

重新加载服务

当集群成员发生变化时,如添加/移除副本、切换/故障转移或调整相对权重,您必须重新加载服务以使更改生效。

bin/pgsql-svc <cls> [ip...]         # 为负载均衡集群或负载均衡实例重新加载服务
# ./pgsql.yml -t pg_service         # 重新加载服务的实际 ansible 任务

覆盖服务

您可以通过几种方式覆盖默认服务配置:

绕过 Pgbouncer

在定义服务时,如果 svc.dest='default',将使用参数 pg_default_service_dest 作为默认值。默认使用 pgbouncer,您可以改用 postgres,这样默认的主节点和副本服务将绕过 pgbouncer 并直接将流量路由到 postgres

如果您完全不需要连接池,可以将 pg_default_service_dest 更改为 postgres,并移除 defaultoffline 服务。

如果您不需要用于在线流量的只读副本,也可以从 pg_default_services 中移除 replica

pg_default_services:
  - { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
  - { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
  - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
  - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

委托服务

Pigsty 在节点上使用 haproxy 暴露 PostgreSQL 服务。集群中的所有 haproxy 实例都配置了相同的服务定义。

然而,您可以将 pg 服务委托给特定的节点组(例如,专用的 haproxy 负载均衡集群)而不是集群成员。

要做到这一点,您需要使用 pg_default_services 覆盖默认服务定义,并将 pg_service_provider 设置为代理组名称。

例如,这个配置将在 haproxy 节点组 proxy 上使用端口 10013 暴露 pg 集群主服务。

pg_service_provider: proxy       # 使用组 `proxy` 上的负载均衡器和端口 10013
pg_default_services:  [{ name: primary ,port: 10013 ,dest: postgres  ,check: /primary   ,selector: "[]" }]

用户有责任确保每个委托服务端口在代理集群中是唯一的

分离读写,将流量路由到正确的位置,并实现对 PostgreSQL 集群的稳定可靠访问。

服务是一个抽象,用于封装底层集群的细节,特别是在集群故障转移/切换期间。


个人用户

对于个人用户,服务是没有意义的。您可以使用原始 IP 地址或任何您喜欢的方法访问数据库。

psql postgres://dbuser_dba:[email protected]/meta     # dbsu 直接连接
psql postgres://dbuser_meta:[email protected]/meta   # 默认业务管理员用户
psql postgres://dbuser_view:DBUser.View@pg-meta/meta       # 默认只读用户

服务概述

在现实世界的生产环境中,我们利用基于复制的 PostgreSQL 数据库集群。在集群内,只有一个实例是可以接受写入的领导者(主节点)。其他实例(副本)持续从领导者获取 WAL 以保持同步。此外,副本可以处理只读查询,并在读取密集、写入较少的场景中为主节点分担负载。因此,区分写入和只读请求是一种常见做法。

此外,我们通过连接池中间件(Pgbouncer)为高频、短期连接池化请求,以减少连接和后端进程创建的开销。而且,对于 ETL 和变更执行等场景,我们需要绕过连接池并直接访问数据库服务器。此外,高可用性集群可能在故障期间发生故障转移,导致集群领导权发生变化。因此,读写请求应该自动重新路由到新的领导者。

这些不同的需求(读写分离、池化与直接连接以及客户端请求故障转移)导致了服务概念的抽象。

通常,数据库集群必须提供这个基本服务:

  • 读写服务(主节点):可以读取和写入数据库。

对于生产数据库集群,至少应该提供这两个服务:

  • 读写服务(主节点):写入数据:只由主节点承载。
  • 只读服务(副本):读取数据:可以由副本承载,但如果没有可用的副本,则回退到主节点。

此外,可能还有其他服务,例如:

  • 直接访问服务(默认):允许(管理员)用户绕过连接池并直接访问数据库。
  • 离线副本服务(离线):专用副本,不处理在线读取流量,用于 ETL 和分析查询。
  • 同步副本服务(备用):无复制延迟的只读服务,由同步备用/主节点处理读取查询。
  • 延迟副本服务(延迟):从一定时间前的同一集群访问较旧的数据,由延迟副本处理。

默认服务

Pigsty 将为每个 PostgreSQL 集群启用四个默认服务:

服务 端口 描述
primary 5433 pgbouncer 读写,连接到主节点 5432 或 6432
replica 5434 pgbouncer 只读,连接到副本 5432/6432
default 5436 管理员或直接访问主节点
offline 5438 OLAP、ETL、个人用户、交互式查询

以默认的 pg-meta 集群为例,您可以通过以下方式访问这些服务:

psql postgres://dbuser_meta:DBUser.Meta@pg-meta:5433/meta   # pg-meta-primary : 通过主节点 pgbouncer(6432) 进行生产读写
psql postgres://dbuser_meta:DBUser.Meta@pg-meta:5434/meta   # pg-meta-replica : 通过副本 pgbouncer(6432) 进行生产只读
psql postgres://dbuser_dba:DBUser.DBA@pg-meta:5436/meta     # pg-meta-default : 通过主节点 postgres(5432) 直接连接主节点
psql postgres://dbuser_stats:DBUser.Stats@pg-meta:5438/meta # pg-meta-offline : 通过离线 postgres(5432) 直接连接离线

pigsty-ha.png

这里 pg-meta 域名指向集群的 L2 VIP,进而指向主实例上的 haproxy 负载均衡器。 它负责将流量路由到不同的实例,查看访问服务了解详细信息。


主服务

主服务可能是生产使用中最关键的服务。

它将根据 pg_default_service_dest 将流量路由到主实例:

  • pgbouncer:将流量路由到主节点 pgbouncer 端口(6432),这是默认行为
  • postgres:如果您不想使用 pgbouncer,直接将流量路由到主节点 postgres 端口(5432)
- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }

这意味着所有集群成员都将包含在主服务中(selector: "[]"),但通过健康检查(check: /primary)的唯一实例将被用作主实例。Patroni 将保证任何时候只有一个实例是主节点,因此主服务将始终将流量路由到主实例。

listen pg-test-primary
    bind *:5433
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /primary
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

副本服务

副本服务用于生产只读流量。

在现实场景中,只读查询可能比读写查询多得多。您可能有许多副本。

副本服务将根据 pg_default_service_dest 将流量路由到 Pgbouncer 或 postgres,就像主服务一样。

- { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }

replica 服务流量将尽量使用 pg_role = replica 的普通 pg 实例,以尽可能减轻 primary 实例的负载。它将尽量不使用 pg_role = offline 的实例,以尽可能避免混合 OLAP 和 OLTP 查询。

所有集群成员将包含在副本服务中(selector: "[]"),当它通过只读健康检查(check: /read-only)时。primaryoffline 实例用作备份服务器,在所有 replica 实例都宕机的情况下接管。

listen pg-test-replica
    bind *:5434
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /read-only
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100 backup
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

默认服务

默认服务将默认路由到主节点 postgres(5432)。

它非常类似于主服务,除了它将始终绕过 pgbouncer,无论 pg_default_service_dest 如何。这对于管理连接、ETL 写入、CDC 变更数据捕获等非常有用…

- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
listen pg-test-default
    bind *:5436
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /primary
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:5432 check port 8008 weight 100
    server pg-test-3 10.10.10.13:5432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:5432 check port 8008 weight 100

离线服务

离线服务将直接将流量路由到专用的 postgres 实例。

这可能是 pg_role = offline 实例,或者是标记了 pg_offline_query 的实例。

如果找不到这样的实例,它将回退到任何副本实例。底线是:它永远不会将流量路由到主实例。

- { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}
listen pg-test-offline
    bind *:5438
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /replica
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-3 10.10.10.13:5432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:5432 check port 8008 weight 100 backup

访问服务

Pigsty 使用 haproxy 暴露服务。默认情况下,所有节点都启用了 haproxy。

默认情况下,haproxy 负载均衡器在同一个 pg 集群中是幂等的,您可以通过任何/所有方式使用它们。

典型的方法是通过集群域名访问,它解析为集群 L2 VIP,或以轮询方式解析为所有实例 IP 地址。

服务可以通过不同的方式实现。您甚至可以实现自己的访问方法,如 L4 LVS、F5 等,而不是 haproxy。

pigsty-access.jpg

您可以使用主机和端口的不同组合,它们以不同的方式提供 PostgreSQL 服务。

主机

类型 示例 描述
集群域名 pg-test 通过集群域名(由基础设施节点上的 dnsmasq 解析)
集群 VIP 地址 10.10.10.3 通过由 vip-manager 管理的 L2 VIP 地址,绑定到主节点
实例主机名 pg-test-1 通过任何实例主机名访问(由基础设施节点上的 dnsmasq 解析)
实例 IP 地址 10.10.10.11 访问任何实例 IP 地址

端口

Pigsty 使用不同的端口来区分 pg 服务:

端口 服务 类型 描述
5432 postgres 数据库 直接访问 postgres 服务器
6432 pgbouncer 中间件 在访问 postgres 之前通过连接池中间件
5433 primary 服务 访问主节点 pgbouncer(或 postgres)
5434 replica 服务 访问副本 pgbouncer(或 postgres)
5436 default 服务 访问主节点 postgres
5438 offline 服务 访问离线 postgres

组合

# 通过集群域名访问
postgres://test@pg-test:5432/test # DNS -> L2 VIP -> 主节点直接连接
postgres://test@pg-test:6432/test # DNS -> L2 VIP -> 主节点连接池 -> 主节点
postgres://test@pg-test:5433/test # DNS -> L2 VIP -> HAProxy -> 主节点连接池 -> 主节点
postgres://test@pg-test:5434/test # DNS -> L2 VIP -> HAProxy -> 副本连接池 -> 副本
postgres://dbuser_dba@pg-test:5436/test # DNS -> L2 VIP -> HAProxy -> 主节点直接连接(管理员)
postgres://dbuser_stats@pg-test:5438/test # DNS -> L2 VIP -> HAProxy -> 离线直接连接(ETL/个人查询)

# 通过集群 VIP 直接访问
postgres://[email protected]:5432/test # L2 VIP -> 主节点直接访问
postgres://[email protected]:6432/test # L2 VIP -> 主节点连接池 -> 主节点
postgres://[email protected]:5433/test # L2 VIP -> HAProxy -> 主节点连接池 -> 主节点
postgres://[email protected]:5434/test # L2 VIP -> HAProxy -> 副本连接池 -> 副本
postgres://[email protected]:5436/test # L2 VIP -> HAProxy -> 主节点直接连接(管理员)
postgres://[email protected]::5438/test # L2 VIP -> HAProxy -> 离线直接连接(ETL/个人查询)

# 直接指定任何集群实例名称
postgres://test@pg-test-1:5432/test # DNS -> 数据库实例直接连接(单例访问)
postgres://test@pg-test-1:6432/test # DNS -> 连接池 -> 数据库
postgres://test@pg-test-1:5433/test # DNS -> HAProxy -> 连接池 -> 数据库读写
postgres://test@pg-test-1:5434/test # DNS -> HAProxy -> 连接池 -> 数据库只读
postgres://dbuser_dba@pg-test-1:5436/test # DNS -> HAProxy -> 数据库直接连接
postgres://dbuser_stats@pg-test-1:5438/test # DNS -> HAProxy -> 数据库离线读写

# 直接指定任何集群实例 IP 访问
postgres://[email protected]:5432/test # 数据库实例直接连接(直接指定实例,无自动流量分发)
postgres://[email protected]:6432/test # 连接池 -> 数据库
postgres://[email protected]:5433/test # HAProxy -> 连接池 -> 数据库读写
postgres://[email protected]:5434/test # HAProxy -> 连接池 -> 数据库只读
postgres://[email protected]:5436/test # HAProxy -> 数据库直接连接
postgres://[email protected]:5438/test # HAProxy -> 数据库离线读写

# 智能客户端自动读写分离(连接池)
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=primary
postgres://[email protected]:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=prefer-standby

11 - 认证

Pigsty 中基于主机的身份验证

PostgreSQL 有各种 身份验证 方法。您可以使用所有这些方法,而 Pigsty 的开箱即用 ACL 系统专注于 HBA、密码和 SSL 身份验证。


客户端身份验证

要连接到 PostgreSQL 数据库,用户必须经过身份验证(默认使用密码)。

您可以在连接字符串中提供密码(不安全)或使用 PGPASSWORD 环境变量或 .pgpass 文件。查看 psql 文档和 PostgreSQL 连接字符串 获取更多详细信息。

psql 'host=<host> port=<port> dbname=<dbname> user=<username> password=<password>'
psql postgres://<username>:<password>@<host>:<port>/<dbname>
PGPASSWORD=<password>; psql -U <username> -h <host> -p <port> -d <dbname>

meta 数据库的默认连接字符串:

psql 'host=10.10.10.10 port=5432 dbname=meta user=dbuser_dba password=DBUser.DBA'
psql postgres://dbuser_dba:[email protected]:5432/meta
PGPASSWORD=DBUser.DBA; psql -U dbuser_dba -h 10.10.10.10 -p 5432 -d meta

要使用 SSL 证书连接,您可以使用 PGSSLCERTPGSSLKEY 环境变量或 sslkeysslcert 参数。

psql 'postgres://dbuser_dba:[email protected]:5432/meta?sslkey=/path/to/dbuser_dba.key&sslcert=/path/to/dbuser_dba.crt'

客户端证书(CN = 用户名)可以使用本地 CA 和 cert.yml 颁发。


定义 HBA

Pigsty 中有四个 HBA 规则参数:

它们是 HBA 规则对象的数组,每个 HBA 规则是以下形式之一:

1. 原始形式

- title: allow intranet password access
  role: common
  rules:
    - host   all  all  10.0.0.0/8      md5
    - host   all  all  172.16.0.0/12   md5
    - host   all  all  192.168.0.0/16  md5

在这种形式中,title 将被渲染为注释行,然后是 rules 作为 HBA 字符串逐一显示。

当实例的 pg_rolerole 相同时,HBA 规则被安装。

带有 role: common 的 HBA 规则将在所有实例上安装。

带有 role: offline 的 HBA 规则将在 pg_role = offlinepg_offline_query = true 的实例上安装。

2. 别名形式

别名形式,用 addrauthuserdb 字段替换 rules

- addr: 'intra'    # world|intra|infra|admin|local|localhost|cluster|<cidr>
  auth: 'pwd'      # trust|pwd|ssl|cert|deny|<official auth method>
  user: 'all'      # all|${dbsu}|${repl}|${admin}|${monitor}|<user>|<group>
  db: 'all'        # all|replication|....
  rules: []        # 原始 HBA 字符串优先于以上所有
  title: allow intranet password access
  • addr:哪里

    • world:所有 IP 地址
    • intra:所有内网 CIDR:'10.0.0.0/8'、'172.16.0.0/12'、'192.168.0.0/16'
    • infra:基础设施节点的 IP 地址
    • adminadmin_ip 地址
    • local:本地 unix 套接字
    • localhost:本地 unix 套接字 + tcp 127.0.0.1/32
    • cluster:PostgreSQL 集群成员的所有 IP 地址
    • <cidr>:任何标准 CIDR 块或 IP 地址
  • auth:如何

    • deny:拒绝访问
    • trust:信任身份验证
    • pwd:根据 pg_pwd_enc 使用 md5scram-sha-256 密码认证
    • sha/scram-sha-256:强制 scram-sha-256 密码身份验证
    • md5md5 密码身份验证
    • ssl:在 pwd 认证基础上强制主机 SSL
    • ssl-md5:在 md5 密码认证基础上强制主机 SSL
    • ssl-sha:在 scram-sha-256 密码认证基础上强制主机 SSL
    • os/ident:使用 ident 操作系统用户身份验证
    • peer:使用 peer 身份验证
    • cert:使用基于证书的客户端身份验证
  • user:谁

  • db:哪个

    • all:所有数据库
    • replication:复制数据库
    • 临时数据库名称

3. 在哪里定义

通常,全局 HBA 在 all.vars 中定义。如果您想修改全局默认 HBA 规则,可以从 full.yml 模板复制到 all.vars 进行修改。

集群特定的 HBA 规则在数据库的集群级配置中定义:

以下是集群 HBA 规则定义的一些示例。

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_hba_rules:
      - { user: dbuser_view ,db: all    ,addr: infra        ,auth: pwd  ,title: 'allow grafana dashboard access cmdb from infra nodes'}
      - { user: all         ,db: all    ,addr: 100.0.0.0/8  ,auth: pwd  ,title: 'all user access all db from kubernetes cluster' }
      - { user: '${admin}'  ,db: world  ,addr: 0.0.0.0/0    ,auth: cert ,title: 'all admin world access with client cert'        }

重载 HBA

要重载 postgres/pgbouncer HBA 规则:

bin/pgsql-hba <cls>                 # 重载集群 `<cls>` 的 HBA 规则
bin/pgsql-hba <cls> ip1 ip2...      # 重载特定实例的 HBA 规则

底层命令是:

./pgsql.yml -l <cls> -e pg_reload=true -t pg_hba,pg_reload
./pgsql.yml -l <cls> -e pg_reload=true -t pgbouncer_hba,pgbouncer_reload

默认 HBA

Pigsty 有一套默认的 HBA 规则,对大多数情况来说都相当安全。

这些规则以别名形式自解释。

pg_default_hba_rules:             # PostgreSQL 默认基于主机的身份验证规则
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' }
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' }
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'   }
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     }
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet'}
pgb_default_hba_rules:            # pgbouncer 默认基于主机的身份验证规则
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' }
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' }

安全增强

对于那些关键情况,我们有一个 safe.yml 模板,以下 HBA 规则集作为参考:

pg_default_hba_rules:             # PostgreSQL 默认基于主机的认证规则
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: ssl   ,title: 'replicator replication from localhost'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: ssl   ,title: 'replicator replication from intranet' }
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: ssl   ,title: 'replicator postgres db from intranet' }
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: ssl   ,title: 'monitor from infra host with password'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: cert  ,title: 'admin @ everywhere with ssl & cert'   }
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: ssl   ,title: 'pgbouncer read/write via local socket'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: ssl   ,title: 'read/write biz user via password'     }
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: ssl   ,title: 'allow etl offline tasks from intranet'}
pgb_default_hba_rules:            # pgbouncer 基于主机的身份验证规则
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: ssl   ,title: 'monitor access via intranet with pwd' }
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: ssl   ,title: 'admin access via intranet with pwd'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: ssl   ,title: 'allow all user intra access with pwd' }

12 - 权限

使用默认角色和权限进行数据库访问控制

Pigsty 具有一套默认的角色系统,包含四个 默认角色 和四个 默认用户

默认用户 用户描述 默认角色 角色描述
postgres 系统超级用户 dbrole_readonly 全局只读权限角色
replicator 系统复制用户 dbrole_readwrite 全局读写权限角色
dbuser_dba PostgreSQL 管理员用户 dbrole_admin 对象创建权限角色
dbuser_monitor PostgreSQL 监控用户 dbrole_offline 受限只读权限角色

概览

角色名称 属性 所属角色 描述
dbrole_readonly NOLOGIN 全局只读权限角色
dbrole_readwrite NOLOGIN dbrole_readonly 全局读写权限角色
dbrole_admin NOLOGIN pg_monitor,dbrole_readwrite 对象创建权限角色
dbrole_offline NOLOGIN 受限只读权限角色
postgres SUPERUSER 系统超级用户
replicator REPLICATION pg_monitor,dbrole_readonly 系统复制用户
dbuser_dba SUPERUSER dbrole_admin PostgreSQL 管理员用户
dbuser_monitor pg_monitor PostgreSQL 监控用户
pg_default_roles:                 # PostgreSQL 集群中的默认角色和用户
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
  - { name: postgres     ,superuser: true  ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
  - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

默认角色

Pigsty 中有四个默认角色:

  • 只读角色(dbrole_readonly):全局只读权限访问角色
  • 读写角色(dbrole_readwrite):全局读写权限访问角色,继承 dbrole_readonly
  • 管理员角色(dbrole_admin):DDL 命令权限角色,继承 dbrole_readwrite
  • 离线角色(dbrole_offline):受限只读权限访问角色(离线 实例)

默认角色在 pg_default_roles 中定义,不建议修改默认角色。

- { name: dbrole_readonly  , login: false , comment: role for global read-only access  }                            # 生产只读角色
- { name: dbrole_offline ,   login: false , comment: role for restricted read-only access (offline instance) }      # 受限只读角色
- { name: dbrole_readwrite , login: false , roles: [dbrole_readonly], comment: role for global read-write access }  # 生产读写角色
- { name: dbrole_admin , login: false , roles: [pg_monitor, dbrole_readwrite] , comment: role for object creation } # 生产 DDL 变更角色

默认用户

Pigsty 中也有四个默认用户。

  • 超级用户(postgres),集群的拥有者和创建者,与操作系统数据库超级用户相同
  • 复制用户(replicator),用于主从复制的系统用户
  • 监控用户(dbuser_monitor),用于监控数据库和连接池指标的用户
  • 管理员用户(dbuser_dba),执行日常操作和数据库变更的管理员用户

默认用户的用户名/密码由专用参数定义(除了数据库超级用户密码):

!> 请记住在生产部署中更改这些密码!

pg_dbsu: postgres                             # 数据库的操作系统用户
pg_replication_username: replicator           # 系统复制用户
pg_replication_password: DBUser.Replicator    # 系统复制用户密码
pg_monitor_username: dbuser_monitor           # 系统监控用户
pg_monitor_password: DBUser.Monitor           # 系统监控用户密码
pg_admin_username: dbuser_dba                 # 系统管理员用户
pg_admin_password: DBUser.DBA                 # 系统管理员用户密码

要定义额外选项,请在 pg_default_roles 中指定:

- { name: postgres     ,superuser: true                                          ,comment: system superuser }
- { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
- { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
- { name: dbuser_monitor   ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

权限管理

Pigsty 具有一套开箱即用的权限模型,与 默认角色 配合使用。

  • 所有用户都可以访问所有 Schema
  • 只读用户可以从所有表读取数据(SELECT、EXECUTE)
  • 读写用户可以向所有表写入数据并运行 DML(INSERT、UPDATE、DELETE)
  • 管理员用户可以创建对象并运行 DDL(CREATE、USAGE、TRUNCATE、REFERENCES、TRIGGER)
  • 离线用户是在离线实例上具有受限访问权限的只读用户(pg_role = 'offline'pg_offline_query = true
  • 由管理员用户创建的对象将具有正确的权限
  • 默认权限安装在所有数据库上,包括模板数据库
  • 数据库连接权限由数据库 定义 覆盖
  • 默认情况下,数据库和 public schema 的 CREATE 权限从 PUBLIC 撤销

对象权限

默认对象权限在 pg_default_privileges 中定义。

- GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
- GRANT SELECT     ON TABLES    TO dbrole_readonly
- GRANT SELECT     ON SEQUENCES TO dbrole_readonly
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
- GRANT USAGE      ON SCHEMAS   TO dbrole_offline
- GRANT SELECT     ON TABLES    TO dbrole_offline
- GRANT SELECT     ON SEQUENCES TO dbrole_offline
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
- GRANT INSERT     ON TABLES    TO dbrole_readwrite
- GRANT UPDATE     ON TABLES    TO dbrole_readwrite
- GRANT DELETE     ON TABLES    TO dbrole_readwrite
- GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
- GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
- GRANT TRUNCATE   ON TABLES    TO dbrole_admin
- GRANT REFERENCES ON TABLES    TO dbrole_admin
- GRANT TRIGGER    ON TABLES    TO dbrole_admin
- GRANT CREATE     ON SCHEMAS   TO dbrole_admin

当新创建的对象由管理员用户创建时,它们将具有相应的权限。

\ddp+ 命令的输出可能如下所示:

类型 访问权限
function =X
dbrole_readonly=X
dbrole_offline=X
dbrole_admin=X
schema dbrole_readonly=U
dbrole_offline=U
dbrole_admin=UC
sequence dbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=wU
dbrole_admin=rwU
table dbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=awd
dbrole_admin=arwdDxt

默认权限

ALTER DEFAULT PRIVILEGES 允许您设置将应用于未来创建的对象的权限。它不会影响分配给已存在对象的权限,也不会影响由非管理员用户创建的对象。

Pigsty 将使用以下默认权限:

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_dbsu }} {{ priv }};
{% endfor %}

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_admin_username }} {{ priv }};
{% endfor %}

-- 对于额外的业务管理员,他们可以使用 SET ROLE 切换到 dbrole_admin
{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE "dbrole_admin" {{ priv }};
{% endfor %}

这些权限将在 pg-init-template.sql 中与管理员用户的 ALTER DEFAULT PRIVILEGES 语句一起渲染。

这些 SQL 命令将在集群引导期间在 postgrestemplate1 上执行,新创建的数据库将默认从 template1 继承它们。

也就是说,要维护正确的对象权限,您必须使用管理员用户运行 DDL,这些用户可以是:

  1. {{ pg_dbsu }},默认为 postgres
  2. {{ pg_admin_username }},默认为 dbuser_dba
  3. 被授予 dbrole_admin 权限的业务管理员用户

明智的做法是使用 postgres 作为全局对象拥有者来执行 DDL 变更。 如果您希望使用业务管理员用户创建对象,您必须在运行该 DDL 之前使用 SET ROLE dbrole_admin 来维护正确的权限。

您也可以使用 ALTER DEFAULT PRIVILEGE FOR ROLE <some_biz_admin> XXX 来为业务管理员用户授予默认权限。


数据库权限

数据库权限由 数据库定义 覆盖。

有 3 个数据库级别的权限:CONNECTCREATETEMP,以及一个特殊的"权限":OWNERSHIP

- name: meta         # 必需,`name` 是数据库定义的唯一必需字段
  owner: postgres    # 可选,指定数据库拥有者,默认为 {{ pg_dbsu }}
  allowconn: true    # 可选,允许连接,默认为 true。false 将完全禁用连接
  revokeconn: false  # 可选,撤销公共连接权限。默认为 false。(将连接权限留给拥有者并授予授权选项)
  • 如果 owner 存在,它将用作数据库拥有者,而不是默认的 {{ pg_dbsu }}
  • 如果 revokeconnfalse,所有用户都具有数据库的 CONNECT 权限,这是默认行为
  • 如果 revokeconn 明确设置为 true
  • 数据库的 CONNECT 权限将从 PUBLIC 撤销
  • CONNECT 权限将授予 {{ pg_replication_username }}{{ pg_monitor_username }}{{ pg_admin_username }}
  • CONNECT 权限将授予数据库拥有者并带有 GRANT OPTION

revokeconn 标志可用于数据库访问隔离,您可以为每个数据库创建不同的业务用户作为拥有者,并为所有数据库设置 revokeconn 选项。


创建权限

出于安全考虑,Pigsty 默认从 PUBLIC 撤销数据库上的 CREATE 权限。这也是 PostgreSQL 15 以来的默认行为。

数据库拥有者具有根据需要调整这些权限的完全能力。

13 - 面板

查看可视化信息

PostgreSQL 集群的 Grafana 监控面板:演示图库

pigsty-dashboard.jpg

共有 26 个关于 PostgreSQL 的默认 Grafana 监控面板,分为 4 个层级,并按数据源分为 PGSQLPGCATPGLOG

概览

  • pgsql-overview:PGSQL 模块的主要监控面板
  • pgsql-alert:全局 PGSQL 关键指标和告警事件
  • pgsql-shard:水平分片 PGSQL 集群概览,例如 citus / gpsql 集群

集群

  • pgsql-cluster:PGSQL 集群的主要监控面板
  • pgrds-cluster:RDS 的 PGSQL 集群监控面板,仅关注所有 postgres 指标
  • pgsql-activity:关注 PGSQL 集群的会话/负载/QPS/TPS/锁
  • pgsql-replication:关注 PGSQL 集群复制、槽位和发布/订阅
  • pgsql-service:关注 PGSQL 集群服务、代理、路由和负载均衡器
  • pgsql-databases:关注数据库 CRUD、慢查询和跨所有实例的表统计
  • pgsql-patroni:关注集群高可用代理 patroni 状态
  • pgsql-pitr:关注 PITR 过程中集群状态的上下文

实例

  • pgsql-instance:单个 PGSQL 实例的主要监控面板
  • pgrds-instance:RDS 的 PGSQL 实例监控面板,仅关注所有 postgres 指标
  • pgcat-instance:直接从数据库目录获取的实例信息
  • pgsql-persist:关于持久化的指标:WAL、XID、检查点、归档、IO
  • pgsql-proxy:关于服务提供商 haproxy 的指标
  • pgsql-queries:单个实例中所有查询的概览
  • pgsql-session:单个实例中关于会话和活动/空闲时间的指标
  • pgsql-xacts:关于事务、锁、查询等的指标
  • pgsql-exporter:Postgres 和 Pgbouncer 导出器自监控指标

数据库

  • pgsql-database:单个 PGSQL 数据库的主要监控面板
  • pgcat-database:直接从数据库目录获取的数据库信息
  • pgsql-tables:单个数据库内的表/索引访问指标
  • pgsql-table:单个表的详细信息(QPS/RT/索引/顺序扫描…)
  • pgcat-table:直接从数据库目录获取的单个表的详细信息(统计/膨胀/…)
  • pgsql-query:单个查询的详细信息(QPS/RT)
  • pgcat-query:直接从数据库目录获取的单个查询的详细信息(SQL/统计)

概览

PGSQL 概览:PGSQL 模块的主要监控面板

PGSQL 告警:全局 PGSQL 关键指标和告警事件

PGSQL 分片:水平分片 PGSQL 集群概览,例如 CITUS / GPSQL 集群


集群

PGSQL 集群:PGSQL 集群的主要监控面板

PGRDS 集群:RDS 的 PGSQL 集群监控面板,仅关注所有 postgres 指标

PGSQL 服务:关注 PGSQL 集群服务、代理、路由和负载均衡器

PGSQL 活动:关注 PGSQL 集群的会话/负载/QPS/TPS/锁

PGSQL 复制:关注 PGSQL 集群复制、槽位和发布/订阅

PGSQL 数据库集:关注数据库 CRUD、慢查询和跨所有实例的表统计

PGSQL Patroni:关注集群高可用代理 patroni 状态

PGSQL PITR:关注 PITR 过程中集群状态的上下文


实例

PGSQL 实例:单个 PGSQL 实例的主要监控面板

PGRDS 实例:RDS 的 PGSQL 实例监控面板,仅关注所有 postgres 指标

PGSQL 代理:关于服务提供商 haproxy 的指标

PGSQL Pgbouncer:关于单个 pgbouncer 连接池实例的指标

PGSQL 持久化:关于持久化的指标:WAL、XID、检查点、归档、IO

PGSQL 事务:关于事务、锁、查询等的指标

PGSQL 会话:单个实例中关于会话和活动/空闲时间的指标

PGSQL 导出器:Postgres 和 Pgbouncer 导出器自监控指标


数据库

PGSQL 数据库:单个 PGSQL 数据库的主要监控面板

PGSQL 表:单个数据库内的表/索引访问指标

PGSQL 表详情:单个表的详细信息(QPS/RT/索引/顺序扫描…)

PGSQL 查询:单个查询的详细信息(QPS/RT)


PGCAT

PGCAT 实例:直接从数据库目录获取的实例信息

PGCAT 数据库:直接从数据库目录获取的数据库信息

PGCAT 模式:直接从数据库目录获取的单个模式的详细信息

PGCAT 表详情:直接从数据库目录获取的单个表的详细信息

PGCAT 查询:直接从数据库目录获取的单类查询的详细信息

PGCAT 锁:直接从数据库目录获取的活动锁和活动的详细信息


PGLOG

PGLOG 概览:Pigsty 元数据库中 CSV 日志样本的概览

PGLOG 详情:Pigsty 元数据库中 CSV 日志样本的单个会话详情

14 - 迁移

零宕机蓝绿部署

Pigsty 有一个内置的 playbook pgsql-migration.yml 来执行基于逻辑复制的在线数据库迁移。

通过适当的自动化,宕机时间可以最小化到几秒钟。但请注意,逻辑复制需要 PostgreSQL 10+ 才能工作。 您仍然可以使用这里的工具,并使用 pg_dump | psql 代替逻辑复制。


定义迁移任务

您必须创建一个迁移任务定义文件来使用此 playbook。

查看 files/migration/pg-meta.yml 作为示例。

它将尝试将 pg-meta.meta 迁移到 pg-test.test

pg-meta-1	10.10.10.10  --> pg-test-1	10.10.10.11 (10.10.10.12,10.10.10.13)

您必须告诉 Pigsty 源集群和目标集群在哪里。要迁移的数据库以及主 IP 地址。

您应该在两端都有超级用户权限才能继续

您可以使用 src_pg 覆盖到源集群的超级用户连接,使用 sub_conn 覆盖逻辑复制连接字符串,否则将使用 Pigsty 默认的管理员和复制器凭据。

---
#-----------------------------------------------------------------
# PG_MIGRATION
#-----------------------------------------------------------------
context_dir: ~/migration           # 迁移手册和脚本
#-----------------------------------------------------------------
# SRC 集群(旧集群)
#-----------------------------------------------------------------
src_cls: pg-meta      # 源集群名称         <必填>
src_db: meta          # 源数据库名称        <必填>
src_ip: 10.10.10.10   # 源集群主 IP        <必填>
#src_pg: ''            # 如果定义,使用此作为源 dbsu pgurl 而不是:
#                      # postgres://{{ pg_admin_username }}@{{ src_ip }}/{{ src_db }}
#                      # 例如 'postgres://dbuser_dba:[email protected]:5432/meta'
#sub_conn: ''          # 如果定义,使用此作为订阅 connstr 而不是:
#                      # host={{ src_ip }} dbname={{ src_db }} user={{ pg_replication_username }}'
#                      # 例如 'host=10.10.10.10 dbname=meta user=replicator password=DBUser.Replicator'
#-----------------------------------------------------------------
# DST 集群(新集群)
#-----------------------------------------------------------------
dst_cls: pg-test      # 目标集群名称         <必填>
dst_db: test          # 目标数据库名称        <必填>
dst_ip: 10.10.10.11   # 目标集群主 IP        <必填>
#dst_pg: ''            # 如果定义,使用此作为目标 dbsu pgurl 而不是:
#                      # postgres://{{ pg_admin_username }}@{{ dst_ip }}/{{ dst_db }}
#                      # 例如 'postgres://dbuser_dba:[email protected]:5432/test'
#-----------------------------------------------------------------
# PGSQL
#-----------------------------------------------------------------
pg_dbsu: postgres
pg_replication_username: replicator
pg_replication_password: DBUser.Replicator
pg_admin_username: dbuser_dba
pg_admin_password: DBUser.DBA
pg_monitor_username: dbuser_monitor
pg_monitor_password: DBUser.Monitor
#-----------------------------------------------------------------
...

生成计划

该 playbook 不会将源迁移到目标,但它会生成您需要执行此操作的所有内容。

执行后,您将在默认的 ~/migration/pg-meta.meta 下找到迁移上下文目录

按照 README.md 并逐一执行这些脚本,您就能完成此操作!

# 此脚本将使用环境变量设置迁移上下文
. ~/migration/pg-meta.meta/activate

# 这些脚本用于检查源集群状态
# 并帮助在 Pigsty 中生成新的集群定义
./check-user     # 检查源用户
./check-db       # 检查源数据库
./check-hba      # 检查源 hba 规则
./check-repl     # 检查源副本标识
./check-misc     # 检查源特殊对象

# 这些脚本用于在现有源集群和 Pigsty 管理的目标集群之间
# 构建逻辑复制
# 架构、数据将实时同步,除了序列
./copy-schema    # 将架构复制到目标
./create-pub     # 在源上创建发布
./create-sub     # 在目标上创建订阅
./copy-progress  # 打印逻辑复制进度
./copy-diff      # 通过计数表快速比较源和目标差异

# 这些脚本将在在线迁移中运行,它们将
# 停止源集群,复制序列号(逻辑复制不会同步)
# 您必须根据您的访问方法重新路由您的应用流量(dns,vip,haproxy,pgbouncer 等...)
# 然后执行清理以删除订阅和发布
./copy-seq [n]   # 同步序列号,如果给定 n,将应用额外的偏移
#./disable-src   # 限制源集群仅对管理节点和新集群的访问(您的实现)
#./re-routing    # 将应用程序流量从源路由到目标!            (您的实现)
./drop-sub       # 迁移后在目标上删除订阅
./drop-pub       # 迁移后在源上删除发布

注意事项

您可以使用 ./copy-seq 1000 在同步序列后将所有序列提前一个数字(例如 1000)。这可能会防止新集群中潜在的串行主键冲突。

您必须实现自己的 ./re-routing 脚本来将应用程序流量从源路由到目标。因为我们不知道您的流量是如何路由的(例如 dns、VIP、haproxy 或 pgbouncer)。当然,您总是可以手动完成…

您必须实现自己的 ./disable-src 脚本来限制源集群。您可以通过更改 HBA 规则并重新加载(推荐)来做到这一点,或者只是关闭 postgres、pgbouncer 或 haproxy…

15 - 备份

备份和时间点恢复

Pigsty 使用 pgBackRest 管理 PostgreSQL 备份,它可能是生态系统中最强大的开源备份工具。 具有增量/并行备份和恢复、加密、MinIO / S3 支持以及许多其他功能。 Pigsty 默认为每个 PGSQL 集群预配置了它。

策略
    备份脚本、调度、pgbackrest、仓库和管理
管理
    备份策略、磁盘规划、恢复窗口权衡
恢复
    使用 playbook 恢复到特定时间点
示例
    沙箱示例:手动执行恢复
无质保承诺

Pigsty 尽力提供可靠的 PITR 解决方案,但我们不对 PITR 操作导致的数据丢失承担任何责任,请自行承担风险使用。 如需专业支持,请考虑我们的 专业服务


快速开始

步骤 1

    [备份策略](/zh/docs/pgsql/backup/mechanism):使用 Crontab 调度基础备份

步骤 2

    [WAL 归档](/zh/docs/pgsql/backup/policy):持续记录写入活动

步骤 3

    [恢复和还原](/zh/docs/pgsql/backup/restore):从备份和 WAL 归档中恢复
每天凌晨 1 点全量备份
node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ]
恢复到时间点
./pgsql-pitr.yml -e '{"pg_pitr": { "time": "2025-07-13 10:00:00+00" }}'

15.1 - 备份机制

备份脚本、调度、仓库和基础设施

备份可以通过内置 脚本 调用,使用节点 crontab 调度, 由 pgbackrest 管理,并存储在备份仓库中, 仓库可以是本地磁盘文件系统或 MinIO / S3,具有不同的 保留 策略。


备份脚本

您可以使用 pg_dbsu 用户(默认为 postgres)通过 pgbackrest 命令创建备份:

pgbackrest --stanza=pg-meta --type=full backup   # 为集群 pg-meta 创建全量备份
$ pgbackrest --stanza=pg-meta --type=full backup
2025-07-15 01:36:57.007 P00   INFO: backup command begin 2.54.2: --annotation=pg_cluster=pg-meta --compress-type=lz4 --delta --exec-id=88380-4b22e767 --expire-auto --log-level-console=info --log-level-file=info --log-path=/pg/log/pgbackrest --pg1-path=/pg/data --pg1-port=5432 --repo1-block --repo1-bundle --repo1-bundle-limit=20MiB --repo1-bundle-size=128MiB --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/pgbackrest --repo1-retention-full=14 --repo1-retention-full-type=time --repo1-s3-bucket=pgsql --repo1-s3-endpoint=sss.pigsty --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --repo1-s3-uri-style=path --repo1-storage-ca-file=/etc/pki/ca.crt --repo1-storage-port=9000 --repo1-type=s3 --stanza=pg-meta --start-fast --type=full
2025-07-15 01:36:57.030 P00   INFO: execute non-exclusive backup start: backup begins after the requested immediate checkpoint completes
2025-07-15 01:36:57.105 P00   INFO: backup start archive = 000000010000000000000006, lsn = 0/6000028
2025-07-15 01:36:57.105 P00   INFO: check archive for prior segment 000000010000000000000005
2025-07-15 01:36:58.403 P00   INFO: execute non-exclusive backup stop and wait for all WAL segments to archive
2025-07-15 01:36:58.421 P00   INFO: backup stop archive = 000000010000000000000006, lsn = 0/6000120
2025-07-15 01:36:58.424 P00   INFO: check archive for segment(s) 000000010000000000000006:000000010000000000000006
2025-07-15 01:36:58.540 P00   INFO: new backup label = 20250715-013657F
2025-07-15 01:36:58.588 P00   INFO: full backup size = 44.5MB, file total = 1437
2025-07-15 01:36:58.589 P00   INFO: backup command end: completed successfully (1584ms)
2025-07-15 01:36:58.589 P00   INFO: expire command begin 2.54.2: --exec-id=88380-4b22e767 --log-level-console=info --log-level-file=info --log-path=/pg/log/pgbackrest --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/pgbackrest --repo1-retention-full=14 --repo1-retention-full-type=time --repo1-s3-bucket=pgsql --repo1-s3-endpoint=sss.pigsty --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --repo1-s3-uri-style=path --repo1-storage-ca-file=/etc/pki/ca.crt --repo1-storage-port=9000 --repo1-type=s3 --stanza=pg-meta
2025-07-15 01:36:58.593 P00   INFO: repo1: time-based archive retention not met - archive logs will not be expired
2025-07-15 01:36:58.593 P00   INFO: expire command end: completed successfully (4ms)
$ pgbackrest --stanza=pg-meta --type=diff backup
2025-07-15 01:37:24.952 P00   INFO: backup command begin 2.54.2: --annotation=pg_cluster=pg-meta --compress-type=lz4 --delta --exec-id=88431-1b8ca3e0 --expire-auto --log-level-console=info --log-level-file=info --log-path=/pg/log/pgbackrest --pg1-path=/pg/data --pg1-port=5432 --repo1-block --repo1-bundle --repo1-bundle-limit=20MiB --repo1-bundle-size=128MiB --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/pgbackrest --repo1-retention-full=14 --repo1-retention-full-type=time --repo1-s3-bucket=pgsql --repo1-s3-endpoint=sss.pigsty --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --repo1-s3-uri-style=path --repo1-storage-ca-file=/etc/pki/ca.crt --repo1-storage-port=9000 --repo1-type=s3 --stanza=pg-meta --start-fast --type=diff
2025-07-15 01:37:24.985 P00   INFO: last backup label = 20250715-013657F, version = 2.54.2
2025-07-15 01:37:24.985 P00   INFO: execute non-exclusive backup start: backup begins after the requested immediate checkpoint completes
2025-07-15 01:37:25.045 P00   INFO: backup start archive = 000000010000000000000008, lsn = 0/8000028
2025-07-15 01:37:25.045 P00   INFO: check archive for prior segment 000000010000000000000007
2025-07-15 01:37:26.204 P00   INFO: execute non-exclusive backup stop and wait for all WAL segments to archive
2025-07-15 01:37:26.220 P00   INFO: backup stop archive = 000000010000000000000008, lsn = 0/8000158
2025-07-15 01:37:26.223 P00   INFO: check archive for segment(s) 000000010000000000000008:000000010000000000000008
2025-07-15 01:37:26.337 P00   INFO: new backup label = 20250715-013657F_20250715-013724D
2025-07-15 01:37:26.381 P00   INFO: diff backup size = 424.3KB, file total = 1437
2025-07-15 01:37:26.381 P00   INFO: backup command end: completed successfully (1431ms)
2025-07-15 01:37:26.381 P00   INFO: expire command begin 2.54.2: --exec-id=88431-1b8ca3e0 --log-level-console=info --log-level-file=info --log-path=/pg/log/pgbackrest --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/pgbackrest --repo1-retention-full=14 --repo1-retention-full-type=time --repo1-s3-bucket=pgsql --repo1-s3-endpoint=sss.pigsty --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --repo1-s3-uri-style=path --repo1-storage-ca-file=/etc/pki/ca.crt --repo1-storage-port=9000 --repo1-type=s3 --stanza=pg-meta
2025-07-15 01:37:26.386 P00   INFO: repo1: time-based archive retention not met - archive logs will not be expired
2025-07-15 01:37:26.386 P00   INFO: expire command end: completed successfully (5ms)
$ pgbackrest --stanza=pg-meta --type=incr backup
2025-07-15 01:37:30.305 P00   INFO: backup command begin 2.54.2: --annotation=pg_cluster=pg-meta --compress-type=lz4 --delta --exec-id=88449-eba235f7 --expire-auto --log-level-console=info --log-level-file=info --log-path=/pg/log/pgbackrest --pg1-path=/pg/data --pg1-port=5432 --repo1-block --repo1-bundle --repo1-bundle-limit=20MiB --repo1-bundle-size=128MiB --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/pgbackrest --repo1-retention-full=14 --repo1-retention-full-type=time --repo1-s3-bucket=pgsql --repo1-s3-endpoint=sss.pigsty --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --repo1-s3-uri-style=path --repo1-storage-ca-file=/etc/pki/ca.crt --repo1-storage-port=9000 --repo1-type=s3 --stanza=pg-meta --start-fast --type=incr
2025-07-15 01:37:30.337 P00   INFO: last backup label = 20250715-013657F_20250715-013724D, version = 2.54.2
2025-07-15 01:37:30.337 P00   INFO: execute non-exclusive backup start: backup begins after the requested immediate checkpoint completes
2025-07-15 01:37:30.383 P00   INFO: backup start archive = 000000010000000000000009, lsn = 0/9000028
2025-07-15 01:37:30.383 P00   INFO: check archive for segment 000000010000000000000009
2025-07-15 01:37:31.191 P00   INFO: execute non-exclusive backup stop and wait for all WAL segments to archive
2025-07-15 01:37:31.230 P00   INFO: backup stop archive = 00000001000000000000000A, lsn = 0/A000050
2025-07-15 01:37:31.232 P00   INFO: check archive for segment(s) 000000010000000000000009:00000001000000000000000A
2025-07-15 01:37:31.356 P00   INFO: new backup label = 20250715-013657F_20250715-013730I
2025-07-15 01:37:31.403 P00   INFO: incr backup size = 8.3KB, file total = 1437
2025-07-15 01:37:31.403 P00   INFO: backup command end: completed successfully (1099ms)
2025-07-15 01:37:31.403 P00   INFO: expire command begin 2.54.2: --exec-id=88449-eba235f7 --log-level-console=info --log-level-file=info --log-path=/pg/log/pgbackrest --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/pgbackrest --repo1-retention-full=14 --repo1-retention-full-type=time --repo1-s3-bucket=pgsql --repo1-s3-endpoint=sss.pigsty --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --repo1-s3-uri-style=path --repo1-storage-ca-file=/etc/pki/ca.crt --repo1-storage-port=9000 --repo1-type=s3 --stanza=pg-meta
2025-07-15 01:37:31.409 P00   INFO: repo1: time-based archive retention not met - archive logs will not be expired
2025-07-15 01:37:31.409 P00   INFO: expire command end: completed successfully (6ms)
$ pgbackrest --stanza=pg-meta info
stanza: pg-meta
    status: ok
    cipher: aes-256-cbc

    db (current)
        wal archive min/max (17): 000000010000000000000001/00000001000000000000000A

        full backup: 20250715-013441F
            timestamp start/stop: 2025-07-15 01:34:41+00 / 2025-07-15 01:34:43+00
            wal start/stop: 000000010000000000000004 / 000000010000000000000004
            database size: 43.9MB, database backup size: 43.9MB
            repo1: backup size: 8.3MB

        full backup: 20250715-013657F
            timestamp start/stop: 2025-07-15 01:36:57+00 / 2025-07-15 01:36:58+00
            wal start/stop: 000000010000000000000006 / 000000010000000000000006
            database size: 44.5MB, database backup size: 44.5MB
            repo1: backup size: 8.7MB

        diff backup: 20250715-013657F_20250715-013724D
            timestamp start/stop: 2025-07-15 01:37:24+00 / 2025-07-15 01:37:26+00
            wal start/stop: 000000010000000000000008 / 000000010000000000000008
            database size: 44.5MB, database backup size: 424.3KB
            repo1: backup size: 94KB
            backup reference total: 1 full

        incr backup: 20250715-013657F_20250715-013730I
            timestamp start/stop: 2025-07-15 01:37:30+00 / 2025-07-15 01:37:31+00
            wal start/stop: 000000010000000000000009 / 00000001000000000000000A
            database size: 44.5MB, database backup size: 8.3KB
            repo1: backup size: 504B
            backup reference total: 1 full, 1 diff

这里的 stanza 是数据库集群名称:pg_cluster,对于默认设置是 pg-meta

Pigsty 有一个别名 pb 和包装脚本 pg-backup,它们将当前集群名称填充为 stanza:

alias
function pb() {
    local stanza=$(grep -o '\[[^][]*]' /etc/pgbackrest/pgbackrest.conf | head -n1 | sed 's/.*\[\([^]]*\)].*/\1/')
    pgbackrest --stanza=$stanza $@
}
pb ...    # pgbackrest --stanza=pg-meta ...
pb info   # pgbackrest --stanza=pg-meta info
pb backup # pgbackrest --stanza=pg-meta backup
script
pg-backup full   # 进行全量备份         = pgbackrest --stanza=pg-meta --type=full backup
pg-backup incr   # 进行增量备份  = pgbackrest --stanza=pg-meta --type=incr backup
pg-backup diff   # 进行差异备份 = pgbackrest --stanza=pg-meta --type=diff backup

定时调度

Pigsty 利用 Linux 的 crontab 来调度备份。您可以使用它定义您的备份策略。

例如,大多数单节点配置模板将为备份设置以下 node_crontab

每日凌晨1点全量备份
node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ]

您可以使用 crontab 和 pg-backup 脚本设计更复杂的备份策略,例如:

周一全量备份,工作日增量备份
node_crontab:  # 周一凌晨 1 点进行全量备份,工作日进行增量备份
  - '00 01 * * 1 postgres /pg/bin/pg-backup full'
  - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

要应用 crontab 更改,使用 node.yml 在所有节点上更新 crontab。

应用 crontab
./node.yml -t node_crontab -l pg-meta    # 将 crontab 更改应用到 pg-meta 组

pgbackrest

以下是 Pigsty 对 pgbackrest 的设置详情:

文件系统层次结构

  • 二进制文件:/usr/bin/pgbackrest,来自 PGDG 的 pgbackrest 包,在组别名 pgsql-common 中。
  • 配置:/etc/pgbackrest,主配置是 /etc/pgbackrest/pgbackrest.conf
  • 日志:/pg/log/pgbackrest/*,由 pgbackrest_log_dir 控制
  • 临时文件:/pg/spool 用作 pgbackrest 的临时缓冲目录
  • 数据:如果选择默认的 local 文件系统备份仓库,则使用 /pg/backup

此外,在 PITR 恢复 过程中, Pigsty 将创建一个临时的 /pg/conf/pitr.conf pgbackrest 配置文件。 并将 PostgreSQL 恢复日志写入 /pg/tmp/recovery.log 文件。

监控

有一个 pgbackrest_exporter 服务运行在(pgbackrest_exporter_port9854)上以导出 pgbackrest 指标。 您可以通过 pgbackrest_exporter_options 自定义它,并通过将 pgbackrest_exporter_enabled 设置为 false 来禁用它。

初始备份

当创建 PostgreSQL 集群时,Pigsty 会自动创建初始备份。 这是一个小备份,因为新集群几乎是空的。 它会留下一个标记文件 /etc/pgbackrest/initial.done 以避免再次创建初始备份。 如果您不想要它,请将 pgbackrest_init_backup 设置为 false


管理

启用备份

如果您的数据库集群是在 pgbackrest_enable 设置为 true 的情况下创建的,备份将自动启用。

如果是在 false 值下创建的,您可以使用以下命令启用 pgbackrest 组件:

./pgsql.yml -t pg_backup    # 运行 pgbackrest 子任务

移除备份

Pigsty 在移除主实例(pg_role = primary)时会移除 pgbackrest 备份 stanza。

./pgsql-rm.yml
./pgsql-rm.yml -e pg_rm_backup=false   # 保持备份完整
./pgsql-rm.yml -t pg_backup            # 仅移除备份

使用 pg_backup 子任务仅移除备份,并使用 pg_rm_backup 参数保留备份。

如果您的备份仓库被锁定(例如,S3 / MinIO 有锁定选项),此操作将失败。

备份移除

移除备份可能导致永久数据丢失,这是一个危险操作,请极其谨慎地执行。

列出备份

此命令将列出 pgbackrest 仓库中的所有备份(由所有集群共享)

pgbackrest info

手动备份

Pigsty 有一个内置脚本 /pg/bin/pg-backup,它封装了 pgbackrest 备份命令。

pg-backup        # 进行增量备份
pg-backup full   # 进行全量备份
pg-backup incr   # 进行增量备份
pg-backup diff   # 进行差异备份

基础备份

Pigsty 有一个替代备份脚本 /pg/bin/pg-basebackup,它不依赖 pgbackrest,并为您提供数据库集群的物理副本。 默认备份目录是 /pg/backup

NAME
  pg-basebackup  -- make base backup from PostgreSQL instance

SYNOPSIS
  pg-basebackup -sdfeukr
  pg-basebackup --src postgres:/// --dst . --file backup.tar.lz4

DESCRIPTION
-s, --src, --url     Backup source URL, optional, "postgres:///" by default, if password is required, it should be given in url, ENV or .pgpass
-d, --dst, --dir     Where to put backup files, "/pg/backup" by default
-f, --file           Overwrite default backup filename, "backup_${tag}_${date}.tar.lz4"
-r, --remove         .lz4 Files mtime before n minutes ago will be removed, default is 1200 (20hour)
-t, --tag            Backup file tag, if not set, target cluster_name or local ip address will be used. Also used as part of DEFAULT filename
-k, --key            Encryption key when --encrypt is specified, default key is ${tag}
-u, --upload         Upload backup files to cloud storage, (need your own implementation)
-e, --encryption     Encrypt with RC4 using OpenSSL, if not key is specified, tag is used as key
-h, --help           Print this message
postgres@pg-meta-1:~$ pg-basebackup
[2025-07-13 06:16:05][INFO] ================================================================
[2025-07-13 06:16:05][INFO] [INIT] pg-basebackup begin, checking parameters
[2025-07-13 06:16:05][DEBUG] [INIT] #====== BINARY
[2025-07-13 06:16:05][DEBUG] [INIT] pg_basebackup     :   /usr/pgsql/bin/pg_basebackup
[2025-07-13 06:16:05][DEBUG] [INIT] openssl           :   /usr/bin/openssl
[2025-07-13 06:16:05][DEBUG] [INIT] #====== PARAMETER
[2025-07-13 06:16:05][DEBUG] [INIT] filename  (-f)    :   backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][DEBUG] [INIT] src       (-s)    :   postgres:///
[2025-07-13 06:16:05][DEBUG] [INIT] dst       (-d)    :   /pg/backup
[2025-07-13 06:16:05][DEBUG] [INIT] tag       (-t)    :   pg-meta
[2025-07-13 06:16:05][DEBUG] [INIT] key       (-k)    :   pg-meta
[2025-07-13 06:16:05][DEBUG] [INIT] encrypt   (-e)    :   false
[2025-07-13 06:16:05][DEBUG] [INIT] upload    (-u)    :   false
[2025-07-13 06:16:05][DEBUG] [INIT] remove    (-r)    :   -mmin +1200
[2025-07-13 06:16:05][INFO] [LOCK] acquire lock @ /tmp/backup.lock
[2025-07-13 06:16:05][INFO] [LOCK] lock acquired success on /tmp/backup.lock, pid=107417
[2025-07-13 06:16:05][INFO] [BKUP] backup begin, from postgres:/// to /pg/backup/backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][INFO] [BKUP] backup in normal mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete

pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/7000028 on timeline 1
pg_basebackup: write-ahead log end point: 0/7000FD8
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[2025-07-13 06:16:06][INFO] [BKUP] backup complete!
[2025-07-13 06:16:06][INFO] [RMBK] remove local obsolete backup: 1200
[2025-07-13 06:16:06][INFO] [BKUP] find obsolete backups: find /pg/backup/ -maxdepth 1 -type f -mmin +1200 -name 'backup*.lz4'
[2025-07-13 06:16:06][WARN] [BKUP] remove obsolete backups:
[2025-07-13 06:16:06][INFO] [RMBK] remove old backup complete
[2025-07-13 06:16:06][INFO] [LOCK] release lock @ /tmp/backup.lock
[2025-07-13 06:16:06][INFO] [DONE] backup procedure complete!
[2025-07-13 06:16:06][INFO] ================================================================

备份使用 lz4 压缩,您可以使用以下命令解压缩和提取 tarball:

mkdir -p /tmp/data   # 将备份提取到此目录
cat /pg/backup/backup_pg-meta_20250713.tar.lz4 | unlz4 -d -c | tar -xC /tmp/data

逻辑备份

您也可以使用 pg_dump 命令执行逻辑备份。

逻辑备份不能用于 PITR(时间点恢复), 但它们对于在不同主版本之间迁移数据或实现灵活的数据导出逻辑很有用。

从仓库引导

现在假设您有一个现有集群 pg-meta,并且想要分叉它作为 pg-meta2

您需要创建新的 pg-meta2 集群分叉,然后在其上运行 pitr

15.2 - 备份仓库

PostgreSQL 的备份存储仓库

您可以通过指定 pgbackrest_repo 参数来配置存储备份的位置。 您可以在那里定义多个仓库,Pigsty 将根据 pgbackrest_method 的值选择它。

默认仓库

默认情况下,Pigsty 有两个默认备份仓库定义:localminio 备份仓库。

  • local默认,使用本地 /pg/backup 目录(软链接指向 pg_fs_backup/data/backups
  • minio:使用 SNSD 1 节点 MinIO 集群(由 pigsty 支持,但默认未启用)
pgbackrest_method: local          # 选择备份仓库方法,`local` 或 `minio` 或任何其他用户定义的仓库
pgbackrest_repo:                  # pgbackrest 仓库:https://pgbackrest.org/configuration.html#section-repository
  local:                          # 使用本地 posix fs 的默认 pgbackrest 仓库
    path: /pg/backup              # 本地备份目录,默认为 `/pg/backup`
    retention_full_type: count    # 按数量保留全量备份
    retention_full: 2             # 使用本地 fs 仓库时保留 2 个,最多 3 个全量备份
  minio:                          # pgbackrest 的可选 minio 仓库
    type: s3                      # minio 兼容 s3,所以使用 s3
    s3_endpoint: sss.pigsty       # minio 端点域名,默认为 `sss.pigsty`
    s3_region: us-east-1          # minio 区域,默认 us-east-1,对 minio 无用
    s3_bucket: pgsql              # minio 存储桶名称,默认为 `pgsql`
    s3_key: pgbackrest            # pgbackrest 的 minio 用户访问密钥
    s3_key_secret: S3User.Backup  # pgbackrest 的 minio 用户密钥
    s3_uri_style: path            # 对 minio 使用路径样式 uri 而不是主机样式
    path: /pgbackrest             # minio 备份路径,默认为 `/pgbackrest`
    storage_port: 9000            # minio 端口,默认为 9000
    storage_ca_file: /etc/pki/ca.crt  # minio ca 文件路径,默认为 `/etc/pki/ca.crt`
    block: y                      # 启用块增量备份
    bundle: y                     # 将小文件打包成单个文件
    bundle_limit: 20MiB           # 文件包限制,对象存储为 20MiB
    bundle_size: 128MiB           # 文件包目标大小,对象存储为 128MiB
    cipher_type: aes-256-cbc      # 为远程备份仓库启用 AES 加密
    cipher_pass: pgBackRest       # AES 加密密码,默认为 'pgBackRest'
    retention_full_type: time     # 在 minio 仓库上按时间保留全量备份
    retention_full: 14            # 保留最后 14 天的全量备份

保留策略

如果您每天备份而不删除它们,备份仓库将越来越大并占满您的磁盘空间。 您需要定义保留策略以仅保留有限数量的备份。

默认备份策略在 pgbackrest_repo 参数中定义,根据需要更改它们。

  • local:保留最后 2 个全量备份,备份期间最多 3 个
  • minio:保留最后 14 天内的所有全量备份

空间规划

对象存储提供几乎无限的存储容量,因此您无需担心磁盘空间。 您可以通过混合全量和差异备份策略优化空间使用。

对于本地磁盘备份仓库,pigsty 建议使用保留最后 2 个全量备份的保留策略, 这意味着在磁盘上保留两个最新的全量备份(在运行新备份时可能存在第三个副本)。

这为您提供至少最后 24 小时的保证恢复窗口。详情请查看备份策略


仓库替代方案

您也可以使用其他服务作为备份仓库,详情请查看 pgbackrest 文档


仓库版本控制

您甚至可以指定仓库目标时间以获取对象存储的快照。

您可以通过在 minio_buckets 中添加 versioning 标志来启用 MinIO 版本控制:

minio_buckets:
  - { name: pgsql ,versioning: true }
  - { name: meta  ,versioning: true }
  - { name: data }

仓库锁定

一些对象存储服务(S3、MinIO 等)支持锁定,可以防止备份被删除,即使是 DBA 本人。

您可以通过在 minio_buckets 中添加 lock 标志来启用 MinIO 锁定功能:

minio_buckets:
  - { name: pgsql , lock: true }
  - { name: meta ,versioning: true  }
  - { name: data }

使用对象存储

对象存储服务提供几乎无限的存储容量,并为您的系统提供远程灾难容错。 如果您没有对象存储,Pigsty 有内置的 MinIO 支持。

MinIO

您可以通过取消注释以下设置来启用 minio 备份仓库。 请注意,pgbackrest 只接受 HTTPS / 域名,因此您必须使用域名和 HTTPS 端点运行 MinIO。

all:
  vars:
    pgbackrest_method: minio      # 使用 minio 作为默认备份仓库
  children:                       # 定义一个单节点 minio SNSD 集群
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 }} ,vars: { minio_cluster: minio }}

S3

如果您只有一个节点,有意义的备份策略可能是使用云供应商的对象存储服务,如 AWS S3、阿里云 OSS 或 Google Cloud 等… 要实现这一点,您可以定义一个新的仓库:

pgbackrest_method: s3             # 使用 'pgbackrest_repo.s3' 作为备份仓库
pgbackrest_repo:                  # pgbackrest 仓库:https://pgbackrest.org/configuration.html#section-repository

  s3:                             # 阿里云 oss(s3 兼容)对象存储服务
    type: s3                      # oss 兼容 s3
    s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
    s3_region: oss-cn-beijing
    s3_bucket: <your_bucket_name>
    s3_key: <your_access_key>
    s3_key_secret: <your_secret_key>
    s3_uri_style: host
    path: /pgbackrest
    bundle: y                     # 将小文件打包成单个文件
    bundle_limit: 20MiB           # 文件包限制,对象存储为 20MiB
    bundle_size: 128MiB           # 文件包目标大小,对象存储为 128MiB
    cipher_type: aes-256-cbc      # 为远程备份仓库启用 AES 加密
    cipher_pass: pgBackRest       # AES 加密密码,默认为 'pgBackRest'
    retention_full_type: time     # 在 minio 仓库上按时间保留全量备份
    retention_full: 14            # 保留最后 14 天的全量备份

  local:                          # 使用本地 posix fs 的默认 pgbackrest 仓库
    path: /pg/backup              # 本地备份目录,默认为 `/pg/backup`
    retention_full_type: count    # 按数量保留全量备份
    retention_full: 2             # 使用本地 fs 仓库时保留 2 个,最多 3 个全量备份

管理备份

启用备份

如果您的数据库集群是在 pgbackrest_enable 设置为 true 的情况下创建的,备份将自动启用。

如果是在 false 值下创建的,您可以使用以下命令启用 pgbackrest 组件:

./pgsql.yml -t pg_backup    # 运行 pgbackrest 子任务

移除备份

Pigsty 在移除主实例(pg_role = primary)时会移除 pgbackrest 备份 stanza。

./pgsql-rm.yml
./pgsql-rm.yml -e pg_rm_backup=false   # 保持备份完整
./pgsql-rm.yml -t pg_backup            # 仅移除备份

使用 pg_backup 子任务仅移除备份,并使用 pg_rm_backup 参数保留备份。

如果您的备份仓库被锁定(例如,S3 / MinIO 有锁定选项),此操作将失败。

备份移除

移除备份可能导致永久数据丢失,这是一个危险操作,请极其谨慎地执行。

列出备份

此命令将列出 pgbackrest 仓库中的所有备份(由所有集群共享)

pgbackrest info

手动备份

Pigsty 有一个内置脚本 /pg/bin/pg-backup,它封装了 pgbackrest 备份命令。

pg-backup        # 进行增量备份
pg-backup full   # 进行全量备份
pg-backup incr   # 进行增量备份
pg-backup diff   # 进行差异备份

基础备份

Pigsty 有一个替代备份脚本 /pg/bin/pg-basebackup,它不依赖 pgbackrest,并为您提供数据库集群的物理副本。 默认备份目录是 /pg/backup

NAME
  pg-basebackup  -- make base backup from PostgreSQL instance

SYNOPSIS
  pg-basebackup -sdfeukr
  pg-basebackup --src postgres:/// --dst . --file backup.tar.lz4

DESCRIPTION
-s, --src, --url     Backup source URL, optional, "postgres:///" by default, if password is required, it should be given in url, ENV or .pgpass
-d, --dst, --dir     Where to put backup files, "/pg/backup" by default
-f, --file           Overwrite default backup filename, "backup_${tag}_${date}.tar.lz4"
-r, --remove         .lz4 Files mtime before n minutes ago will be removed, default is 1200 (20hour)
-t, --tag            Backup file tag, if not set, target cluster_name or local ip address will be used. Also used as part of DEFAULT filename
-k, --key            Encryption key when --encrypt is specified, default key is ${tag}
-u, --upload         Upload backup files to cloud storage, (need your own implementation)
-e, --encryption     Encrypt with RC4 using OpenSSL, if not key is specified, tag is used as key
-h, --help           Print this message
postgres@pg-meta-1:~$ pg-basebackup
[2025-07-13 06:16:05][INFO] ================================================================
[2025-07-13 06:16:05][INFO] [INIT] pg-basebackup begin, checking parameters
[2025-07-13 06:16:05][DEBUG] [INIT] #====== BINARY
[2025-07-13 06:16:05][DEBUG] [INIT] pg_basebackup     :   /usr/pgsql/bin/pg_basebackup
[2025-07-13 06:16:05][DEBUG] [INIT] openssl           :   /usr/bin/openssl
[2025-07-13 06:16:05][DEBUG] [INIT] #====== PARAMETER
[2025-07-13 06:16:05][DEBUG] [INIT] filename  (-f)    :   backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][DEBUG] [INIT] src       (-s)    :   postgres:///
[2025-07-13 06:16:05][DEBUG] [INIT] dst       (-d)    :   /pg/backup
[2025-07-13 06:16:05][DEBUG] [INIT] tag       (-t)    :   pg-meta
[2025-07-13 06:16:05][DEBUG] [INIT] key       (-k)    :   pg-meta
[2025-07-13 06:16:05][DEBUG] [INIT] encrypt   (-e)    :   false
[2025-07-13 06:16:05][DEBUG] [INIT] upload    (-u)    :   false
[2025-07-13 06:16:05][DEBUG] [INIT] remove    (-r)    :   -mmin +1200
[2025-07-13 06:16:05][INFO] [LOCK] acquire lock @ /tmp/backup.lock
[2025-07-13 06:16:05][INFO] [LOCK] lock acquired success on /tmp/backup.lock, pid=107417
[2025-07-13 06:16:05][INFO] [BKUP] backup begin, from postgres:/// to /pg/backup/backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][INFO] [BKUP] backup in normal mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete

pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/7000028 on timeline 1
pg_basebackup: write-ahead log end point: 0/7000FD8
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[2025-07-13 06:16:06][INFO] [BKUP] backup complete!
[2025-07-13 06:16:06][INFO] [RMBK] remove local obsolete backup: 1200
[2025-07-13 06:16:06][INFO] [BKUP] find obsolete backups: find /pg/backup/ -maxdepth 1 -type f -mmin +1200 -name 'backup*.lz4'
[2025-07-13 06:16:06][WARN] [BKUP] remove obsolete backups:
[2025-07-13 06:16:06][INFO] [RMBK] remove old backup complete
[2025-07-13 06:16:06][INFO] [LOCK] release lock @ /tmp/backup.lock
[2025-07-13 06:16:06][INFO] [DONE] backup procedure complete!
[2025-07-13 06:16:06][INFO] ================================================================

备份使用 lz4 压缩,您可以使用以下命令解压缩和提取 tarball:

mkdir -p /tmp/data   # 将备份提取到此目录
cat /pg/backup/backup_pg-meta_20250713.tar.lz4 | unlz4 -d -c | tar -xC /tmp/data

逻辑备份

您也可以使用 pg_dump 命令执行逻辑备份。

逻辑备份不能用于 PITR(时间点恢复), 但它们对于在不同主版本之间迁移数据或实现灵活的数据导出逻辑很有用。

从仓库引导

现在假设您有一个现有集群 pg-meta,并且想要分叉它作为 pg-meta2

您需要创建新的 pg-meta2 集群分叉,然后在其上运行 pitr

15.3 - 备份策略

根据您的需求设计备份策略。
  • 何时:备份策略
  • 何地:备份仓库
  • 如何:备份方法

何时备份

第一个问题是何时备份您的数据库——在备份频率和恢复时间之间做权衡。 由于您需要回放 WAL 日志到从上次备份以来的恢复目标, 备份越频繁,需要回放的 WAL 日志就越少,恢复就越快。

每日全量备份

对于生产数据库,建议从最简单的每日全量备份策略开始。 这是 Pigsty 中的默认备份策略,通过 crontab 实现。

每日凌晨1点全量备份
node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ]
pgbackrest_method: local          # 选择备份仓库方法,`local` 或 `minio` 或任何其他用户定义的仓库
pgbackrest_repo:                  # pgbackrest 仓库:https://pgbackrest.org/configuration.html#section-repository
  local:                          # 使用本地 POSIX 文件系统的默认 pgbackrest 仓库
    path: /pg/backup              # 本地备份目录,默认为 `/pg/backup`
    retention_full_type: count    # 按数量保留全量备份
    retention_full: 2             # 保留 2 个,使用本地文件系统仓库时最多 3 个全量备份

当使用默认的 local 文件系统备份仓库时,它提供 24~48 小时的恢复窗口。

假设您的数据库大小为 100GB,每天写入 10GB,您的备份大小将是:

它将消耗数据库大小的 2 ~ 3 倍,加上 2 天的 WAL。 因此在实践中,您可能需要准备至少数据库大小 3 ~ 5 倍 的备份磁盘 来使用默认备份策略。

全量 + 增量备份

您可以通过更改这些参数来优化备份空间使用。

如果您使用 MinIO / S3 作为集中式备份仓库,您可以使用比磁盘限制更多的空间。 那么考虑使用 2 周保留策略的全量 + 增量备份:

node_crontab:  # 周一凌晨 1 点进行全量备份,工作日进行增量备份
  - '00 01 * * 1 postgres /pg/bin/pg-backup full'
  - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'
pgbackrest_method: minio
pgbackrest_repo:                  # pgbackrest 仓库:https://pgbackrest.org/configuration.html#section-repository
  minio:                          # pgbackrest 的可选 minio 仓库
    type: s3                      # minio 兼容 s3,所以使用 s3
    s3_endpoint: sss.pigsty       # minio 端点域名,默认为 `sss.pigsty`
    s3_region: us-east-1          # minio 区域,默认为 us-east-1,对 minio 无用
    s3_bucket: pgsql              # minio 存储桶名称,默认为 `pgsql`
    s3_key: pgbackrest            # pgbackrest 的 minio 用户访问密钥
    s3_key_secret: S3User.Backup  # pgbackrest 的 minio 用户秘密密钥
    s3_uri_style: path            # 对 minio 使用路径样式 URI 而不是主机样式
    path: /pgbackrest             # minio 备份路径,默认为 `/pgbackrest`
    storage_port: 9000            # minio 端口,默认为 9000
    storage_ca_file: /etc/pki/ca.crt  # minio ca 文件路径,默认为 `/etc/pki/ca.crt`
    block: y                      # 启用块增量备份
    bundle: y                     # 将小文件打包成单个文件
    bundle_limit: 20MiB           # 文件包的限制,对象存储为 20MiB
    bundle_size: 128MiB           # 文件包的目标大小,对象存储为 128MiB
    cipher_type: aes-256-cbc      # 为远程备份仓库启用 AES 加密
    cipher_pass: pgBackRest       # AES 加密密码,默认为 'pgBackRest'
    retention_full_type: time     # 在 minio 仓库上按时间保留全量备份
    retention_full: 14            # 保留最近 14 天的全量备份

当使用内置的 minio 文件系统备份仓库时,它提供有保证的 1 周 PITR 窗口。

假设您的数据库大小为 100GB,每天写入 10GB,您的备份大小将如下所示:


备份位置

默认情况下,Pigsty 有两个默认备份仓库定义:localminio 备份仓库。

  • local默认,使用本地 /pg/backup 目录(软链接指向 pg_fs_backup/data/backups
  • minio:使用 SNSD 1 节点 MinIO 集群(由 Pigsty 支持,但默认未启用)
pgbackrest_method: local          # 选择备份仓库方法,`local` 或 `minio` 或任何其他用户定义的仓库
pgbackrest_repo:                  # pgbackrest 仓库:https://pgbackrest.org/configuration.html#section-repository
  local:                          # 使用本地 POSIX 文件系统的默认 pgbackrest 仓库
    path: /pg/backup              # 本地备份目录,默认为 `/pg/backup`
    retention_full_type: count    # 按数量保留全量备份
    retention_full: 2             # 保留 2 个,使用本地文件系统仓库时最多 3 个全量备份
  minio:                          # pgbackrest 的可选 minio 仓库
    type: s3                      # minio 兼容 s3,所以使用 s3
    s3_endpoint: sss.pigsty       # minio 端点域名,默认为 `sss.pigsty`
    s3_region: us-east-1          # minio 区域,默认为 us-east-1,对 minio 无用
    s3_bucket: pgsql              # minio 存储桶名称,默认为 `pgsql`
    s3_key: pgbackrest            # pgbackrest 的 minio 用户访问密钥
    s3_key_secret: S3User.Backup  # pgbackrest 的 minio 用户秘密密钥
    s3_uri_style: path            # 对 minio 使用路径样式 URI 而不是主机样式
    path: /pgbackrest             # minio 备份路径,默认为 `/pgbackrest`
    storage_port: 9000            # minio 端口,默认为 9000
    storage_ca_file: /etc/pki/ca.crt  # minio ca 文件路径,默认为 `/etc/pki/ca.crt`
    block: y                      # 启用块增量备份
    bundle: y                     # 将小文件打包成单个文件
    bundle_limit: 20MiB           # 文件包的限制,对象存储为 20MiB
    bundle_size: 128MiB           # 文件包的目标大小,对象存储为 128MiB
    cipher_type: aes-256-cbc      # 为远程备份仓库启用 AES 加密
    cipher_pass: pgBackRest       # AES 加密密码,默认为 'pgBackRest'
    retention_full_type: time     # 在 minio 仓库上按时间保留全量备份
    retention_full: 14            # 保留最近 14 天的全量备份

15.4 - 备份管理

管理备份仓库和备份

启用备份

如果您的数据库集群是在 pgbackrest_enable 设置为 true 的情况下创建的,备份将自动启用。

如果是在 false 值下创建的,您可以使用以下命令启用 pgbackrest 组件:

./pgsql.yml -t pg_backup    # 运行 pgbackrest 子任务

移除备份

Pigsty 在移除主实例(pg_role = primary)时会移除 pgbackrest 备份 stanza。

./pgsql-rm.yml
./pgsql-rm.yml -e pg_rm_backup=false   # 保持备份完整
./pgsql-rm.yml -t pg_backup            # 仅移除备份

使用 pg_backup 子任务仅移除备份,并使用 pg_rm_backup 参数保留备份。

如果您的备份仓库被锁定(例如,S3 / MinIO 有锁定选项),此操作将失败。

备份移除

移除备份可能导致永久数据丢失,这是一个危险操作,请极其谨慎地执行。


列出备份

此命令将列出 pgbackrest 仓库中的所有备份(由所有集群共享)

pgbackrest info

手动备份

Pigsty 有一个内置脚本 /pg/bin/pg-backup,它封装了 pgbackrest 备份命令。

pg-backup        # 进行增量备份
pg-backup full   # 进行全量备份
pg-backup incr   # 进行增量备份
pg-backup diff   # 进行差异备份

基础备份

Pigsty 有一个替代备份脚本 /pg/bin/pg-basebackup,它不依赖 pgbackrest,并为您提供数据库集群的物理副本。 默认备份目录是 /pg/backup

NAME
  pg-basebackup  -- make base backup from PostgreSQL instance

SYNOPSIS
  pg-basebackup -sdfeukr
  pg-basebackup --src postgres:/// --dst . --file backup.tar.lz4

DESCRIPTION
-s, --src, --url     Backup source URL, optional, "postgres:///" by default, if password is required, it should be given in url, ENV or .pgpass
-d, --dst, --dir     Where to put backup files, "/pg/backup" by default
-f, --file           Overwrite default backup filename, "backup_${tag}_${date}.tar.lz4"
-r, --remove         .lz4 Files mtime before n minutes ago will be removed, default is 1200 (20hour)
-t, --tag            Backup file tag, if not set, target cluster_name or local ip address will be used. Also used as part of DEFAULT filename
-k, --key            Encryption key when --encrypt is specified, default key is ${tag}
-u, --upload         Upload backup files to cloud storage, (need your own implementation)
-e, --encryption     Encrypt with RC4 using OpenSSL, if not key is specified, tag is used as key
-h, --help           Print this message
postgres@pg-meta-1:~$ pg-basebackup
[2025-07-13 06:16:05][INFO] ================================================================
[2025-07-13 06:16:05][INFO] [INIT] pg-basebackup begin, checking parameters
[2025-07-13 06:16:05][DEBUG] [INIT] #====== BINARY
[2025-07-13 06:16:05][DEBUG] [INIT] pg_basebackup     :   /usr/pgsql/bin/pg_basebackup
[2025-07-13 06:16:05][DEBUG] [INIT] openssl           :   /usr/bin/openssl
[2025-07-13 06:16:05][DEBUG] [INIT] #====== PARAMETER
[2025-07-13 06:16:05][DEBUG] [INIT] filename  (-f)    :   backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][DEBUG] [INIT] src       (-s)    :   postgres:///
[2025-07-13 06:16:05][DEBUG] [INIT] dst       (-d)    :   /pg/backup
[2025-07-13 06:16:05][DEBUG] [INIT] tag       (-t)    :   pg-meta
[2025-07-13 06:16:05][DEBUG] [INIT] key       (-k)    :   pg-meta
[2025-07-13 06:16:05][DEBUG] [INIT] encrypt   (-e)    :   false
[2025-07-13 06:16:05][DEBUG] [INIT] upload    (-u)    :   false
[2025-07-13 06:16:05][DEBUG] [INIT] remove    (-r)    :   -mmin +1200
[2025-07-13 06:16:05][INFO] [LOCK] acquire lock @ /tmp/backup.lock
[2025-07-13 06:16:05][INFO] [LOCK] lock acquired success on /tmp/backup.lock, pid=107417
[2025-07-13 06:16:05][INFO] [BKUP] backup begin, from postgres:/// to /pg/backup/backup_pg-meta_20250713.tar.lz4
[2025-07-13 06:16:05][INFO] [BKUP] backup in normal mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete

pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/7000028 on timeline 1
pg_basebackup: write-ahead log end point: 0/7000FD8
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[2025-07-13 06:16:06][INFO] [BKUP] backup complete!
[2025-07-13 06:16:06][INFO] [RMBK] remove local obsolete backup: 1200
[2025-07-13 06:16:06][INFO] [BKUP] find obsolete backups: find /pg/backup/ -maxdepth 1 -type f -mmin +1200 -name 'backup*.lz4'
[2025-07-13 06:16:06][WARN] [BKUP] remove obsolete backups:
[2025-07-13 06:16:06][INFO] [RMBK] remove old backup complete
[2025-07-13 06:16:06][INFO] [LOCK] release lock @ /tmp/backup.lock
[2025-07-13 06:16:06][INFO] [DONE] backup procedure complete!
[2025-07-13 06:16:06][INFO] ================================================================

备份使用 lz4 压缩,您可以使用以下命令解压缩和提取 tarball:

mkdir -p /tmp/data   # 将备份提取到此目录
cat /pg/backup/backup_pg-meta_20250713.tar.lz4 | unlz4 -d -c | tar -xC /tmp/data

逻辑备份

您也可以使用 pg_dump 命令执行逻辑备份。

逻辑备份不能用于 PITR(时间点恢复),但它们对于在不同主版本之间迁移数据或实现灵活的数据导出逻辑很有用。


从备份仓库中恢复

现在假设您有一个现有集群 pg-meta,并且想要分叉它作为 pg-meta2

您需要创建新的 pg-meta2 集群分叉,然后在其上运行 pitr任务,来实现从备份仓库中恢复的效果。

15.5 - 时间点恢复

从备份恢复 PostgreSQL

您可以使用预配置的 pgbackrest 在 Pigsty 中执行时间点恢复(PITR)。

  • 手动方式:使用 pg-pitr 提示脚本进行 PITR,手动操作,更灵活但更复杂。
  • 剧本方式:使用 pgsql-pitr.yml 剧本进行 PITR,自动化,但灵活性较低且更容易出错。

如果您对配置非常熟悉,可以使用全自动剧本, 否则,考虑逐步手动操作


快速开始

如果您想将 pg-meta 集群回滚到之前的时间点,添加 pg_pitr

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { time: '2025-07-13 10:00:00+00' }  # 从最新备份恢复

然后运行 pgsql-pitr.yml 剧本,它将把 pg-meta 集群回滚到指定的时间点。

./pgsql-pitr.yml -l pg-meta

恢复 PITR

恢复的集群上的 archive_mode 将被禁用,以防止不必要的 WAL 写入。 如果恢复的数据库状态正常,您可以启用 archive_mode 并进行全量备份。

postgres @ pg-meta $
psql -c 'ALTER SYSTEM RESET archive_mode; SELECT pg_reload_conf();'
pg-backup full    # 进行新的全量备份

恢复目标

您可以在 pg_pitr 中指定不同类型的恢复目标,但它们是互斥的:

  • time:恢复到哪个时间点?
  • name:恢复到命名的恢复点(由 pg_create_restore_point 创建)
  • xid:恢复到特定的事务 ID(TXID/XID)
  • lsn:恢复到特定的 LSN(日志序列号)点

如果指定了上述任何参数,恢复 type 将相应设置, 否则将设置为 latest(WAL 归档流的末尾)。 特殊的 immediate 类型可用于指示 pgbackrest 通过在第一个一致点停止来最小化恢复时间。

目标类型

pg_pitr: { }  # 恢复到最新状态(wal 归档流结束)
pg_pitr: { time: "2025-07-13 10:00:00+00" }
pg_pitr: { lsn: "0/4001C80" }
pg_pitr: { xid: "250000" }
pg_pitr: { name: "some_restore_point" }
pg_pitr: { type: "immediate" }

按时间

最常用的目标是时间点;您可以指定要恢复到的时间点:

恢复到时间点
./pgsql-pitr.yml -e '{"pg_pitr": { "time": "2025-07-13 10:00:00+00" }}'

时间应该是有效的 PostgreSQL TIMESTAMP,建议使用 YYYY-MM-DD HH:MM:SS+TZ

按名称

您可以使用 pg_create_restore_point 创建命名的恢复点:

SELECT pg_create_restore_point('shit_incoming');

并在 PITR 中使用该命名恢复点:

./pgsql-pitr.yml -e '{"pg_pitr": { "name": "shit_incoming" }}'

按 XID

如果您有一个意外删除某些数据的事务,最好的恢复方法是将数据库恢复到该事务之前的状态。

恢复到事务之前
./pgsql-pitr.yml -e '{"pg_pitr": { "xid": "250000", exclusive: true }}'

您可以从监控仪表板找到确切的事务 ID,或从 CSVLOG 的 TXID 中找到它。

包含 vs 排除

目标参数默认是"包含"的,这意味着恢复将包含目标点。 exclusive 标志将排除那个确切的目标,比如 xid 24999 将是最后一个被重放的事务

这仅适用于 timexidlsn 恢复目标,详情请查看 recovery_target_inclusive

按 LSN

PostgreSQL 使用 LSN(日志序列号)来标识 WAL 记录的位置。 您可以在任何地方找到它,比如 Pigsty 仪表板的 PG LSN 面板。

恢复到 LSN
./pgsql-pitr.yml -e '{"pg_pitr": { "lsn": "0/4001C80", timeline: "1" }}'

要恢复到 WAL 流中的确切点,您还可以指定 timeline 参数(默认为 latest


恢复来源

  • cluster:恢复哪个集群?默认使用当前的 pg_cluster,您可以在同一个 pgbackrest 仓库中使用任何其他集群
  • repo:覆盖备份仓库,使用与 pgbackrest_repo 相同的格式
  • set:默认使用 latest 备份集,但您可以指定特定的 pgbackrest 备份标签

Pigsty 将从 pgbackrest 备份仓库恢复,如果您使用集中式备份仓库(如 MinIO/S3), 您可以指定另一个"stanza"(另一个集群的备份目录)来恢复。

pg-meta2:
  hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { cluster: pg-meta }  # 从 pg-meta 集群备份恢复

上述配置将标记 PITR 过程使用 pg-meta stanza。 您也可以通过 CLI 参数传递 pg_pitr 参数:

使用 pg-meta 备份恢复 pg-meta2
./pgsql-pitr.yml -l pg-meta2 -e '{"pg_pitr": { "cluster": "pg-meta" }}'

从另一个集群进行 pitr 时,您也可以使用这些目标:

./pgsql-pitr.yml -l pg-meta2 -e '{"pg_pitr": { "cluster": "pg-meta", "time": "2025-07-14 08:00:00+00" }}'

分步执行

这种方法是半自动的,您将参与 PITR 过程以做出关键决策。

例如,此配置将把 pg-meta 集群本身恢复到指定的时间点

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { time: '2025-07-13 10:00:00+00' }  # 从最新备份恢复

让我们逐步执行:

./pgsql-pitr.yml -l pg-meta -t down     # 暂停 patroni HA
./pgsql-pitr.yml -l pg-meta -t pitr     # 运行 pitr 过程
./pgsql-pitr.yml -l pg-meta -t up       # 生成 pgbackrest 配置和恢复脚本
# down                 : # 停止 ha 并关闭 patroni 和 postgres
#   - pause            : # 暂停 patroni 自动故障转移
#   - stop             : # 停止 patroni 和 postgres 服务
#     - stop_patroni   : # 停止 patroni 服务
#     - stop_postgres  : # 停止 postgres 服务
# pitr                 : # 执行 PITR 过程
#   - config           : # 生成 pgbackrest 配置和恢复脚本
#   - restore          : # 运行 pgbackrest 恢复命令
#   - recovery         : # 启动 postgres 并完成恢复
#   - verify           : # 验证恢复的集群控制数据
# up:                  : # 启动 postgres / patroni 并恢复 ha
#   - etcd             : # 在启动前清理 etcd 元数据
#   - start            : # 启动 patroni 和 postgres 服务
#     - start_postgres : # 启动 postgres 服务
#     - start_patroni  : # 启动 patroni 服务
#   - resume           : # 恢复 patroni 自动故障转移

PITR 定义

pg_pitr 参数中有更多可用选项,以下是一些可用的参考项:

pg_pitr:                          # 定义 PITR 任务
    cluster: "some_pg_cls_name"   # 源集群名称
    type: latest                  # 恢复目标类型:time、xid、name、lsn、immediate、latest
    time: "2025-01-01 10:00:00+00" # 恢复目标:时间,与 xid、name、lsn 互斥
    name: "some_restore_point"    # 恢复目标:命名恢复点,与 time、xid、lsn 互斥
    xid:  "100000"                # 恢复目标:事务 ID,与 time、name、lsn 互斥
    lsn:  "0/3000000"             # 恢复目标:日志序列号,与 time、name、xid 互斥
    timeline: latest              # 目标时间线,可以是整数,默认为 latest
    exclusive: false              # 排除目标点,默认为 false?
    action: pause                 # 恢复后操作:pause、promote、shutdown
    archive: false                # 保留归档设置?默认为 false
    db_exclude: [ template0, template1 ]
    db_include: []
    link_map:
      pg_wal: '/data/wal'
      pg_xact: '/data/pg_xact'
    process: 4                    # 并行恢复进程
    repo: {}                      # 要恢复的仓库
    data: /pg/data                # 恢复数据的位置
    port: 5432                    # 恢复实例的监听端口

15.6 - 示例

在沙盒环境中根据提示脚本手动执行 PITR

您可以使用 pgsql-pitr 剧本执行 PITR,但在某些情况下,您可能希望手动执行 PITR。 我们将使用带有 MinIO 备份仓库的 4 节点沙盒环境 集群来演示该过程。


初始化沙盒

使用 vagrantterraform 准备 4 节点沙盒环境,然后:

curl https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty/
./configure -c full
./install

现在在管理节点上以管理员用户(或 dbsu)身份操作以继续。

pigsty-sandbox.jpg

检查备份

要检查备份状态,您需要切换到 postgres 用户并使用 pb 命令:

sudo su - postgres    # 切换到 dbsu:postgres 用户
pb info               # 打印 pgbackrest 备份信息

pbpgbackrest 的别名,会自动从 pgbackrest 配置中获取 stanza 名称。

/etc/profile.d/pg-alias.sh
function pb() {
    local stanza=$(grep -o '\[[^][]*]' /etc/pgbackrest/pgbackrest.conf | head -n1 | sed 's/.*\[\([^]]*\)].*/\1/')
    pgbackrest --stanza=$stanza $@
}

您可以看到初始备份信息,这是在以下时间创建的全量备份:

root@pg-meta-1:~# pb info
stanza: pg-meta
    status: ok
    cipher: aes-256-cbc

    db (current)
        wal archive min/max (17): 000000010000000000000001/000000010000000000000007

        full backup: 20250713-022731F
            timestamp start/stop: 2025-07-13 02:27:31+00 / 2025-07-13 02:27:33+00
            wal start/stop: 000000010000000000000004 / 000000010000000000000004
            database size: 44MB, database backup size: 44MB
            repo1: backup size: 8.4MB

备份完成于 2025-07-13 02:27:33+00,这是您可以恢复到的最早时间。 由于 WAL 归档处于活动状态,您可以恢复到备份后直到 WAL 结束(现在)的任何时间点。


生成心跳

您可以生成一些心跳来模拟工作负载。/pg-bin/pg-heartbeat 就是为此目的, 它将每秒向 monitor.heartbeat 表写入一个心跳时间戳。

make rh     # 运行心跳:ssh 10.10.10.10 'sudo -iu postgres /pg/bin/pg-heartbeat'
ssh 10.10.10.10 'sudo -iu postgres /pg/bin/pg-heartbeat'
   cls   |              ts               |    lsn     |  lsn_int  | txid | status  |       now       |  elapse
---------+-------------------------------+------------+-----------+------+---------+-----------------+----------
 pg-meta | 2025-07-13 03:01:20.318234+00 | 0/115BF5C0 | 291239360 | 4812 | leading | 03:01:20.318234 | 00:00:00

您甚至可以为集群添加更多工作负载,让我们使用 pgbench 生成一些随机写入:

make ri     # 初始化 pgbench
make rw     # 运行 pgbench 读写工作负载
pgbench -is10 postgres://dbuser_meta:[email protected]:5433/meta
while true; do pgbench -nv -P1 -c4 --rate=64 -T10 postgres://dbuser_meta:[email protected]:5433/meta; done
while true; do pgbench -nv -P1 -c4 --rate=64 -T10 postgres://dbuser_meta:[email protected]:5433/meta; done
pgbench (17.5 (Homebrew), server 17.4 (Ubuntu 17.4-1.pgdg24.04+2))
progress: 1.0 s, 60.9 tps, lat 7.295 ms stddev 4.219, 0 failed, lag 1.818 ms
progress: 2.0 s, 69.1 tps, lat 6.296 ms stddev 1.983, 0 failed, lag 1.397 ms
...

手动 PITR

现在让我们选择一个恢复的时间点,比如说 2025-07-13 03:03:03+00,这是初始备份(和心跳)之后的时间点。 要执行手动 PITR,请使用 pg-pitr 工具:

$ pg-pitr -t "2025-07-13 03:03:00+00"

它将为您生成执行恢复的说明,通常需要四个步骤:

Perform time PITR on pg-meta
[1. Stop PostgreSQL] ===========================================
   1.1 暂停 Patroni(如果有任何副本)
       $ pg pause <cls>  # 暂停 patroni 自动故障转移
   1.2 关闭 Patroni
       $ pt-stop         # sudo systemctl stop patroni
   1.3 关闭 Postgres
       $ pg-stop         # pg_ctl -D /pg/data stop -m fast

[2. Perform PITR] ===========================================
   2.1 恢复备份
       $ pgbackrest --stanza=pg-meta --type=time --target='2025-07-13 03:03:00+00' restore
   2.2 启动 PG 以重放 WAL
       $ pg-start        # pg_ctl -D /pg/data start
   2.3 验证并提升
     - 如果数据库内容正确,提升它以完成恢复,否则转到 2.1
       $ pg-promote      # pg_ctl -D /pg/data promote

[3. Restore Primary] ===========================================
   3.1 启用归档模式(需要重启)
       $ psql -c 'ALTER SYSTEM SET archive_mode = on;'
   3.1 重启 Postgres 以应用更改
       $ pg-restart      # pg_ctl -D /pg/data restart
   3.3 重启 Patroni
       $ pt-restart      # sudo systemctl restart patroni

[4. Restore Cluster] ===========================================
   4.1 重新初始化所有**副本**(如果有)
       - 4.1.1 选项 1:使用相同的 pgbackrest 命令恢复副本(需要中央备份仓库)
           $ pgbackrest --stanza=pg-meta --type=time --target='2025-07-13 03:03:00+00' restore
       - 4.1.2 选项 2:清除副本数据目录并重启 patroni(可能需要很长时间恢复)
           $ rm -rf /pg/data/*; pt-restart
       - 4.1.3 选项 3:使用 patroni 重新初始化,如果主 lsn < 副本 lsn 可能会失败
           $ pg reinit pg-meta
   4.2 恢复 Patroni
       $ pg resume pg-meta
   4.3 全量备份(可选)
       $ pg-backup full      # 建议在 PITR 后进行新的全量备份

单节点示例

让我们以简单的单节点 pg-meta 集群为例开始,这比较简单。

关闭数据库

pt-stop         # sudo systemctl stop patroni,关闭 patroni(和 postgres)
$ pg_stop        # pg_ctl -D /pg/data stop -m fast,关闭 postgres

pg_ctl: PID file "/pg/data/postmaster.pid" does not exist
Is server running?

$ pg-ps           # 打印与 postgres 相关的进程

 UID         PID   PPID  C STIME TTY      STAT   TIME CMD
postgres  31048      1  0 02:27 ?        Ssl    0:19 /usr/sbin/pgbouncer /etc/pgbouncer/pgbouncer.ini
postgres  32026      1  0 02:28 ?        Ssl    0:03 /usr/bin/pg_exporter --web.listen-address=:9630 --log.level=info
postgres  32252      1  0 02:28 ?        Ssl    0:00 /usr/bin/pg_exporter --web.listen-address=:9631 --log.level=info
postgres  32460      1  0 02:28 ?        Ssl    0:00 /usr/bin/pgbackrest_exporter --log.level=info
postgres  35480  35479  0 03:00 pts/2    S      0:00 -bash
postgres  35510  35480  0 03:01 pts/2    S+     0:00 /bin/bash /pg/bin/pg-heartbeat
postgres  37183  37182  0 03:07 pts/4    S      0:00 -bash
postgres  38627  35510  0 03:14 pts/2    S+     0:00 sleep 1

确保本地 postgres 没有运行,然后执行手册中给出的恢复命令:

恢复备份

pgbackrest --stanza=pg-meta --type=time --target='2025-07-13 03:03:00+00' restore
postgres@pg-meta-1:~$ pgbackrest --stanza=pg-meta --type=time --target='2025-07-13 03:03:00+00' restore
2025-07-13 03:17:07.443 P00   INFO: restore command begin 2.54.2: --archive-mode=off --delta --exec-id=38997-5c07abb3 --log-level-console=info --log-level-file=info --log-path=/pg/log/pgbackrest --pg1-path=/pg/data --process-max=2 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/pgbackrest --repo1-s3-bucket=pgsql --repo1-s3-endpoint=sss.pigsty --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --repo1-s3-uri-style=path --repo1-storage-ca-file=/etc/pki/ca.crt --repo1-storage-port=9000 --repo1-type=s3 --spool-path=/pg/spool --stanza=pg-meta --target="2025-07-13 03:03:00+00" --type=time
2025-07-13 03:17:07.470 P00   INFO: repo1: restore backup set 20250713-022731F, recovery will start at 2025-07-13 02:27:31
2025-07-13 03:17:07.471 P00   INFO: remove invalid files/links/paths from '/pg/data'
2025-07-13 03:17:08.523 P00   INFO: write updated /pg/data/postgresql.auto.conf
2025-07-13 03:17:08.526 P00   INFO: restore global/pg_control (performed last to ensure aborted restores cannot be started)
2025-07-13 03:17:08.527 P00   INFO: restore size = 44MB, file total = 1436
2025-07-13 03:17:08.527 P00   INFO: restore command end: completed successfully (1087ms)

验证数据

我们不希望 patroni HA 在确保数据正确之前接管,所以我们手动启动 postgres:

pg-start
waiting for server to start....2025-07-13 03:19:33.133 UTC [39294] LOG:  redirecting log output to logging collector process
2025-07-13 03:19:33.133 UTC [39294] HINT:  Future log output will appear in directory "/pg/log/postgres".
 done
server started

现在您可以检查数据,看看它是否在您想要的时间点。 您可以通过检查业务表中的一些最新时间戳来验证它,或者在这种情况下,通过心跳表进行检查。

postgres@pg-meta-1:~$ psql -c 'table monitor.heartbeat'
   id    |              ts               |    lsn    | txid
---------+-------------------------------+-----------+------
 pg-meta | 2025-07-13 03:02:59.214104+00 | 302005504 | 4912

时间戳正好在我们指定的时间点之前!(2025-07-13 03:03:00+00)。 如果这不是您想要的时间点,您可以使用不同的时间点重复恢复。 由于恢复是以增量和并行方式执行的,所以很快。 重试直到获得正确的时间点是可以的。

提升为主节点

恢复的 postgres 集群处于 recovery 模式,因此在您将其提升为主节点之前,它将拒绝任何写入操作。 这些恢复参数由 pgBackRest 在配置文件中生成。

/pg/data/postgresql.auto.conf
postgres@pg-meta-1:~$ cat /pg/data/postgresql.auto.conf
# Do not edit this file or use ALTER SYSTEM manually!
# It is managed by Pigsty & Ansible automatically!

# Recovery settings generated by pgBackRest restore on 2025-07-13 03:17:08
archive_mode = 'off'
restore_command = 'pgbackrest --stanza=pg-meta archive-get %f "%p"'
recovery_target_time = '2025-07-13 03:03:00+00'

如果数据正确,您可以将其提升为主节点,将其标记为新的领导者并准备接受写入。

pg-promote
waiting for server to promote.... done
server promoted
psql -c 'SELECT pg_is_in_recovery()'   # 'f' 表示它已提升为主节点
 pg_is_in_recovery
-------------------
 f
(1 row)
新时间线和脑裂

一旦提升,数据库集群将进入新的时间线(主节点纪元)。 如果有任何写入流量,它将被写入新的时间线。

恢复集群

最后,不仅数据需要恢复,集群状态也需要恢复,例如:

  • patroni 接管
  • 归档模式
  • 备份集
  • 副本

Patroni 接管

您的 postgres 直接启动,要恢复 HA 接管;您必须启动 patroni 服务:

pt-start   # sudo systemctl start patroni
pg resume pg-meta      # 恢复 patroni 自动故障转移(如果您之前暂停了它)

归档模式

archive_mode 在恢复期间被 pgbackrest 禁用。 如果您希望新主节点的写入被归档到备份仓库中,您还需要启用 archive_mode 配置。

psql -c 'show archive_mode'

 archive_mode
--------------
 off
psql -c 'ALTER SYSTEM RESET archive_mode;'
psql -c 'SELECT pg_reload_conf();'
psql -c 'show archive_mode'
# 您也可以直接编辑 postgresql.auto.conf 并使用 pg_ctl 重新加载
sed -i '/archive_mode/d' /pg/data/postgresql.auto.conf
pg_ctl -D /pg/data reload

备份集

在 PITR 后进行新的全量备份通常是一个好主意,但这是可选的。

副本

如果您的 postgres 集群有副本,您需要在每个副本上也执行 PITR。 或者,简单的方法是清除副本数据目录并重启 patroni,这将从主节点重新初始化副本。 我们将在下一个多节点集群示例中介绍这种情况。

16 - 内核

您可以在 Pigsty 中使用特殊风味的 PostgreSQL 内核分支替代原生内核。

Pigsty 支持各种 PostgreSQL 内核和兼容分支, 使您能够模拟不同的数据库系统,同时利用 PostgreSQL 的生态系统。 每个内核都能提供独特的功能和兼容性层。

数据库内核

PostgreSQL

带有 437 个扩展插件的原生 PostgreSQL 内核

Citus

PG 原生分布式扩展

Babelfish

SQL Server 线缆协议兼容

IvorySQL

Oracle 语法和 PL/SQL 兼容

OpenHalo

MySQL 线缆协议兼容

Percona

透明加密内核

OrioleDB

OLTP 优化的云原生存储引擎

PolarDB PG

类 Aurora RAC 风味的信创内核

Supabase

后端即服务,自托管 Firebase

FerretDB

MongoDB 线缆协议兼容的内核


选择合适的内核

内核 关键特性 描述
PostgreSQL 原始版本 原版 PostgreSQL 配备 437 扩展
Citus 水平扩展 通过原生扩展实现分布式 PostgreSQL
WiltonDB SQL Server 迁移 SQL Server 线协议兼容
IvorySQL Oracle 迁移 Oracle 语法和 PL/SQL 兼容
OpenHalo MySQL 迁移 MySQL 线协议兼容
Percona 透明数据加密 带有 pg_tde 的 Percona 发行版
FerretDB MongoDB 迁移 MongoDB 线协议兼容
OrioleDB OLTP 优化 Zheap,无膨胀,S3 存储
PolarDB Aurora 风格 RAC RAC,中国国产合规
Supabase 后端即服务 基于 PostgreSQL 的 BaaS,Firebase 替代方案
Cloudberry MPP 数厂与数据分析 大规模并行处理数据仓库(等待2.0GA)

Citus(分布式)

Citus 原生分布式

Citus 将 PostgreSQL 转换为分布式数据库系统,实现跨多个节点的水平扩展。使用 Pigsty 部署原生 HA Citus 集群以获得更好的吞吐量和性能。

关键特性

  • 分布式表:自动将表分片到工作节点
  • 分布式查询:在整个集群中执行查询
  • 高可用性:内置复制和故障转移功能
  • 实时分析:处理事务和分析工作负载
  • Postgres 兼容性:保持完整的 PostgreSQL 功能兼容性

用例

  • 需要水平扩展的多租户 SaaS 应用程序
  • 大型数据集的实时分析
  • 高吞吐量 OLTP 工作负载
  • 需要扩展超出单节点限制的应用程序
说明

需要规划:正确的分片键选择对于最佳性能和避免跨分片查询至关重要。

Babelfish(MSSQL)

Babelfish SQL Server 线缆协议兼容

使用 WiltonDB 和 Babelfish 创建 SQL Server 兼容的 PostgreSQL 集群,提供与 Microsoft SQL Server 的线协议级别兼容性。

关键特性

  • T-SQL 支持:原生执行 T-SQL 查询
  • 线协议兼容性:使用 SQL Server 驱动程序和工具连接
  • 存储过程:支持 T-SQL 存储过程和函数
  • 数据类型:与 SQL Server 数据类型和行为兼容
  • 迁移工具:简化从 SQL Server 环境的迁移

用例

  • 将传统 SQL Server 应用程序迁移到 PostgreSQL
  • 需要 SQL Server 兼容性的多数据库环境
  • 在保持应用程序兼容性的同时降低成本
  • 从 SQL Server 到开源替代方案的云迁移
说明

迁移路径:非常适合希望降低许可成本同时保持现有 SQL Server 应用程序兼容性的组织。


IvorySQL(Oracle)

Babelfish Oracle Grammar Compatible

使用 IvorySQL 内核运行 Oracle 兼容的 PostgreSQL 集群,由瀚高开源,提供 Oracle 语法和功能兼容性。

关键特性

  • PL/SQL 支持:以最少的修改执行 PL/SQL 代码
  • Oracle 语法:支持 Oracle 特定的 SQL 语法和函数
  • 包支持:Oracle 风格的包和过程定义
  • 数据类型:Oracle 兼容的数据类型和行为

用例

  • Oracle 数据库迁移项目
  • 寻求 Oracle 功能兼容性的组织
  • 在保持 Oracle 功能的同时进行成本优化
  • 需要 Oracle 兼容性的开发环境
说明

企业焦点:对于在 Oracle 上有重大投资并寻求迁移路径的企业特别有价值。


OpenHalo(MySQL)

OpenHalo MySQL Wire-Compatible

OpenHalo 内核提供 MySQL 兼容的 PostgreSQL 功能,可使用标准 MySQL 客户端和协议访问。

关键特性

  • MySQL 协议:与 MySQL 协议的线级别兼容性
  • 客户端兼容性:使用现有的 MySQL 驱动程序和工具
  • SQL 方言:支持 MySQL 特定的 SQL 语法
  • 迁移支持:简化从 MySQL 环境的迁移
  • 生态系统集成:在保持 MySQL 兼容性的同时利用 PostgreSQL 的高级功能

用例

  • MySQL 应用程序迁移到 PostgreSQL
  • 需要 MySQL 兼容性的多数据库环境
  • 在保持 MySQL 接口的同时利用 PostgreSQL 功能
  • 从 MySQL 到 PostgreSQL 的渐进式迁移策略
说明

早期阶段:目前处于实验阶段 - 在生产使用前请彻底评估。


OrioleDB(OLTP)

OrioleDB OLTP Optimized Cloud Native

为 OLTP 工作负载优化的 PostgreSQL 存储引擎,消除事务 ID 回绕问题和表膨胀,同时支持云存储。

与 PostgreSQL 17 兼容,在所有支持的平台上可用。

关键特性

  • 无 XID 回绕:消除事务 ID 回绕维护
  • 无表膨胀:高级存储管理防止表膨胀
  • 云存储:对 S3 兼容对象存储的原生支持
  • OLTP 优化:专为事务工作负载设计
  • 改进性能:更好的空间利用率和查询性能

用例

  • 高频事务应用程序
  • 需要对象存储的云原生部署
  • 受 PostgreSQL 维护开销影响的应用程序
  • 需要无需清理周期的一致性能的系统
说明

早期阶段:目前处于 Beta 阶段 - 在生产使用前请彻底评估。


PolarDB PG(RAC)

PolarDB Aurora Flavor RAC

用 PolarDB PG 替换原版 PostgreSQL,这是一个开源的类 Aurora 解决方案,类似于具有共享存储架构的 Oracle RAC。

关键特性

  • 共享存储:多个计算节点共享同一存储层
  • 读取扩展:无需存储复制即可添加读副本
  • 快速恢复:通过共享存储架构快速恢复
  • 成本效率:通过共享降低存储成本
  • 高可用性:内置故障转移和灾难恢复

用例

  • 需要极端读取可扩展性的应用程序
  • 需要高可用性的成本敏感部署
  • 具有共享存储基础设施的云环境
  • 具有可变读写模式的工作负载
说明

云架构:专为具有分离计算和存储的云环境设计。


Supabase(Firebase)

Supabase Backend as a Service

使用现有托管的 HA PostgreSQL 集群自托管 Supabase,使用 docker-compose 启动无状态组件以获得完整的 Firebase 替代方案。

关键特性

  • 实时 API:自动生成的 REST 和 GraphQL API
  • 实时订阅:基于 WebSocket 的实时数据同步
  • 身份验证:内置用户身份验证和授权
  • 存储:具有 CDN 功能的文件存储
  • 边缘函数:用于自定义逻辑的无服务器函数

用例

  • 使用后端即服务进行快速应用程序开发
  • AI / Agent / SaaS 应用快速原型设计
  • 需要即时数据同步的实时应用程序
  • 需要身份验证和存储的移动和 Web 应用程序
说明

全栈:提供以 PostgreSQL 为基础的完整后端解决方案。


Greenplum(MPP)

Cloudberry MPP Data Warehouse

使用 Pigsty 部署和监控 Greenplum/YMatrix MPP 集群,用于大规模分析处理和数据仓库。

关键特性

  • 大规模并行处理:在多个节点间分布查询
  • 列式存储:为分析工作负载优化的存储
  • 高级分析:内置机器学习和统计函数
  • PB 级扩展:通过线性可扩展性处理大规模数据集
  • 标准 SQL:与 PostgreSQL 兼容的完整 SQL 合规性

用例

  • 数据仓库和商业智能
  • 大规模分析和报告
  • 大数据集上的机器学习
  • 企业数据平台的 ETL 处理
说明

企业分析:专为需要大规模并行处理能力的企业级分析工作负载而设计。

16.1 - PostgreSQL

带有 437 扩展的原版 PostgreSQL 内核

PostgreSQL 是世界上最先进和最受欢迎的开源数据库。

Pigsty 支持 PostgreSQL 13 ~ 18,并提供 437 个 PG 扩展。


快速开始

使用 pgsql 配置模板 安装 Pigsty。

./configure -c pgsql     # 使用 postgres 内核
./install.yml            # 使用 pigsty 设置一切

大多数配置模板默认使用 PostgreSQL 内核,例如:

  • meta : 默认,带有核心扩展(vector、postgis、timescale)的 postgres
  • rich : 安装了所有扩展的 postgres
  • slim : 仅 postgres,无监控基础设施
  • full : 用于 HA 演示的 4 节点沙盒
  • pgsql : 最小的 postgres 内核配置示例

配置

原版 PostgreSQL 内核不需要特殊调整:

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
      - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
    pg_databases:
      - { name: meta, baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ vector ]}
    pg_hba_rules:
      - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # 每天凌晨 1 点进行全量备份
    pg_packages: [ pgsql-main, pgsql-common ]   # pg 内核和通用工具
    #pg_extensions: [ pg18-time ,pg18-gis ,pg18-rag ,pg18-fts ,pg18-olap ,pg18-feat ,pg18-lang ,pg18-type ,pg18-util ,pg18-func ,pg18-admin ,pg18-stat ,pg18-sec ,pg18-fdw ,pg18-sim ,pg18-etl]

版本选择

要使用不同的 PostgreSQL 主版本,您可以使用 -v 参数进行配置:

./configure -c pgsql            # 默认就是 postgresql 18,无需显式指定
./configure -c pgsql -v 17      # 使用 postgresql 17
./configure -c pgsql -v 16      # 使用 postgresql 16
./configure -c pgsql -v 15      # 使用 postgresql 15
./configure -c pgsql -v 14      # 使用 postgresql 14
./configure -c pgsql -v 13      # 使用 postgresql 13

如果 PostgreSQL 集群已经安装,您需要在安装新版本之前卸载它:

./pgsql-rm.yml # -l pg-meta

扩展生态

Pigsty 为 PostgreSQL 提供了丰富的扩展生态,包括:

  • 时序类:timescaledb, pg_cron, periods
  • 地理类:postgis, h3, pgrouting
  • 向量类:pgvector, pgml, vchord
  • 搜索类:pg_trgm, zhparser, pgroonga
  • 分析类:citus, pg_duckdb, pg_analytics
  • 特性类:age, pg_graphql, rum
  • 语言类:plpython3u, pljava, plv8
  • 类型类:hstore, ltree, citext
  • 工具类:http, pg_net, pgjwt
  • 函数类:pgcrypto, uuid-ossp, pg_uuidv7
  • 管理类:pg_repack, pgagent, pg_squeeze
  • 统计类:pg_stat_statements, pg_qualstats, auto_explain
  • 安全类:pgaudit, pgcrypto, pgsodium
  • 外部类:postgres_fdw, mysql_fdw, oracle_fdw
  • 兼容类:orafce, babelfishpg_tds
  • 数据类:pglogical, wal2json, decoderbufs

详情请参考 扩展目录

16.2 - Citus

PostgreSQL 分片的原生分布式扩展

Citus 是一个 PostgreSQL 扩展,它将 PostgreSQL 转换为分布式数据库,能够跨多个节点水平扩展以处理大量数据和查询。

自 Patroni v3.0 以来,已原生支持 Citus 高可用性,简化了 Citus 集群的设置。Pigsty 也为此提供原生支持。

Pigsty v3.7.0 的 Citus 模板固定使用 PostgreSQL 17;该版本没有 PostgreSQL 18 的 Citus 软件包。


Citus 集群

Pigsty 原生支持 Citus。参考 conf/citus.yml

此示例使用四节点沙盒,包含一个名为 pg-citus 的 Citus 集群,由一个双节点协调器集群 pg-citus0 和两个工作节点集群 pg-citus1pg-citus2 组成。

pg-citus:
  hosts:
    10.10.10.10: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.2/24 ,pg_seq: 1, pg_role: primary }
    10.10.10.11: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.2/24 ,pg_seq: 2, pg_role: replica }
    10.10.10.12: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.3/24 ,pg_seq: 1, pg_role: primary }
    10.10.10.13: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.4/24 ,pg_seq: 1, pg_role: primary }
  vars:
    pg_mode: citus                            # pgsql 集群模式:citus
    pg_version: 17                            # v3.7.0 没有 PG18 的 Citus 软件包
    pg_shard: pg-citus                        # Citus 分片名称:pg-citus
    pg_primary_db: citus                      # Citus 使用的主数据库
    pg_vip_enabled: true                      # 为 Citus 集群启用 VIP
    pg_vip_interface: eth1                    # 所有成员的 VIP 接口
    pg_dbsu_password: DBUser.Postgres         # Citus 集群的所有 DBSU 密码
    pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ]  # 安装这些扩展
    pg_libs: 'citus, pg_cron, pg_stat_statements' # Citus 将由 Patroni 自动添加
    pg_users: [{ name: dbuser_citus ,password: DBUser.Citus ,pgbouncer: true ,roles: [ dbrole_admin ]    }]
    pg_databases: [{ name: citus ,owner: dbuser_citus ,extensions: [ citus, vector, topn, pg_cron, hll ] }]
    pg_parameters:
      cron.database_name: citus
      citus.node_conninfo: 'sslmode=require sslrootcert=/pg/cert/ca.crt sslmode=verify-full'
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32  ,auth: ssl   ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra         ,auth: ssl   ,title: 'all user ssl access from intranet'  }

与标准 PostgreSQL 集群相比,Citus 集群配置有一些特定要求。首先,确保 Citus 扩展被下载、安装、加载和启用。这涉及以下四个参数:

  • repo_packages:必须包含 citus 扩展,或者您需要使用带有 Citus 扩展的 PostgreSQL 离线包。
  • pg_extensions:必须包含 citus 扩展,意味着您需要在每个节点上安装 citus 扩展。
  • pg_libs:必须包含 citus 扩展,且必须在列表中排第一,但现在 Patroni 会自动处理。
  • pg_databases:定义安装了 citus 扩展的主数据库。

另外,确保 Citus 集群的配置正确:

  • pg_mode:必须设置为 citus 以告知 Patroni 使用 Citus 模式。
  • pg_primary_db:指定主数据库名称,该数据库必须安装 citus 扩展(此处命名为 citus)。
  • pg_shard:指定统一名称作为所有水平分片 PG 集群的前缀(例如,pg-citus)。
  • pg_group:指定分片编号,协调器集群从零开始,工作节点集群递增。
  • pg_cluster:必须匹配 [pg_shard] 和 [pg_group] 的组合。
  • pg_dbsu_password:设置非空明文密码以确保 Citus 正常运行。
  • pg_parameters:建议设置 citus.node_conninfo 参数,强制 SSL 访问并要求节点间客户端证书验证。

配置完成后,使用 pgsql.yml 部署 Citus 集群,就像常规 PostgreSQL 集群一样。


管理 Citus 集群

定义 Citus 集群后,使用相同的剧本 pgsql.yml 部署 Citus 集群:

./pgsql.yml -l pg-citus    # 部署 Citus 集群 pg-citus

任何 DBSU 用户(postgres)都可以使用 patronictl(别名:pg)列出 Citus 集群的状态:

$ pg list
+ Citus cluster: pg-citus ----------+---------+-----------+----+-----------+--------------------+
| Group | Member      | Host        | Role    | State     | TL | Lag in MB | Tags               |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
|     0 | pg-citus0-1 | 10.10.10.10 | Leader  | running   |  1 |           | clonefrom: true    |
|       |             |             |         |           |    |           | conf: tiny.yml     |
|       |             |             |         |           |    |           | spec: 20C.40G.125G |
|       |             |             |         |           |    |           | version: '17'      |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
|     1 | pg-citus1-1 | 10.10.10.11 | Leader  | running   |  1 |           | clonefrom: true    |
|       |             |             |         |           |    |           | conf: tiny.yml     |
|       |             |             |         |           |    |           | spec: 10C.20G.125G |
|       |             |             |         |           |    |           | version: '17'      |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
|     2 | pg-citus2-1 | 10.10.10.12 | Leader  | running   |  1 |           | clonefrom: true    |
|       |             |             |         |           |    |           | conf: tiny.yml     |
|       |             |             |         |           |    |           | spec: 10C.20G.125G |
|       |             |             |         |           |    |           | version: '17'      |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
|     2 | pg-citus2-2 | 10.10.10.13 | Replica | streaming |  1 |         0 | clonefrom: true    |
|       |             |             |         |           |    |           | conf: tiny.yml     |
|       |             |             |         |           |    |           | spec: 10C.20G.125G |
|       |             |             |         |           |    |           | version: '17'      |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+

每个水平分片集群都可以作为单独的 PGSQL 集群处理,使用 pgpatronictl)命令管理。注意使用 pg 管理 Citus 集群时,必须使用 --group 参数指定集群分片编号:

pg list pg-citus --group 0   # 使用 --group 0 指定分片编号

Citus 有一个名为 pg_dist_node 的系统表来记录节点信息,Patroni 会自动维护。

PGURL=postgres://postgres:[email protected]/citus

psql $PGURL -c 'SELECT * FROM pg_dist_node;'       # 查看节点信息

另外,您可以查看用户认证信息(仅限超级用户):

$ psql $PGURL -c 'SELECT * FROM pg_dist_authinfo;'   # 查看节点认证信息(仅超级用户)

然后您可以使用常规业务用户(例如,具有 DDL 权限的 dbuser_citus)访问 Citus 集群:

psql postgres://dbuser_citus:[email protected]/citus -c 'SELECT * FROM pg_dist_node;'

使用 Citus 集群

使用 Citus 集群时,我们强烈建议阅读 Citus 官方文档 了解其架构和核心概念。

关键是理解 Citus 中五种类型的表、它们的特征和用例:

  • 分布式表
  • 引用表
  • 本地表
  • 本地管理表
  • 模式表

在协调器节点上,您可以创建分布式表和引用表,并从任何数据节点查询它们。自版本 11.2 以来,任何 Citus 数据库节点都可以充当协调器。

我们可以使用 pgbench 创建一些表,将主表(pgbench_accounts)分布到各个节点,并将其他较小的表用作引用表:

PGURL=postgres://dbuser_citus:[email protected]/citus
pgbench -i $PGURL

psql $PGURL <<-EOF
SELECT create_distributed_table('pgbench_accounts', 'aid'); SELECT truncate_local_data_after_distributing_table('public.pgbench_accounts');
SELECT create_reference_table('pgbench_branches')         ; SELECT truncate_local_data_after_distributing_table('public.pgbench_branches');
SELECT create_reference_table('pgbench_history')          ; SELECT truncate_local_data_after_distributing_table('public.pgbench_history');
SELECT create_reference_table('pgbench_tellers')          ; SELECT truncate_local_data_after_distributing_table('public.pgbench_tellers');
EOF

运行读写基准测试:

pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:[email protected]/citus      # 直连协调器 5432 端口
pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:[email protected]:6432/citus # 通过连接池,减少客户端连接数压力,可以有效提高整体吞吐。
pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:[email protected]/citus      # 任意 primary 节点都可以作为 coordinator
pgbench --select-only -nv -P1 -c10 -T500 postgres://dbuser_citus:[email protected]/citus # 可以发起只读查询

生产部署

生产环境的 Citus 部署通常需要为协调器和每个工作节点集群提供物理复制。

例如,在 simu.yml 中有一个 10 节点集群:

pg-citus: # citus 组
  hosts:
    10.10.10.50: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.51: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.52: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.53: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.54: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.55: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.56: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.57: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 1, pg_role: replica }
    10.10.10.58: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 0, pg_role: primary }
    10.10.10.59: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 1, pg_role: replica }
  vars:
    pg_mode: citus                            # pgsql 集群模式:citus
    pg_version: 17                            # v3.7.0 没有 PG18 的 Citus 软件包
    pg_shard: pg-citus                        # citus 分片名称:pg-citus
    pg_primary_db: citus                      # citus 使用的主数据库
    pg_vip_enabled: true                      # 为 citus 集群启用 vip
    pg_vip_interface: eth1                    # 所有成员的 vip 接口
    pg_dbsu_password: DBUser.Postgres         # 为 citus 启用 dbsu 密码访问
    pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ]  # 安装这些扩展
    pg_libs: 'citus, pg_cron, pg_stat_statements' # citus 将由 patroni 自动添加
    pg_users: [{ name: dbuser_citus ,password: DBUser.Citus ,pgbouncer: true ,roles: [ dbrole_admin ]    }]
    pg_databases: [{ name: citus ,owner: dbuser_citus ,extensions: [ citus, vector, topn, pg_cron, hll ] }]
    pg_parameters:
      cron.database_name: citus
      citus.node_conninfo: 'sslrootcert=/pg/cert/ca.crt sslmode=verify-full'
    pg_hba_rules:
      - { user: 'all' ,db: all  ,addr: 127.0.0.1/32  ,auth: ssl   ,title: 'all user ssl access from localhost' }
      - { user: 'all' ,db: all  ,addr: intra         ,auth: ssl   ,title: 'all user ssl access from intranet'  }

我们将在后续教程中涵盖一系列高级主题:

  • 读写分离
  • 故障转移处理
  • 一致性备份和恢复
  • 高级监控和故障排除
  • 连接池

16.3 - Babelfish

PostgreSQL 上的 MS SQL Server 线协议兼容性

Pigsty 允许用户使用 Babelfish 和 WiltonDB 创建与 Microsoft SQL Server 兼容的 PostgreSQL 集群!

  • Babelfish:由 AWS 开源的 MSSQL(Microsoft SQL Server)兼容性扩展
  • WiltonDB:专注于集成 Babelfish 的 PostgreSQL 内核发行版

Babelfish 是一个 PostgreSQL 扩展,但它运行在经过轻微修改的 PostgreSQL 内核分支上,WiltonDB 在 EL/Ubuntu 系统上提供编译后的内核二进制文件和扩展二进制包。

Pigsty 可以用 WiltonDB 替换原生 PostgreSQL 内核,提供开箱即用的 MSSQL 兼容集群,以及常见 PostgreSQL 集群支持的所有功能,如 HA、PITR、IaC、监控等。

WiltonDB 与 PostgreSQL 15 非常相似,但不能直接使用原版 PostgreSQL 扩展。WiltonDB 有几个重新编译的扩展,如 system_statspg_hint_plantds_fdw

集群将监听默认的 PostgreSQL 端口和默认的 MSSQL 1433 端口,通过 TDS WireProtocol 在此端口上提供 MSSQL 服务。您可以使用任何 MSSQL 客户端连接到 Pigsty 提供的 MSSQL 服务,例如 SQL Server Management Studio,或使用 sqlcmd 命令行工具。


快速开始

使用 mssql 配置模板 安装 Pigsty。

curl -fsSL https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty;
./configure -c mssql     # 使用 mssql (babelfish) 模板
./install.yml            # 使用 pigsty 安装一切

对于生产部署,请确保在运行 install 剧本之前修改 pigsty.yml 配置中的密码参数。


注意事项

在安装和部署 MSSQL 模块时,请特别注意以下几点:

  • WiltonDB 在 EL(7/8/9)和 Ubuntu(20.04/22.04)上可用,但在 Debian 系统上不可用
  • WiltonDB 目前基于 PostgreSQL 15 编译,因此您需要指定 pg_version: 15
  • 在 EL 系统上,wiltondb 二进制文件默认安装在 /usr/bin/ 目录中,而在 Ubuntu 系统上,它安装在 /usr/lib/postgresql/15/bin/ 目录中,这与官方 PostgreSQL 二进制文件位置不同。
  • 在 WiltonDB 兼容模式下,HBA 密码认证规则需要使用 md5 而不是 scram-sha-256。因此,您需要覆盖 Pigsty 的默认 HBA 规则集,并在 dbrole_readonly 通配符认证规则之前插入 SQL Server 所需的 md5 认证规则。
  • WiltonDB 只能为主数据库启用,您应该指定一个用户作为 Babelfish 超级用户,允许 Babelfish 创建数据库和用户。默认是 mssqldbuser_myssql。如果您更改了这个,您还应该修改 files/mssql.sql 中的用户。
  • WiltonDB TDS 线协议兼容性插件 babelfishpg_tds 需要在 shared_preload_libraries 中启用。
  • 启用 WiltonDB 扩展后,它监听默认的 MSSQL 端口 1433。您可以覆盖 Pigsty 的默认服务定义,将 primaryreplica 服务重定向到端口 1433 而不是 5432 / 6432 端口。

需要为 MSSQL 数据库集群配置以下参数:

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - {name: dbuser_mssql ,password: DBUser.MSSQL ,superuser: true, pgbouncer: true ,roles: [dbrole_admin], comment: superuser & owner for babelfish  }
    pg_databases:
      - name: mssql
        baseline: mssql.sql
        extensions: [uuid-ossp, babelfishpg_common, babelfishpg_tsql, babelfishpg_tds, babelfishpg_money, pg_hint_plan, system_stats, tds_fdw]
        owner: dbuser_mssql
        parameters: { 'babelfishpg_tsql.migration_mode' : 'multi-db' }
        comment: babelfish cluster, a MSSQL compatible pg cluster
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # 每天凌晨 1 点进行全量备份

    # Babelfish / WiltonDB 临时设置
    pg_mode: mssql                     # Microsoft SQL Server 兼容模式
    pg_version: 15
    pg_packages: [ wiltondb, pgsql-common, sqlcmd ]
    pg_libs: 'babelfishpg_tds, pg_stat_statements, auto_explain' # 将 timescaledb 添加到 shared_preload_libraries
    pg_default_hba_rules: # 覆盖 babelfish 集群的默认 HBA 规则
      - { user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident' }
      - { user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
      - { user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost' }
      - { user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' }
      - { user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' }
      - { user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
      - { user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password' }
      - { user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl' }
      - { user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd' }
      - { user: dbuser_mssql ,db: mssql       ,addr: intra     ,auth: md5   ,title: 'allow mssql dbsu intranet access' } # <--- 为 mssql 用户使用 md5 认证方法
      - { user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket' }
      - { user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password' }
      - { user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet' }
    pg_default_services: # 将 primary 和 replica 服务路由到 mssql 端口 1433
      - { name: primary ,port: 5433 ,dest: 1433  ,check: /primary   ,selector: "[]" }
      - { name: replica ,port: 5434 ,dest: 1433  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
      - { name: default ,port: 5436 ,dest: postgres ,check: /primary   ,selector: "[]" }
      - { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]" }

您可以在 pg_databasespg_users 部分定义业务数据库和用户:

#----------------------------------#
# pgsql (singleton on current node)
#----------------------------------#
# 这是一个在当前节点上安装了 postgis 和 timescaledb 的单节点 postgres 集群示例,包含一个业务数据库和两个业务用户
pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary } # <---- 具有读写能力的主实例
  vars:
    pg_cluster: pg-test
    pg_users:                           # 创建 MSSQL 超级用户
      - {name: dbuser_mssql ,password: DBUser.MSSQL ,superuser: true, pgbouncer: true ,roles: [dbrole_admin], comment: superuser & owner for babelfish  }
    pg_primary_db: mssql                # 使用 `mssql` 作为主 sql server 数据库
    pg_databases:
      - name: mssql
        baseline: mssql.sql             # 初始化 babelfish 数据库和用户
        extensions:
          - { name: uuid-ossp          }
          - { name: babelfishpg_common }
          - { name: babelfishpg_tsql   }
          - { name: babelfishpg_tds    }
          - { name: babelfishpg_money  }
          - { name: pg_hint_plan       }
          - { name: system_stats       }
          - { name: tds_fdw            }
        owner: dbuser_mssql
        parameters: { 'babelfishpg_tsql.migration_mode' : 'multi-db' }
        comment: babelfish cluster, a MSSQL compatible pg cluster

客户端访问

您可以使用任何兼容 SQL Server 的客户端工具来访问此数据库集群。

Microsoft 提供 sqlcmd 作为官方命令行工具。

此外,他们还有一个 go 版本的 cli 工具:go-sqlcmd

安装 go-sqlcmd

curl -LO https://github.com/microsoft/go-sqlcmd/releases/download/v1.4.0/sqlcmd-v1.4.0-linux-amd64.tar.bz2
tar xjvf sqlcmd-v1.4.0-linux-amd64.tar.bz2
sudo mv sqlcmd* /usr/bin/

开始使用 go-sqlcmd

$ sqlcmd -S 10.10.10.10,1433 -U dbuser_mssql -P DBUser.MSSQL
1> select @@version
2> go
version
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Babelfish for PostgreSQL with SQL Server Compatibility - 12.0.2000.8
Oct 22 2023 17:48:32
Copyright (c) Amazon Web Services
PostgreSQL 15.4 (EL 1:15.4.wiltondb3.3_2-2.el8) on x86_64-redhat-linux-gnu (Babelfish 3.3.0)

(1 row affected)

您可以将服务流量路由到 MSSQL 1433 端口而不是 5433/5434:

# 将所有成员上的 5433 路由到主节点上的 1433
sqlcmd -S 10.10.10.11,5433 -U dbuser_mssql -P DBUser.MSSQL

# 将所有成员上的 5434 路由到副本上的 1433
sqlcmd -S 10.10.10.11,5434 -U dbuser_mssql -P DBUser.MSSQL

安装

如果您有互联网访问权限,可以将 WiltonDB 仓库添加到节点并直接作为节点包安装:

node_repo_modules: local,node,pgsql,mssql
node_packages: [ wiltondb ]

使用以下命令安装 wiltondb:

./node.yml -t node_repo,node_pkg

在同一个节点上安装原版 PostgreSQL 和 WiltonDB 是可以的,但一次只能运行其中一个,不建议在生产环境中这样做。


扩展

PGSQL 模块的大多数扩展(非 SQL 类)不能直接在 MSSQL 模块的 WiltonDB 内核上使用,需要重新编译。

WiltonDB 目前附带以下扩展插件:

名称 版本 注释
dblink 1.2 从数据库内连接到其他 PostgreSQL 数据库
adminpack 2.1 PostgreSQL 的管理功能
dict_int 1.0 整数的文本搜索字典模板
intagg 1.1 整数聚合器和枚举器(已过时)
dict_xsyn 1.0 扩展同义词处理的文本搜索字典模板
amcheck 1.3 验证关系完整性的函数
autoinc 1.0 自动递增字段的函数
bloom 1.0 bloom 访问方法 - 基于签名文件的索引
fuzzystrmatch 1.1 确定字符串之间的相似性和距离
intarray 1.5 1-D 整数数组的函数、操作符和索引支持
btree_gin 1.3 在 GIN 中索引常见数据类型的支持
btree_gist 1.7 在 GiST 中索引常见数据类型的支持
hstore 1.8 存储(键,值)对集合的数据类型
hstore_plperl 1.0 hstore 和 plperl 之间的转换
isn 1.2 国际产品编号标准的数据类型
hstore_plperlu 1.0 hstore 和 plperlu 之间的转换
jsonb_plperl 1.0 jsonb 和 plperl 之间的转换
citext 1.6 不区分大小写字符串的数据类型
jsonb_plperlu 1.0 jsonb 和 plperlu 之间的转换
jsonb_plpython3u 1.0 jsonb 和 plpython3u 之间的转换
cube 1.5 多维立方体的数据类型
hstore_plpython3u 1.0 hstore 和 plpython3u 之间的转换
earthdistance 1.1 计算地球表面的大圆距离
lo 1.1 大对象维护
file_fdw 1.0 平面文件访问的外部数据包装器
insert_username 1.0 跟踪谁更改了表的函数
ltree 1.2 分层树状结构的数据类型
ltree_plpython3u 1.0 ltree 和 plpython3u 之间的转换
pg_walinspect 1.0 检查 PostgreSQL 写前日志内容的函数
moddatetime 1.0 跟踪最后修改时间的函数
old_snapshot 1.0 支持 old_snapshot_threshold 的实用程序
pgcrypto 1.3 加密函数
pgrowlocks 1.2 显示行级锁定信息
pageinspect 1.11 在低级别检查数据库页面的内容
pg_surgery 1.0 对损坏关系进行手术的扩展
seg 1.4 表示线段或浮点区间的数据类型
pgstattuple 1.5 显示元组级统计信息
pg_buffercache 1.3 检查共享缓冲区缓存
pg_freespacemap 1.2 检查空闲空间映射(FSM)
postgres_fdw 1.1 远程 PostgreSQL 服务器的外部数据包装器
pg_prewarm 1.2 预热关系数据
tcn 1.0 触发的更改通知
pg_trgm 1.6 基于三元组的文本相似度测量和索引搜索
xml2 1.1 XPath 查询和 XSLT
refint 1.0 实现引用完整性的函数(已过时)
pg_visibility 1.2 检查可见性映射(VM)和页面级可见性信息
pg_stat_statements 1.10 跟踪所有已执行 SQL 语句的规划和执行统计信息
sslinfo 1.2 SSL 证书信息
tablefunc 1.0 操作整个表的函数,包括交叉表
tsm_system_rows 1.0 接受行数作为限制的 TABLESAMPLE 方法
tsm_system_time 1.0 接受毫秒时间作为限制的 TABLESAMPLE 方法
unaccent 1.1 去除重音符号的文本搜索字典
uuid-ossp 1.1 生成通用唯一标识符(UUID)
plpgsql 1.0 PL/pgSQL 过程语言
babelfishpg_money 1.1.0 babelfishpg_money
system_stats 2.0 PostgreSQL 的 EnterpriseDB 系统统计信息
tds_fdw 2.0.3 查询 TDS 数据库(Sybase 或 Microsoft SQL Server)的外部数据包装器
babelfishpg_common 3.3.3 Transact SQL 数据类型支持
babelfishpg_tds 1.0.0 TDS 协议扩展
pg_hint_plan 1.5.1
babelfishpg_tsql 3.3.1 Transact SQL 兼容性

16.4 - IvorySQL

具有 Oracle(语法)兼容性的 PostgreSQL 分支

IvorySQL 是一个开源的"Oracle 兼容"PostgreSQL 内核,由 HighGo 开发,采用 Apache 2.0 许可证。

这里的 Oracle 兼容性是指在 PL/SQL、语法、内置函数、数据类型、系统视图、MERGE 和 GUC 参数级别的兼容性。它不是像 BabelfishopenHaloFerretDB 那样的线协议兼容性, 不能使用原始客户端驱动程序。用户仍需要使用 PostgreSQL 客户端工具访问 IvorySQL,但可以使用 Oracle 兼容的语法。

目前,IvorySQL 的最新版本 5.0 与 PostgreSQL 的最新次要版本 18.0 保持兼容,并为主流 Linux 发行版提供二进制 RPM/DEB 包。 Pigsty 提供了在 PG RDS 中用 IvorySQL 内核替换原生 PostgreSQL 的选项,支持所有 Pigsty 支持的 Linux 系统。


快速开始

使用标准流程以 ivory 配置模板 安装 Pigsty:

curl -fsSL https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty;
./configure -c ivory     # 使用 IvorySQL 配置模板
./install.yml            # 运行安装剧本

对于生产部署,您应该编辑自动生成的 pigsty.yml 配置文件,在执行 ./install.yml 进行部署之前修改密码等参数。

最新的 IvorySQL 5.0 等价于 PostgreSQL 18.0。任何与 PostgreSQL 线协议兼容的客户端工具都可以访问 IvorySQL 集群。

默认情况下,您可以使用 PostgreSQL 客户端通过替代的 1521 端口访问,该端口默认启用 Oracle 兼容模式。


配置说明

要在 Pigsty 中使用 IvorySQL 内核,请修改以下四个配置参数:

就这么简单——只需在配置文件的全局变量中添加这四行,Pigsty 就会用 IvorySQL 替换原生 PostgreSQL 内核:

pg_mode: ivory                           # IvorySQL 兼容模式,使用 IvorySQL 二进制文件
pg_packages: [ ivorysql, pgsql-common ]  # 安装 ivorysql,替换 pgsql-main 内核
pg_libs: 'liboracle_parser, pg_stat_statements, auto_explain'  # 加载 Oracle 兼容性扩展
repo_extra_packages: [ ivorysql ]        # 下载 ivorysql 包

IvorySQL 还提供了一系列新的 GUC 参数,可以在 pg_parameters 中指定。


扩展

PGSQL 模块的大多数扩展(非 SQL 类)不能直接在 IvorySQL 内核上使用。 如果您需要使用它们,您需要为新内核从源代码重新编译和安装。


注意事项

  • IvorySQL 软件包位于 pigsty-infra 仓库中,而不在 pigsty-pgsqlpigsty-ivory 仓库中。
  • Pigsty 不为使用 IvorySQL 内核承担任何保证,任何问题或请求应联系制造商。

16.5 - Percona

支持 TDE 的 Percona Postgres 发行版

Percona Postgres 是一个带有 pg_tde(透明数据加密)扩展的补丁 Postgres 内核。

它与 PostgreSQL 18.1 兼容,在所有 Pigsty 支持的平台上都可用。


快速开始

使用 pgtde 配置模板 安装 Pigsty。

curl -fsSL https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty;
./configure -c pgtde     # 使用 percona postgres 内核
./install.yml            # 使用 pigsty 设置一切

配置

需要调整以下参数来部署 Percona 集群:

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
      - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
    pg_databases:
      - name: meta
        baseline: cmdb.sql
        comment: pigsty tde database
        schemas: [pigsty]
        extensions: [ vector, postgis, pg_tde ,pgaudit, { name: pg_stat_monitor, schema: monitor } ]
    pg_hba_rules:
      - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # 每天凌晨 1 点进行全量备份

    # Percona PostgreSQL TDE 临时设置
    pg_packages: [ percona-main, pgsql-common ]  # 安装 percona postgres 包
    pg_libs: 'pg_tde, pgaudit, pg_stat_statements, pg_stat_monitor, auto_explain'

扩展

Percona 提供了 80 个可用的扩展,包括 pg_tde, pgvector, postgis, pgaudit, set_user, pg_stat_monitor 等实用三方扩展。

name version comment
hstore_plperlu 1.0 transform between hstore and plperlu
jsonb_plperl 1.0 transform between jsonb and plperl
intagg 1.1 integer aggregator and enumerator (obsolete)
pltcl 1.0 PL/Tcl procedural language
isn 1.3 data types for international product numbering standards
pgstattuple 1.5 show tuple-level statistics
postgis_topology-3 3.5.4 PostGIS topology spatial types and functions
postgis_raster 3.5.4 PostGIS raster types and functions
tsm_system_rows 1.0 TABLESAMPLE method which accepts number of rows as a limit
lo 1.2 Large Object maintenance
hstore_plperl 1.0 transform between hstore and plperl
ltree 1.3 data type for hierarchical tree-like structures
postgis_raster-3 3.5.4 PostGIS raster types and functions
postgis_topology 3.5.4 PostGIS topology spatial types and functions
pgrowlocks 1.2 show row-level locking information
address_standardizer_data_us-3 3.5.4 Address Standardizer US dataset example
uuid-ossp 1.1 generate universally unique identifiers (UUIDs)
postgis-3 3.5.4 PostGIS geometry and geography spatial types and functions
hstore_plpython3u 1.0 transform between hstore and plpython3u
postgis 3.5.4 PostGIS geometry and geography spatial types and functions
set_user 4.2.0 similar to SET ROLE but with added logging
postgis_tiger_geocoder-3 3.5.4 PostGIS tiger geocoder and reverse geocoder
jsonb_plperlu 1.0 transform between jsonb and plperlu
pg_surgery 1.0 extension to perform surgery on a damaged relation
xml2 1.2 XPath querying and XSLT
pg_stat_monitor 2.3 The pg_stat_monitor is a PostgreSQL Query Performance Monitoring tool, based on PostgreSQL contrib module pg_stat_statements. pg_stat_monitor provides aggregated statistics, client information, plan details including plan, and histogram information.
pg_tde 2.1 pg_tde access method
plpgsql 1.0 PL/pgSQL procedural language
address_standardizer-3 3.5.4 Used to parse an address into constituent elements. Generally used to support geocoding address normalization step.
tablefunc 1.0 functions that manipulate whole tables, including crosstab
hstore 1.8 data type for storing sets of (key, value) pairs
vector 0.8.1 vector data type and ivfflat and hnsw access methods
postgis_tiger_geocoder 3.5.4 PostGIS tiger geocoder and reverse geocoder
dblink 1.2 connect to other PostgreSQL databases from within a database
pltclu 1.0 PL/TclU untrusted procedural language
pg_trgm 1.6 text similarity measurement and index searching based on trigrams
sslinfo 1.2 information about SSL certificates
pg_stat_statements 1.12 track planning and execution statistics of all SQL statements executed
bool_plperlu 1.0 transform between bool and plperlu
cube 1.5 data type for multidimensional cubes
ltree_plpython3u 1.0 transform between ltree and plpython3u
amcheck 1.5 functions for verifying relation integrity
postgis_sfcgal 3.5.4 PostGIS SFCGAL functions
plpython3u 1.0 PL/Python3U untrusted procedural language
tsm_system_time 1.0 TABLESAMPLE method which accepts time in milliseconds as a limit
intarray 1.5 functions, operators, and index support for 1-D arrays of integers
btree_gist 1.8 support for indexing common datatypes in GiST
plperlu 1.0 PL/PerlU untrusted procedural language
fuzzystrmatch 1.2 determine similarities and distance between strings
bool_plperl 1.0 transform between bool and plperl
btree_gin 1.3 support for indexing common datatypes in GIN
pg_prewarm 1.2 prewarm relation data
pg_repack 1.5.3 Reorganize tables in PostgreSQL databases with minimal locks
citext 1.8 data type for case-insensitive character strings
pgcrypto 1.4 cryptographic functions
moddatetime 1.0 functions for tracking last modification time
plperl 1.0 PL/Perl procedural language
seg 1.4 data type for representing line segments or floating-point intervals
earthdistance 1.2 calculate great-circle distances on the surface of the Earth
unaccent 1.1 text search dictionary that removes accents
postgres_fdw 1.2 foreign-data wrapper for remote PostgreSQL servers
pg_logicalinspect 1.0 functions to inspect logical decoding components
tcn 1.0 Triggered change notifications
bloom 1.0 bloom access method - signature file based index
dict_int 1.0 text search dictionary template for integers
autoinc 1.0 functions for autoincrementing fields
address_standardizer_data_us 3.5.4 Address Standardizer US dataset example
postgis_sfcgal-3 3.5.4 PostGIS SFCGAL functions
jsonb_plpython3u 1.0 transform between jsonb and plpython3u
file_fdw 1.0 foreign-data wrapper for flat file access
pgaudit 18.0 provides auditing functionality
dict_xsyn 1.0 text search dictionary template for extended synonym processing
pg_walinspect 1.1 functions to inspect contents of PostgreSQL Write-Ahead Log
pg_buffercache 1.6 examine the shared buffer cache
refint 1.0 functions for implementing referential integrity (obsolete)
pg_freespacemap 1.3 examine the free space map (FSM)
insert_username 1.0 functions for tracking who changed a table
address_standardizer 3.5.4 Used to parse an address into constituent elements. Generally used to support geocoding address normalization step.
pg_visibility 1.2 examine the visibility map (VM) and page-level visibility info
pageinspect 1.13 inspect the contents of database pages at a low level

16.6 - PolarDB

PolarDB for PostgreSQL,带有 aurora 风格的 RAC

PolarDB 是一个由阿里云开发并开源的 aurora RAC 风格"云原生"数据库系统。

当前仓库中的最新版本 v15.15.5.0 与 PostgreSQL 15 兼容,在所有 Pigsty 支持的操作系统上都可用。


快速开始

使用 polar 配置模板 安装 Pigsty。

curl -fsSL https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty;
./configure -c polar     # 使用 polar(PolarDB)模板
./install.yml            # 运行部署剧本

配置

需要调整以下参数来部署 PolarDB 集群:

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
      - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
    pg_databases:
      - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # 每天凌晨 1 点进行全量备份

    # PolarDB 临时设置
    pg_version: 15                            # PolarDB PG 基于 PG 15
    pg_mode: polar                            # PolarDB PG 兼容模式
    pg_packages: [ polardb, pgsql-common ]    # 用 PolarDB 内核替换 PG 内核
    pg_exporter_exclude_database: 'template0,template1,postgres,polardb_admin'
    pg_default_roles:                         # PolarDB 要求 replicator 为超级用户
      - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
      - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
      - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
      - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
      - { name: postgres     ,superuser: true  ,comment: system superuser }
      - { name: replicator   ,superuser: true  ,replication: true ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator } # <- 复制需要超级用户权限
      - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
      - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

PolarDB for PostgreSQL 本质上等价于 PostgreSQL 15,任何与 PostgreSQL 线协议兼容的客户端工具都可以访问 PolarDB 集群。

扩展

PGSQL 模块的大多数扩展(非纯 SQL)不能直接在 PolarDB 内核上使用。如果您需要使用它们,您需要为新内核从源代码重新编译和安装。

这是 PolarDB 内核提供的扩展列表:

name Version comment
adminpack 2.1 administrative functions for PostgreSQL
amcheck 1.3 functions for verifying relation integrity
autoinc 1.0 functions for autoincrementing fields
bloom 1.0 bloom access method - signature file based index
bool_plperl 1.0 transform between bool and plperl
bool_plperlu 1.0 transform between bool and plperlu
btree_gin 1.3 support for indexing common datatypes in GIN
btree_gist 1.7 support for indexing common datatypes in GiST
citext 1.6 data type for case-insensitive character strings
cube 1.5 data type for multidimensional cubes
dblink 1.2 connect to other PostgreSQL databases from within a database
dict_int 1.0 text search dictionary template for integers
dict_xsyn 1.0 text search dictionary template for extended synonym processing
earthdistance 1.1 calculate great-circle distances on the surface of the Earth
file_fdw 1.0 foreign-data wrapper for flat file access
fuzzystrmatch 1.1 determine similarities and distance between strings
hll 2.18 type for storing hyperloglog data
hstore 1.8 data type for storing sets of (key, value) pairs
hstore_plperl 1.0 transform between hstore and plperl
hstore_plperlu 1.0 transform between hstore and plperlu
hstore_plpython3u 1.0 transform between hstore and plpython3u
hypopg 1.3.1 Hypothetical indexes for PostgreSQL
insert_username 1.0 functions for tracking who changed a table
intagg 1.1 integer aggregator and enumerator (obsolete)
intarray 1.5 functions, operators, and index support for 1-D arrays of integers
isn 1.2 data types for international product numbering standards
jsonb_plperl 1.0 transform between jsonb and plperl
jsonb_plperlu 1.0 transform between jsonb and plperlu
jsonb_plpython3u 1.0 transform between jsonb and plpython3u
lo 1.1 Large Object maintenance
log_fdw 1.4 foreign-data wrapper for Postgres log file access
ltree 1.2 data type for hierarchical tree-like structures
ltree_plpython3u 1.0 transform between ltree and plpython3u
moddatetime 1.0 functions for tracking last modification time
old_snapshot 1.0 utilities in support of old_snapshot_threshold
pageinspect 1.11 inspect the contents of database pages at a low level
pase 0.0.1 ant ai similarity search
pg_bigm 1.2 text similarity measurement and index searching based on bigrams
pg_buffercache 1.4 examine the shared buffer cache
pg_freespacemap 1.2 examine the free space map (FSM)
pg_jieba 1.1.0 a parser for full-text search of Chinese
pg_prewarm 1.2 prewarm relation data
pg_repack 1.5.1-1 Reorganize tables in PostgreSQL databases with minimal locks
pg_stat_statements 1.10 track planning and execution statistics of all SQL statements executed
pg_surgery 1.0 extension to perform surgery on a damaged relation
pg_trgm 1.6 text similarity measurement and index searching based on trigrams
pg_visibility 1.2 examine the visibility map (VM) and page-level visibility info
pg_walinspect 1.0 functions to inspect contents of PostgreSQL Write-Ahead Log
pgcrypto 1.3 cryptographic functions
pgrowlocks 1.2 show row-level locking information
pgstattuple 1.5 show tuple-level statistics
plperl 1.0 PL/Perl procedural language
plperlu 1.0 PL/PerlU untrusted procedural language
plpgsql 1.0 PL/pgSQL procedural language
plpython3u 1.0 PL/Python3U untrusted procedural language
pltcl 1.0 PL/Tcl procedural language
pltclu 1.0 PL/TclU untrusted procedural language
polar_audit 1.0 provides auditing functionality
polar_feature_utils 1.0 PolarDB feature utilization
polar_io_stat 1.0 polar io stat in multi dimension
polar_login_history 1.0 record user login information
polar_masking 1.0.0 provides data masking for polardb
polar_monitor 1.0 monitor functions for PolarDB
polar_monitor_preload 1.0 examine the polardb information
polar_parameter_manager 1.1 Extension to select parameters for manger.
polar_password_policy 1.0 create password policies and check user passwords based on the policies
polar_proxy_utils 1.0 Extension to provide operations about proxy.
polar_resource_manager 1.0 a background process that forcibly frees user session process memory
polar_smgrperf 1.0 smgr perf test extension
polar_sql_mapping 1.0 Record error sqls and mapping them to correct one
polar_stat_env 1.0 env stat functions for PolarDB
polar_vfs 1.0 polar virtual file system for different storage
polar_worker 1.0 polar_worker
postgres_fdw 1.1 foreign-data wrapper for remote PostgreSQL servers
refint 1.0 functions for implementing referential integrity (obsolete)
roaringbitmap 0.5 support for Roaring Bitmaps
seg 1.4 data type for representing line segments or floating-point intervals
sslinfo 1.2 information about SSL certificates
tablefunc 1.0 functions that manipulate whole tables, including crosstab
tcn 1.0 Triggered change notifications
tsm_system_rows 1.0 TABLESAMPLE method which accepts number of rows as a limit
tsm_system_time 1.0 TABLESAMPLE method which accepts time in milliseconds as a limit
unaccent 1.1 text search dictionary that removes accents
uuid-ossp 1.1 generate universally unique identifiers (UUIDs)
vector 0.6.2 vector data type and ivfflat and hnsw access methods
xml2 1.1 XPath querying and XSLT

PolarDB for Oracle

还有 PolarDB 的第二个分支,即 PolarDB for Oracle,它不是开源的。

Pigsty Pro 支持将 PolarDB for Oracle 作为 RDS 运行。

16.7 - OrioleDB

PostgreSQL 的下一代 OLTP 引擎

OrioleDB 是一个 PostgreSQL 存储引擎扩展,声称能够 提供 4 倍 OLTP 性能,没有 xid 环绕和表膨胀问题,并具有"云原生"(数据存储在 s3)能力。

OrioleDB 的最新版本基于 补丁版 PostgreSQL 17.0 和一个额外的扩展

您可以使用 pigsty 将 OrioleDB 作为 RDS 运行,它与 PG 17 兼容,在所有支持的 Linux 平台上都可用。 最新版本为 beta12 ,基于 PG 17_11 补丁。


快速开始

按照 Pigsty 标准安装 流程,使用 oriole 配置模板。

curl -fsSL https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty;
./configure -c oriole    # 使用 OrioleDB 配置模板
./install.yml            # 使用 OrioleDB 安装 Pigsty

对于生产部署,请确保在运行 install 剧本之前修改 pigsty.yml 配置中的密码参数。


配置

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
      - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
    pg_databases:
      - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty], extensions: [orioledb]}
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # 每天凌晨 1 点进行全量备份

    # OrioleDB 临时设置
    pg_mode: oriole                                         # oriole 兼容模式
    pg_packages: [ orioledb, pgsql-common ]                 # 安装 OrioleDB 内核
    pg_libs: 'orioledb, pg_stat_statements, auto_explain'   # 加载 OrioleDB 扩展

使用

要使用 OrioleDB,您需要安装 orioledb_17oriolepg_17 包(目前仅提供 RPM 版本)。

使用 pgbench 初始化类似 TPC-B 的表,包含 100 个仓库:

pgbench -is 100 meta
pgbench -nv -P1 -c10 -S -T1000 meta
pgbench -nv -P1 -c50 -S -T1000 meta
pgbench -nv -P1 -c10    -T1000 meta
pgbench -nv -P1 -c50    -T1000 meta

接下来,您可以使用 orioledb 存储引擎重建这些表并观察性能差异:

-- 创建 OrioleDB 表
CREATE TABLE pgbench_accounts_o (LIKE pgbench_accounts INCLUDING ALL) USING orioledb;
CREATE TABLE pgbench_branches_o (LIKE pgbench_branches INCLUDING ALL) USING orioledb;
CREATE TABLE pgbench_history_o (LIKE pgbench_history INCLUDING ALL) USING orioledb;
CREATE TABLE pgbench_tellers_o (LIKE pgbench_tellers INCLUDING ALL) USING orioledb;

-- 从常规表复制数据到 OrioleDB 表
INSERT INTO pgbench_accounts_o SELECT * FROM pgbench_accounts;
INSERT INTO pgbench_branches_o SELECT * FROM pgbench_branches;
INSERT INTO pgbench_history_o SELECT  * FROM pgbench_history;
INSERT INTO pgbench_tellers_o SELECT * FROM pgbench_tellers;

-- 删除原始表并重命名 OrioleDB 表
DROP TABLE pgbench_accounts, pgbench_branches, pgbench_history, pgbench_tellers;
ALTER TABLE pgbench_accounts_o RENAME TO pgbench_accounts;
ALTER TABLE pgbench_branches_o RENAME TO pgbench_branches;
ALTER TABLE pgbench_history_o RENAME TO pgbench_history;
ALTER TABLE pgbench_tellers_o RENAME TO pgbench_tellers;

16.8 - OpenHalo

MySQL 兼容的 Postgres 14 分支

OpenHalo 是一个开源的 PostgreSQL 内核,提供 MySQL 线协议兼容性。

OpenHalo 基于 PostgreSQL 14.10 内核版本,提供与 MySQL 5.7.32-log / 8.0 版本的线协议兼容性。

Pigsty 在所有支持的 Linux 平台上为 OpenHalo 提供部署支持。


快速开始

使用 Pigsty 的 标准安装流程mysql 配置模板。

curl -fsSL https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty;
./configure -c mysql    # 使用 MySQL(openHalo)配置模板
./install.yml           # 安装,生产部署请先在 pigsty.yml 中修改密码

对于生产部署,请确保在运行安装剧本之前修改 pigsty.yml 配置文件中的密码参数。


配置

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - {name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
      - {name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
    pg_databases:
      - {name: postgres, extensions: [aux_mysql]} # mysql 兼容数据库
      - {name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty]}
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # 每天凌晨 1 点进行全量备份

    # OpenHalo 临时设置
    pg_mode: mysql                    # HaloDB 的 MySQL 兼容模式
    pg_version: 14                    # 当前 HaloDB 兼容 PG 主版本 14
    pg_packages: [ openhalodb, pgsql-common ]  # 安装 openhalodb 而不是 postgresql 内核

使用

访问 MySQL 时,实际连接使用的是 postgres 数据库。请注意,MySQL 中的"数据库"概念实际上对应于 PostgreSQL 中的"Schema"。因此,use mysql 实际上使用的是 postgres 数据库内的 mysql Schema。

用于 MySQL 的用户名和密码与 PostgreSQL 中的相同。您可以使用标准的 PostgreSQL 方法管理用户和权限。

客户端访问

OpenHalo 提供 MySQL 线协议兼容性,默认监听端口 3306,允许 MySQL 客户端和驱动程序直接连接。

Pigsty 的 conf/mysql 配置默认安装 mysql 客户端工具。

您可以使用以下命令访问 MySQL:

mysql -h 127.0.0.1 -u dbuser_dba

目前,OpenHalo 官方确保 Navicat 可以正常访问此 MySQL 端口,但 Intellij IDEA 的 DataGrip 访问会导致错误。


修改

Pigsty 安装的 OpenHalo 内核基于 HaloTech-Co-Ltd/openHalo 内核进行了少量修改:

  • 将默认数据库名称从 halo0root 改回 postgres
  • 从默认版本号中删除 1.0. 前缀,恢复为 14.10
  • 修改默认配置文件以启用 MySQL 兼容性并默认监听端口 3306

请注意,Pigsty 不为使用 OpenHalo 内核提供任何保证。使用此内核时遇到的任何问题或需求应与原始供应商联系。

16.9 - Cloudberry

Cloudberry 和 Greenplum,MPP 数据仓库

您可以部署和监控 Cloudberry 集群,这是 Greenplum 的一个分支。

要定义 Greenplum 集群,您需要指定以下参数:

POC

我们正在等待 Apache Cloudberry 2.0 的官方发布,因此现在请勿在生产环境中使用


安装

要安装 cloudberry,您必须启用 gpsql 仓库模块:

./node.yml -t node_install  -e '{"node_repo_modules":"node,pgsql,gpsql","node_packages":["cloudberrydb"]}'

配置

设置 pg_mode = gpsql 和额外的标识参数 pg_shardgp_role

#================================================================#
#                        GPSQL 集群                              #
#================================================================#

#----------------------------------#
# 集群:mx-mdw (gp master)
#----------------------------------#
mx-mdw:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary , nodename: mx-mdw-1 }
  vars:
    gp_role: master          # 此集群用作 greenplum master
    pg_shard: mx             # pgsql 分片名称和 gpsql 部署名称
    pg_cluster: mx-mdw       # 此 master 集群名称为 mx-mdw
    pg_databases:
      - { name: matrixmgr , extensions: [ { name: matrixdbts } ] }
      - { name: meta }
    pg_users:
      - { name: meta , password: DBUser.Meta , pgbouncer: true }
      - { name: dbuser_monitor , password: DBUser.Monitor , roles: [ dbrole_readonly ], superuser: true }

    pgbouncer_enabled: true                # 为 greenplum master 启用 pgbouncer
    pgbouncer_exporter_enabled: false      # 为 greenplum master 启用 pgbouncer_exporter
    pg_exporter_params: 'host=127.0.0.1&sslmode=disable'  # 使用 127.0.0.1 作为本地监控主机

#----------------------------------#
# 集群:mx-sdw (gp master)
#----------------------------------#
mx-sdw:
  hosts:
    10.10.10.11:
      nodename: mx-sdw-1        # greenplum 段节点
      pg_instances:             # greenplum 段实例
        6000: { pg_cluster: mx-seg1, pg_seq: 1, pg_role: primary , pg_exporter_port: 9633 }
        6001: { pg_cluster: mx-seg2, pg_seq: 2, pg_role: replica , pg_exporter_port: 9634 }
    10.10.10.12:
      nodename: mx-sdw-2
      pg_instances:
        6000: { pg_cluster: mx-seg2, pg_seq: 1, pg_role: primary , pg_exporter_port: 9633  }
        6001: { pg_cluster: mx-seg3, pg_seq: 2, pg_role: replica , pg_exporter_port: 9634  }
    10.10.10.13:
      nodename: mx-sdw-3
      pg_instances:
        6000: { pg_cluster: mx-seg3, pg_seq: 1, pg_role: primary , pg_exporter_port: 9633 }
        6001: { pg_cluster: mx-seg1, pg_seq: 2, pg_role: replica , pg_exporter_port: 9634 }
  vars:
    gp_role: segment               # 这些是 gp 段的节点
    pg_shard: mx                   # pgsql 分片名称和 gpsql 部署名称
    pg_cluster: mx-sdw             # 这些段集群名称为 mx-sdw
    pg_preflight_skip: true        # 跳过预检查(因为 pg_seq 和 pg_role 和 pg_cluster 不存在)
    pg_exporter_config: pg_exporter_basic.yml                             # 使用基本配置以避免段服务器崩溃
    pg_exporter_params: 'options=-c%20gp_role%3Dutility&sslmode=disable'  # 使用 gp_role = utility 连接到段

16.10 - Supabase

在您的 Postgres 上自托管 BaaS —— Supabase

最新的自托管教程请参阅:Supabase

Supabase 很好,拥有属于你自己的 supabase 则好上加好。 Pigsty 可以帮助您在自己的服务器上(物理机/虚拟机/云服务器),一键自建企业级 supabase —— 更多扩展,更好性能,更深入的控制,更合算的成本。

Pigsty 是 Supabase 官网文档上列举的三种自建部署之一:Self-hosting: Third-Party Guides


简短版本

准备 Linux,执行 Pigsty 标准安装 流程,选择 supabase 配置模板,依次执行:

curl -fsSL https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty
./configure -c supabase    # 使用 supabase 配置(请在 pigsty.yml 中更改凭据)
vi pigsty.yml              # 编辑域名、密码、密钥...
./install.yml              # 安装 pigsty
./docker.yml               # 安装 docker compose 组件
./app.yml                  # 使用 docker 启动 supabase 无状态部分(可能较慢)

安装完毕后,使用浏览器访问 8000 端口造访 Supa Studio,用户名 supabase,密码 pigsty


目录


Supabase是什么?

Supabase 是一个 BaaS (Backend as Service),开源的 Firebase,是 AI Agent 时代最火爆的数据库 + 后端解决方案。 Supabase 对 PostgreSQL 进行了封装,并提供了身份认证,消息传递,边缘函数,对象存储,并基于 PG 数据库模式自动生成 REST API 与 GraphQL API。

Supabase 旨在为开发者提供一条龙式的后端解决方案,减少开发和维护后端基础设施的复杂性。 它能让开发者告别绝大部分后端开发的工作,只需要懂数据库设计与前端即可快速出活! 开发者只要用 Vibe Coding 糊个前端与数据库模式设计,就可以快速完成一个完整的应用。

目前,Supabase 是 PostgreSQL 开源生态 中人气最高的开源项目,在 GitHub 上已有 八万 Star。 Supabase 还为小微创业者提供了“慷慨”的免费云服务额度 —— 免费的 500 MB 空间,对于存个用户表,浏览数之类的东西绰绰有余。


为什么要自建?

既然 Supabase 云服务这么香,为什么要自建呢?

最直观的原因是是我们在《云数据库是智商税吗?》中提到过的:当你的数据/计算规模超出云计算适用光谱(Supabase:4C/8G/500MB免费存储),成本很容易出现爆炸式增长。 而且在当下,足够可靠的 本地企业级 NVMe SSD 在性价比上与 云端存储 有着三到四个数量级的优势,而自建能更好地利用这一点。

另一个重要的原因是 功能, Supabase 云服务的功能受限 —— 很多强力PG扩展因为多租户安全挑战与许可证的原因无法以云服务的形式。 故而尽管 扩展是 PostgreSQL 的核心特色,在 Supabase 云服务上也依然只有 64 个扩展可用。 而通过 Pigsty 自建的 Supabase 则提供了多达 437 个开箱即用的 PG 扩展。

此外,自主可控与规避供应商锁定也是自建的重要原因 —— 尽管 Supabase 虽然旨在提供一个无供应商锁定的 Google Firebase 开源替代,但实际上自建高标准企业级的 Supabase 门槛并不低。 Supabase 内置了一系列由他们自己开发维护的 PG 扩展插件,并计划将原生的 PostgreSQL 内核替换为收购的 OrioleDB,而这些内核与扩展在 PGDG 官方仓库中并没有提供。

这实际上是某种隐性的供应商锁定,阻止了用户使用除了 supabase/postgres Docker 镜像之外的方式自建,Pigsty 则提供开源,透明,通用的方案解决这个问题。 我们将所有 Supabase 自研与用到的 10 个缺失的扩展打成开箱即用的 RPM/DEB 包,确保它们在所有 主流Linux操作系统发行版 上都可用:

扩展 说明
pg_graphql 提供PG内的GraphQL支持 (RUST),Rust扩展,由PIGSTY提供
pg_jsonschema 提供JSON Schema校验能力,Rust扩展,由PIGSTY提供
wrappers Supabase提供的外部数据源包装器捆绑包,,Rust扩展,由PIGSTY提供
index_advisor 查询索引建议器,SQL扩展,由PIGSTY提供
pg_net 用 SQL 进行异步非阻塞HTTP/HTTPS 请求的扩展 (supabase),C扩展,由PIGSTY提供
vault 在 Vault 中存储加密凭证的扩展 (supabase),C扩展,由PIGSTY提供
pgjwt JSON Web Token API 的PG实现 (supabase),SQL扩展,由PIGSTY提供
pgsodium 表数据加密存储 TDE,扩展,由PIGSTY提供
supautils 用于在云环境中确保数据库集群的安全,C扩展,由PIGSTY提供
pg_plan_filter 使用执行计划代价过滤阻止特定查询语句,C扩展,由PIGSTY提供

同时,我们在 Supabase 自建部署中默认 安装绝大多数扩展,您可以参考可用扩展列表按需 启用

同时,Pigsty 还会负责好底层 高可用 PostgreSQL 数据库集群,高可用 MinIO 对象存储集群的自动搭建,甚至是 Docker 容器底座的部署与 Nginx 反向代理,域名配置HTTPS证书签发。 您可以使用 Docker Compose 拉起任意数量的无状态 Supabase 容器集群,并将状态存储在外部 Pigsty 自托管数据库服务中。

在这一自建部署架构中,您获得了使用不同内核的自由(PG 15-18,OrioleDB),加装 437 个扩展的自由,扩容与伸缩 Supabase / Postgres / MinIO 的自由, 免于数据库运维杂务的自由,以及免于供应商锁定,本地运行到地老天荒的自由。 而相比于使用云服务需要付出的代价,不过是准备服务器和多敲几行命令而已。


单节点自建快速上手

让我们先从单节点 Supabase 部署开始,我们会在后面进一步介绍多节点高可用部署的方法。

准备 一台全新 Linux 服务器,使用 Pigsty 提供的 supabase 配置模板执行 标准安装, 然后额外运行 docker.ymlapp.yml 拉起无状态部分的 Supabase 容器即可(默认端口 8000/8433)。

curl -fsSL https://repo.pigsty.io/get | bash -s v3.7.0; cd ~/pigsty
./configure -c supabase    # 使用 supabase 配置(请在 pigsty.yml 中更改凭据)
vi pigsty.yml              # 编辑域名、密码、密钥...
./install.yml              # 安装 pigsty
./docker.yml               # 安装 docker compose 组件
./app.yml                  # 使用 docker 启动 supabase 无状态部分

在部署 Supabase 前请根据实际情况修改自动生成的 pigsty.yml 配置文件中的参数(域名与密码) 如果只是本地开发测试,可以先跳过,我们将在后面介绍如何通过修改配置文件来进一步定制。

asciicast

如果配置无误,大约十分钟后,就可以在本地网络通过 http://<your_ip_address>:8000 访问到 Supabase Studio 图形管理界面了。 默认的用户名与密码分别是: supabasepigsty

中国大陆地区 DockerHub 被墙

在中国大陆地区,Pigsty 默认使用 1Panel 与 1ms 提供的 DockerHub 镜像站点下载 Supabase 相关镜像,可能会较慢。 你也可以自行配置 代理镜像站cd /opt/supabase; docker compose pull 手动拉取镜像。 我们亦提供包含完整离线安装方案的 Supabase 自建专家咨询服务

使用 Supabase 的对象存储需要HTTPS/域名

如果你需要使用的对象存储功能,那么需要通过域名与 HTTPS 访问 Supabase,否则会出现报错。

生产部署请务必修改密码!

对于严肃的生产部署,请 务必 修改所有默认密码!


自建关键技术决策

以下是一些自建 Supabase 会涉及到的关键技术决策,供您参考:

使用默认的单节点部署 Supabase 无法享受到 PostgreSQL / MinIO 的高可用能力。 尽管如此,单节点部署相比官方纯 Docker Compose 方案依然要有显著优势: 例如开箱即用的监控系统,自由安装扩展的能力,各个组件的扩缩容能力,以及提供兜底数据库时间点恢复能力等。

如果您只有一台服务器,或者选择在云服务器上自建,Pigsty 建议您使用外部的 S3 替代本地的 MinIO 作为对象存储,存放 PostgreSQL 的备份,并承载 Supabase Storage 服务。 这样的部署在故障时可以在单机部署条件下,提供一个兜底级别的 RTO (小时级恢复时长)/ RPO (MB级数据损失)容灾水平。

在严肃的生产部署中,Pigsty 建议使用至少3~4个节点的部署策略,确保 MinIO 与 PostgreSQL 都使用满足企业级高可用要求的多节点部署。 在这种情况下,您需要相应准备更多节点与磁盘,并相应调整 pigsty.yml 配置清单中的集群配置,以及 supabase 集群配置中的接入信息,使用高可用接入点访问服务。

Supabase 的部分功能需要发送邮件,所以要用到 SMTP 服务。除非单纯用于内网,否则对于严肃的生产部署,建议使用 SMTP 云服务。自建的邮件服务器发送的邮件容易被标记为垃圾邮件导致拒收。

如果您的服务直接向公网暴露,我们强烈建议您使用真正的域名与 HTTPS 证书,并通过 Nginx 门户 访问。

接下来,我们会依次讨论一些进阶主题。如何在单节点部署的基础上,进一步提升 Supabase 的安全性、可用性与性能。


进阶主题:安全加固

Pigsty基础组件

对于严肃的生产部署,我们强烈建议您修改 Pigsty 基础组件的密码。因为这些默认值是公开且众所周知的,不改密码上生产无异于裸奔:

以上密码为 Pigsty 组件模块的密码,强烈建议在安装部署前就设置完毕。

Supabase密钥

除了 Pigsty 组件的密码,你还需要 修改 Supabase 的密钥,包括

这里请您务必参照 Supabase教程:保护你的服务 里的说明:

  • 生成一个长度超过 40 个字符的 JWT_SECRET,并使用教程中的工具签发 ANON_KEYSERVICE_ROLE_KEY 两个 JWT。
  • 使用教程中提供的工具,根据 JWT_SECRET 以及过期时间等属性,生成一个 ANON_KEY JWT,这是匿名用户的身份凭据。
  • 使用教程中提供的工具,根据 JWT_SECRET 以及过期时间等属性,生成一个 SERVICE_ROLE_KEY,这是权限更高服务角色的身份凭据。
  • 指定一个32个字符以上的随机字符串密钥 PG_META_CRYPTO_KEY,用于加密 Studio UI 与 meta 服务的交互
  • 如果您使用的 PostgreSQL 业务用户使用了不同于默认值的密码,请相应修改 `POSTGRES_PASSWORD`` 的值
  • 如果您的对象存储使用了不同于默认值的密码,请相应修改 S3_ACCESS_KEY``](https://github.com/pgsty/pigsty/blob/v3.7.0/conf/supabase.yml#L154) 与 [S3_SECRET_KEY`` 的值

Supabase 部分的凭据修改后,您可以重启 Docker Compose 容器以应用新的配置:

./app.yml -t app_config,app_launch
cd /opt/supabase; make up

进阶主题:域名接入

如果你在本机或局域网内使用 Supabase,那么可以选择 IP:Port 直连 Kong 对外暴露的 HTTP 8000 端口访问 Supabase。

你可以使用一个内网静态解析的域名,但对于严肃的生产部署,我们建议您使用真域名 + HTTPS 来访问 Supabase。 在这种情况下,您的服务器应当有一个公网 IP 地址,你应当拥有一个域名,使用云/DNS/CDN 供应商提供的 DNS 解析服务,将其指向安装节点的公网 IP(可选默认下位替代:本地 /etc/hosts 静态解析)。

比较简单的做法是,直接批量替换占位域名(supa.pigsty)为你的实际域名,假设为 supa.pigsty.cc

sed -ie 's/supa.pigsty.cc/supa.pigsty/g/' ~/pigsty/pigsty.yml

如果你没有事先配置好,那么重载 Nginx 和 Supabase 的配置生效即可:

make nginx      # 重载 nginx 配置
make cert       # 申请 certbot 免费 HTTPS 证书
./app.yml       # 重载 Supabase 配置

修改后的配置应当类似下面的片段:

all:
  vars:
    infra_portal:
      supa :
        domain: supa.pigsty.cc        # 替换为你的域名!
        endpoint: "10.10.10.10:8000"
        websocket: true
        certbot: supa.pigsty.cc       # 证书名称,通常与域名一致即可

  children:
    supabase:
      vars:
          supabase:                                       # the definition of supabase app
            conf:                                         # override /opt/supabase/.env
              SITE_URL: https://supa.pigsty                # <------- Change This to your external domain name
              API_EXTERNAL_URL: https://supa.pigsty        # <------- Otherwise the storage api may not work!
              SUPABASE_PUBLIC_URL: https://supa.pigsty     # <------- DO NOT FORGET TO PUT IT IN infra_portal!

完整的域名/HTTPS 配置可以参考 证书管理 教程,您也可以使用 Pigsty 自带的本地静态解析与自签发 HTTPS 证书作为下位替代。

asciicast


进阶主题:外部对象存储

您可以使用 S3 或 S3 兼容的服务,来作为 PGSQL 备份与 Supabase 使用的对象存储。这里我们使用一个 阿里云 OSS 对象存储作为例子。

Pigsty 提供了一个 terraform/spec/aliyun-meta-s3.tf 模板, 可以用于在阿里云上拉起一台服务器,以及一个 OSS 存储桶。

首先,我们修改 all.children.supa.vars.apps.[supabase].conf 中 S3 相关的配置,将其指向阿里云 OSS 存储桶:

# if using s3/minio as file storage
S3_BUCKET: data                       # 替换为 S3 兼容服务的连接信息
S3_ENDPOINT: https://sss.pigsty:9000  # 替换为 S3 兼容服务的连接信息
S3_ACCESS_KEY: s3user_data            # 替换为 S3 兼容服务的连接信息
S3_SECRET_KEY: S3User.Data            # 替换为 S3 兼容服务的连接信息
S3_FORCE_PATH_STYLE: true             # 替换为 S3 兼容服务的连接信息
S3_REGION: stub                       # 替换为 S3 兼容服务的连接信息
S3_PROTOCOL: https                    # 替换为 S3 兼容服务的连接信息

同样使用以下命令重载 Supabase 配置:

./app.yml -t app_config,app_launch

您同样可以使用 S3 作为 PostgreSQL 的备份仓库,在 all.vars.pgbackrest_repo 新增一个 aliyun 备份仓库的定义:

all:
  vars:
    pgbackrest_method: aliyun          # pgbackrest 备份方法:local,minio,[其他用户定义的仓库...],本例中将备份存储到 MinIO 上
    pgbackrest_repo:                   # pgbackrest 备份仓库: https://pgbackrest.org/configuration.html#section-repository
      aliyun:                          # 定义一个新的备份仓库 aliyun
        type: s3                       # 阿里云 oss 是 s3-兼容的对象存储
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing
        s3_bucket: pigsty-oss
        s3_key: xxxxxxxxxxxxxx
        s3_key_secret: xxxxxxxx
        s3_uri_style: host
        path: /pgbackrest
        bundle: y                         # bundle small files into a single file
        bundle_limit: 20MiB               # Limit for file bundles, 20MiB for object storage
        bundle_size: 128MiB               # Target size for file bundles, 128MiB for object storage
        cipher_type: aes-256-cbc          # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest.MyPass    # 设置一个加密密码,pgBackRest 备份仓库的加密密码
        retention_full_type: time         # retention full backup by time on minio repo
        retention_full: 14                # keep full backup for the last 14 days

然后在 all.vars.pgbackrest_mehod 中指定使用 aliyun 备份仓库,重置 pgBackrest 备份:

./pgsql.yml -t pgbackrest

Pigsty 会将备份仓库切换到外部对象存储上,更多备份配置可以参考 PostgreSQL 备份 文档。


进阶主题:使用SMTP

你可以使用 SMTP 来发送邮件,修改 supabase 应用配置,添加 SMTP 信息:

all:
  children:
    supabase:        # supa group
      vars:          # supa group vars
        apps:        # supa group app list
          supabase:  # the supabase app
            conf:    # the supabase app conf entries
              SMTP_HOST: smtpdm.aliyun.com:80
              SMTP_PORT: 80
              SMTP_USER: [email protected]
              SMTP_PASS: your_email_user_password
              SMTP_SENDER_NAME: MySupabase
              SMTP_ADMIN_EMAIL: [email protected]
              ENABLE_ANONYMOUS_USERS: false

不要忘了使用 app.yml 来重载配置


进阶主题:真·高可用

经过这些配置,您拥有了一个带公网域名,HTTPS 证书,SMTP,PITR 备份,监控,IaC,以及 400+ 扩展的企业级 Supabase (基础单机版)。 高可用的配置请参考 Pigsty 其他部份的文档,如果您懒得阅读学习,我们提供手把手扶上马的 Supabase 自建专家咨询服务 —— ¥2000 元免去折腾与下载的烦恼。

单节点的 RTO / RPO 依赖外部对象存储服务提供兜底,如果您的这个节点挂了,外部 S3 存储中保留了备份,您可以在新的节点上重新部署 Supabase,然后从备份中恢复。 这样的部署在故障时可以提供一个最低标准的 RTO (小时级恢复时长)/ RPO (MB级数据损失)兜底容灾水平 兜底。

如果想要达到 RTO < 30s ,切换零数据丢失,那么需要使用多节点进行高可用部署,这涉及到:

  • ETCD: DCS 需要使用三个节点或以上,才能容忍一个节点的故障。
  • PGSQL: PGSQL 同步提交不丢数据模式,建议使用至少三个节点。
  • INFRA:监控基础设施故障影响稍小,建议生产环境使用双副本
  • Supabase 无状态容器本身也可以是多节点的副本,可以实现高可用。

在这种情况下,您还需要修改 PostgreSQL 与 MinIO 的接入点,使用 DNS / L2 VIP / HAProxy 等 高可用接入点 关于这些部分,您只需参考 Pigsty 中各个模块的文档进行配置部署即可。 建议您参考 conf/ha/trio.ymlconf/ha/safe.yml 中的配置,将集群规模升级到三节点或以上。

16.11 - FerretDB

MongoDB 线协议兼容的 PostgreSQL 方案

FerretDB 是开源的 MongoDB 线协议兼容中间件,可将 PostgreSQL 作为 MongoDB 的直接替代后端。依赖 MongoDB 线协议的应用可以通过它无缝使用 PostgreSQL,在两个数据库生态之间建立桥梁。

启用 FerretDB 需要使用 FerretDB 修订的 documentdb 扩展;Pigsty 软件仓库也提供该扩展。此冻结版本中的最新组合为 FerretDB 2.7 与 DocumentDB 0.107.0。


快速上手

按照 Pigsty 的标准安装流程,使用 mongo 配置模板:

./configure -c mongo    # 使用 FerretDB / DocumentDB 配置模板
./install.yml           # 安装;生产部署前请先修改 pigsty.yml 中的密码

生产部署时,务必在运行安装剧本前修改 pigsty.yml 中的密码参数。


配置

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - { name: mongod      ,password: DBUser.Mongo  ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: ferretdb super user ,superuser: true }
      - { name: dbuser_meta ,password: DBUser.Meta   ,pgbouncer: true ,roles: [dbrole_admin   ] ,comment: pigsty admin user }
      - { name: dbuser_view ,password: DBUser.Viewer ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer  }
    pg_databases:
      - {name: meta, owner: mongod ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [ documentdb, postgis, vector, pg_cron, rum ]}
    pg_hba_rules:
      - { user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes' }
      - { user: mongod      , db: all ,addr: world ,auth: pwd ,title: 'mongodb password access from everywhere' }
    node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ]

    # DocumentDB 设置
    pg_extensions: [ documentdb, citus, postgis, pgvector, pg_cron, rum ]
    pg_libs: 'pg_documentdb, pg_documentdb_core, pg_cron, pg_stat_statements, auto_explain'
    pg_parameters: { cron.database_name: meta }

使用

完整说明请参阅 FERRET 模块文档。

安装客户端工具

可以使用 MongoDB 命令行工具 MongoSH 访问 FerretDB。

先用 pig 添加 MongoDB 软件仓库,再通过 yumapt 安装 mongosh

pig repo add mongo -u
yum install mongodb-mongosh
apt install mongodb-mongosh

连接 FerretDB

任何语言的 MongoDB 驱动都可以使用 MongoDB 连接串访问 FerretDB。以下为 mongosh 示例:

$ mongosh
Current Mongosh Log ID: 67ba8c1fe551f042bf51e943
Connecting to:          mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.4.0
Using MongoDB:          7.0.77
Using Mongosh:          2.4.0

For mongosh info see: https://www.mongodb.com/docs/mongodb-shell/

test>

认证

可以使用不同用户登录,细节参阅 FerretDB:认证

mongosh 'mongodb://dbuser_meta:[email protected]:27017/meta'      # 业务管理员
mongosh 'mongodb://dbuser_view:[email protected]:27017/meta'    # 只读用户

使用示例

连接 FerretDB 后,可以像使用 MongoDB 集群一样执行命令:

$ mongosh 'mongodb://dbuser_meta:[email protected]:27017/meta'

MongoDB 命令会转换为 SQL,并在底层 PostgreSQL 中执行:

use test                            // CREATE SCHEMA test;
db.dropDatabase();                  // DROP SCHEMA test;
db.createCollection('posts');       // CREATE TABLE posts(_data JSONB,...)
db.posts.insertOne({                // INSERT INTO posts VALUES(...);
    title: 'Post One',body: 'Body of post one',category: 'News',tags: ['news', 'events'],
    user: {name: 'John Doe',status: 'author'},date: Date()}
);
db.posts.find().limit(2).pretty();  // SELECT * FROM posts LIMIT 2;
db.posts.createIndex({ title: 1 })  // CREATE INDEX ON posts(_data->>'title');

如果不熟悉 MongoDB,可以参考同样适用于 FerretDB 的 MongoDB Shell CRUD 教程

下面的 mongosh 脚本可用于生成简单的示例负载:

cat > benchmark.js <<'EOF'
const coll = "testColl";
const numDocs = 1000;

for (let i = 0; i < numDocs; i++) {
  db.getCollection(coll).insertOne({ num: i, name: "MongoDB Benchmark Test" });
}
for (let i = 0; i < numDocs; i++) {
  db.getCollection(coll).find({ num: i });
}
for (let i = 0; i < numDocs; i++) {
  db.getCollection(coll).updateOne({ num: i }, { $set: { name: "Updated" } });
}
for (let i = 0; i < numDocs; i++) {
  db.getCollection(coll).deleteOne({ num: i });
}
EOF

mongosh 'mongodb://dbuser_meta:[email protected]:27017' benchmark.js

FerretDB 的支持命令列表已知差异说明了兼容边界;对基本使用场景而言,这些差异通常影响不大。

17 - 扩展

利用 PostgreSQL 扩展的协同超能力

Pigsty 允许您通过三样东西来利用 Postgres 扩展生态系统的协同超能力:目录、仓库和 pig。

扩展目录
    完整的 <span class="text-lg font-black text-emerald-500">437</span> 可用 PostgreSQL 扩展列表
软件仓库
    提供 PostgreSQL 扩展的 APT/YUM 仓库
包管理器
    PostgreSQL 和扩展缺失的包管理器
快速开始
    如何获取、安装、配置、管理这些扩展?

v3.7.0 扩展目录共收录 437 个 PostgreSQL 扩展,且 PostgreSQL 18 是默认版本。

下表是归档中保留的 PG13–17 兼容性快照,并未记录最终 PG18 分项统计;PG18 请以 v3.7.0 软件包别名和发布说明为准。

发行版 全部 PGDG PIGSTY CONTRIB 其他 缺失 PG17 PG16 PG15 PG14 PG13
EL 417 119 227 71 0 6 399 407 410 394 368
Debian 410 103 236 71 0 13 397 400 403 391 363

ecosystem

时间 地理 向量 搜索 分析 特性 语言 类型 工具 函数 管理 统计 安全 外部 兼容 数据

MIT ISC PostgreSQL BSD-0 BSD-2 BSD-3 Artistic Apache-2.0 MPL-2.0 GPL-2.0 GPL-3.0 LGPL-2.1 LGPL-3.0 AGPL-3.0 Timescale


使用方法

    使用包别名下载和安装扩展
下载
    从 PGDG / Pigsty 仓库下载扩展
安装
    安装 Postgres 扩展包
配置
    配置扩展并设置预加载
下载
    从 PGDG / Pigsty 仓库下载扩展
安装
    安装 Postgres 扩展包
配置
    配置扩展并设置预加载
创建
    在数据库中创建 Postgres 扩展
更新
    升级 Postgres 扩展
移除
    卸载 Postgres 扩展

索引

类别 扩展
时间 emaj periods pg_background pg_cron pg_later pg_task table_version temporal_tables timescaledb timescaledb_toolkit timeseries
地理 address_standardizer address_standardizer_data_us earthdistance geoip h3 h3_postgis mobilitydb ogr_fdw pg_geohash pg_polyline pgrouting pointcloud pointcloud_postgis postgis postgis_raster postgis_sfcgal postgis_tiger_geocoder postgis_topology q3c tzf
向量 pg4ml pg_similarity pg_summarize pg_tiktoken pgml smlar vchord vector vectorize vectorscale
搜索 fuzzystrmatch hunspell_cs_cz hunspell_de_de hunspell_en_us hunspell_fr hunspell_ne_np hunspell_nl_nl hunspell_nn_no hunspell_pt_pt hunspell_ru_ru hunspell_ru_ru_aot pg_bestmatch pg_bigm pg_search pg_tokenizer pg_trgm pgroonga pgroonga_database vchord_bm25 zhparser
分析 citus citus_columnar columnar duckdb_fdw pg_analytics pg_duckdb pg_fkpart pg_mooncake pg_parquet pg_partman pg_strom plproxy tablefunc
特性 age bloom hll hypopg imgsmlr index_advisor jsquery omni omni_auth omni_aws omni_cloudevents omni_containers omni_credentials omni_email omni_http omni_httpc omni_httpd omni_id omni_json omni_kube omni_ledger omni_manifest omni_mimetypes omni_os omni_polyfill omni_python omni_regex omni_rest omni_schema omni_seq omni_service omni_session omni_sql omni_sqlite omni_test omni_txn omni_types omni_var omni_vfs omni_vfs_types_v1 omni_web omni_worker omni_xml omni_yaml orioledb pg_cardano pg_graphql pg_hint_plan pg_incremental pg_ivm pg_jsonschema pgmq pgq plan_filter rdkit rum
语言 bool_plperl bool_plperlu dbt2 faker hstore_pllua hstore_plluau hstore_plperl hstore_plperlu hstore_plpython3u jsonb_plperl jsonb_plperlu jsonb_plpython3u ltree_plpython3u pg_tle pgtap pldbgapi pljava pllua plluau plperl plperlu plpgsql plpgsql_check plprofiler plprql plpython3u plr plsh pltcl pltclu plv8
类型 acl asn1oid chkpass citext collection country cube currency debversion emailaddr hashtypes hstore ip4r isn l10n_table_dependent_extension ltree md5hash numeral pg_duration pg_rational pg_rrule pg_sphere pg_xenophile pgfaceting pglite_fusion pgmp pgpdf prefix roaringbitmap seg semver timestamp9 uint uint128 unit uri xml2
工具 bzip cryptint data_historization ddl_historization envvar floatfile gzip hashlib http icu_ext pg_curl pg_extra_time pg_html5_email_address pg_net pg_protobuf pg_readme pg_readme_test_extension pg_render pg_smtp_client pgjq pgjwt pgpcre pgqr pgsql_tweaks pguecc schedoc shacrypt sparql url_encode xxhash zstd
函数 aggs_for_arrays aggs_for_vecs arraymath autoinc base36 base62 btree_gin btree_gist convert count_distinct ddsketch dict_int dict_xsyn extra_window_functions financial first_last_agg floatvec insert_username intagg intarray lower_quantile moddatetime omnisketch permuteseq pg_base58 pg_hashids pg_idkit pg_math pg_uuidv7 pgx_ulid quantile random refint sequential_uuids tcn tdigest topn tsm_system_rows tsm_system_time unaccent uuid-ossp vasco xicor
管理 adminpack amcheck basebackup_to_shell basic_archive ddlx fio lo old_snapshot pg_catcheck pg_cheat_funcs pg_checksums pg_cooldown pg_crash pg_dirtyread pg_drop_events pg_orphaned pg_permissions pg_prewarm pg_readonly pg_repack pg_savior pg_squeeze pg_surgery pg_upless pgagent pgautofailover pgcozy pgdd pgfincore pgpool_adm pgpool_recovery pgpool_regclass pre_prepare prioritize safeupdate table_log
统计 auto_explain bgw_replstatus explain_ui meta pageinspect pagevis pg_buffercache pg_freespacemap pg_logicalinspect pg_overexplain pg_proctab pg_profile pg_qualstats pg_relusage pg_show_plans pg_sqlog pg_stat_kcache pg_stat_monitor pg_stat_statements pg_store_plans pg_tracing pg_track_settings pg_visibility pg_wait_sampling pg_walinspect pgmeminfo pgnodemx pgrowlocks pgsentinel pgstattuple powa sslinfo system_stats toastinfo
安全 anon auth_delay credcheck logerrors login_hook noset passwordcheck passwordcheck_cracklib pg_auditor pg_auth_mon pg_jobmon pg_session_jwt pg_snakeoil pg_tde pgaudit pgauditlogtofile pgcrypto pgcryptokey pgextwlist pgsmcrypto pgsodium sepgsql set_user sslutils supabase_vault supautils
外部 aws_s3 db2_fdw dblink file_fdw firebird_fdw hdfs_fdw jdbc_fdw kafka_fdw log_fdw mongo_fdw multicorn mysql_fdw odbc_fdw oracle_fdw pgbouncer_fdw pgspider_ext postgres_fdw redis redis_fdw sqlite_fdw tds_fdw wrappers
兼容 babelfishpg_common babelfishpg_money babelfishpg_tds babelfishpg_tsql documentdb documentdb_core documentdb_distributed orafce pg_dbms_job pg_dbms_lock pg_dbms_metadata pg_statement_rollback pgmemcache pgtt session_variable spat
数据 db_migrator decoder_raw decoderbufs mimeo pg_bulkload pg_fact_loader pg_failover_slots pgactive pgl_ddl_deploy pglogical pglogical_origin pglogical_ticker pgoutput repmgr test_decoding wal2json wal2mongo

17.1 - 快速开始

安装、加载、创建、更新 PostgreSQL 扩展

Pigsty 为 14 个主流 Linux 发行版提供了无与伦比的 437 扩展。


概述

交付扩展需要 4 个步骤:下载安装配置创建

步骤 1

    [**下载**](#download-extension):要下载哪些扩展包

    ```yaml tab="config" title="定义要下载的扩展"
    repo_extra_packages: [ postgis, timescaledb, vector ]
    ```
    ```bash tab="apply" title="下载包"
    make repo
    ```

步骤 2

    [**安装**](#install-extension):要安装哪些扩展

    ```yaml tab="config"
    pg_extensions: [ postgis, pgvector, timescaledb ]
    ```
    ```bash tab="apply"
    ./pgsql.yml -t pg_ext     # 安装扩展
    ```

步骤 3

    [**加载**](#load-extension):要预加载哪些扩展

    ```yaml tab="config"
    pg_libs: 'timescaledb, pg_stat_statements, auto_explain'  # 将扩展添加到预加载库(并非所有扩展都需要此操作)
    ```
    ```bash tab="apply" title="编辑现有集群配置并重新加载"
    pg edit-config --force -p shared_preload_libraries='timescaledb, pg_stat_statements, auto_explain'
    ```

步骤 4

    [**创建**](#create-extension):在[数据库](/zh/docs/pgsql/db)中创建扩展

    ```yaml tab="config"
    pg_databases:
    - { name: meta ,extensions: [ postgis, timescaledb, vector ] }
    ```
    ```sql tab="apply" title="在现有数据库中创建扩展"
    CREATE EXTENSION postgis CASCADE;
    ```

快速开始

您可以在配置清单中描述扩展,Pigsty 将为您下载、安装、配置和启用扩展。 此示例使 postgispgvectortimescaledb 开箱即用:

all:
  children:
    pg-meta:
      hosts: {10.10.10.10: { pg_seq: 1, pg_role: primary }}
      vars:
        pg_cluster: pg-meta
        pg_databases: {name: meta, extensions: [ postgis, vector ]} # 创建(在数据库中)
        pg_extensions: [ postgis, pgvector ]                        # 安装(在集群中)
  vars:
    repo_extra_packages: [ postgis, timescaledb, vector ]           # 下载(全局)

当您初始化此 PG 集群时,这些扩展将在 pg-meta 集群中为您提供。

这里是一个更复杂的示例:启动 Postgres 并带有自托管 supabase 所需的扩展:

all:
  children:
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_databases:
          - name: postgres
            baseline: supabase.sql
            schemas: [ extensions ,auth ,realtime ,storage ,graphql_public ,supabase_functions ,_analytics ,_realtime ]
            extensions:                                 # 在 postgres 数据库中启用的扩展
              - { name: pgcrypto  ,schema: extensions } # 加密函数
              - { name: pg_net    ,schema: extensions } # 异步 HTTP
              - { name: pgjwt     ,schema: extensions } # PostgreSQL 的 JSON Web Token API
              - { name: uuid-ossp ,schema: extensions } # 生成通用唯一标识符 (UUIDs)
              - { name: pgsodium        }               # PostgreSQL 的现代密码学
              - { name: supabase_vault  }               # Supabase Vault 扩展
              - { name: pg_graphql      }               # GraphQL 支持
              - { name: pg_jsonschema   }               # JSON 模式验证
              - { name: wrappers        }               # 外部数据包装器集合
              - { name: http            }               # 数据库内网页检索
              - { name: pg_cron         }               # PostgreSQL 的作业调度器
              - { name: timescaledb     }               # 时间序列数据支持
              - { name: pg_tle          }               # PostgreSQL 的可信语言扩展
              - { name: vector          }               # 向量相似性搜索
              - { name: pgmq            }               # 轻量级消息队列
        # supabase 加载所需扩展
        pg_libs: 'timescaledb, plpgsql, plpgsql_check, pg_cron, pg_net, pg_stat_statements, auto_explain, pg_tle, plan_filter'
        pg_parameters:
          cron.database_name: postgres
          pgsodium.enable_event_trigger: off
  vars:
    pg_version: 17
    repo_extra_packages: [pg17-core ,pg17-time ,pg17-gis ,pg17-rag ,pg17-fts ,pg17-olap ,pg17-feat ,pg17-lang ,pg17-type ,pg17-util ,pg17-func ,pg17-admin ,pg17-stat ,pg17-sec ,pg17-fdw ,pg17-sim ,pg17-etl ]
    pg_extensions:                  [pg17-time ,pg17-gis ,pg17-rag ,pg17-fts ,pg17-feat ,pg17-lang ,pg17-type ,pg17-util ,pg17-func ,pg17-admin ,pg17-stat ,pg17-sec ,pg17-fdw ,pg17-sim ,pg17-etl ] #,pg17-olap]

下载并安装了 PG 17 的所有可用扩展,并加载和启用了所需的扩展。

17.2 - 软件包

扩展包和别名

管理扩展和包并不简单,这里有两个常见的扩展示例:

实体 示例 pgvector 示例 postgis
扩展 vector postgis, postgis_topology, postgis_raster,…
pgvector postgis
操作系统包 pgvector_17 postgresql-16-postgis-3
RPM/DEB pgvector_17_0.8.0-1PGDG.rhel8.x86_64.rpm postgresql-17-postgis-3_3.5.2+dfsg-1.pgdg22.04+1_amd64.deb

要以最小的努力安装正确的 RPM / DEB,我们需要使用抽象层:包别名。 因此您可以通过指定"标准化"名称(如 pgvectorpostgis)来安装这些扩展。 无需了解 PG 和操作系统版本、架构、扩展版本以及任何其他详细信息。

包别名 pkg 用于扩展下载和安装,但在数据库中 CREATE EXTENSION 时您必须使用扩展名称 ext(如 meta 数据库中的 vector)。 请注意,某些扩展需要显式预加载,如上述示例中的 timescaledb

此外,所有扩展都被分类为 16 个主要类别,我们也为整个扩展类别提供别名 这样您就可以批量下载和安装它们,例如:

将 17 替换为 16,15,14,13,...
repo_extra_packages: [ pg17-main ,pg17-core ,pg17-time ,pg17-gis ,pg17-rag ,pg17-fts ,pg17-olap ,pg17-feat ,pg17-lang ,pg17-type ,pg17-util ,pg17-func ,pg17-admin ,pg17-stat ,pg17-sec ,pg17-fdw ,pg17-sim ,pg17-etl]
pg_extensions: [pg17-time ,pg17-gis ,pg17-rag ,pg17-fts ,pg17-feat ,pg17-lang ,pg17-type ,pg17-util ,pg17-func ,pg17-admin ,pg17-stat ,pg17-sec ,pg17-fdw ,pg17-sim ,pg17-etl ] #,pg17-olap]

除了 olap 类别外,所有扩展都可以同时安装,在 olap 类别中,citushydra 冲突,pg_duckdbpg_mooncake 冲突。 所以您可以下载所有扩展,但要一次安装一个。

17.3 - 下载

下载 PostgreSQL 扩展

在 Pigsty 中,下载和安装扩展是两个独立的步骤。在 INFRA 模块安装期间,Pigsty 将所有必需的软件下载到本地机器上,并为整个部署创建本地 YUM/APT 仓库。

这种方法加速了安装过程,消除了冗余下载,移除了数据库节点访问互联网的需求,减少了网络流量,提高了交付可靠性,并确保了环境中版本的一致性——这些都是生产部署的最佳实践。

对于开发环境,直接从互联网仓库安装扩展也是可以接受的


快速开始

repo_packagesrepo_extra_packages 中定义的包会在 Pigsty 安装期间自动下载到您的本地仓库。

对于 PostgreSQL 相关的包(内核和扩展),通常将它们放在 repo_extra_packages 中,而让 repo_packages 保持其特定于操作系统的全局默认值。

repo_extra_packages 的默认值是 [pgsql-main],这是一个别名,代表当前活跃主版本的核心 PostgreSQL 和关键扩展。

repo_extra_packages: [ pgsql-main ]  # 当前 pg 主版本 18 的主要包(内核 + 3 个扩展)

要添加特定扩展,只需将 Pigsty 扩展包名称(pkg添加到此参数中。Pigsty 会自动为您的活跃 PG 版本和当前操作系统发行版下载适当的包。

repo_extra_packages: [ pgsql-main, documentdb, citus, postgis, pgvector, pg_cron, rum ]

要下载当前 PG 版本的所有可用扩展,添加所有 16 个扩展类别别名(如 rich 配置模板中所示):

repo_extra_packages: [ pgsql-main ,pgsql-time ,pgsql-gis ,pgsql-rag ,pgsql-fts ,pgsql-olap ,pgsql-feat ,pgsql-lang ,pgsql-type ,pgsql-util ,pgsql-func ,pgsql-admin ,pgsql-stat ,pgsql-sec ,pgsql-fdw ,pgsql-sim ,pgsql-etl]

或者,使用特定版本的别名来下载多个 PostgreSQL 版本的扩展:

repo_extra_packages: [
    pg18-core,pg18-time,pg18-gis,pg18-rag,pg18-fts,pg18-olap,pg18-feat,pg18-lang,pg18-type,pg18-util,pg18-func,pg18-admin,pg18-stat,pg18-sec,pg18-fdw,pg18-sim,pg18-etl,
    pg17-core,pg17-time,pg17-gis,pg17-rag,pg17-fts,pg17-olap,pg17-feat,pg17-lang,pg17-type,pg17-util,pg17-func,pg17-admin,pg17-stat,pg17-sec,pg17-fdw,pg17-sim,pg17-etl,
    pg16-core,pg16-time,pg16-gis,pg16-rag,pg16-fts,pg16-olap,pg16-feat,pg16-lang,pg16-type,pg16-util,pg16-func,pg16-admin,pg16-stat,pg16-sec,pg16-fdw,pg16-sim,pg16-etl,
    pg15-core,pg15-time,pg15-gis,pg15-rag,pg15-fts,pg15-olap,pg15-feat,pg15-lang,pg15-type,pg15-util,pg15-func,pg15-admin,pg15-stat,pg15-sec,pg15-fdw,pg15-sim,pg15-etl,
    pg14-core,pg14-time,pg14-gis,pg14-rag,pg14-fts,pg14-olap,pg14-feat,pg14-lang,pg14-type,pg14-util,pg14-func,pg14-admin,pg14-stat,pg14-sec,pg14-fdw,pg14-sim,pg14-etl,
    pg13-core,pg13-time,pg13-gis,pg13-rag,pg13-fts,pg13-olap,pg13-feat,pg13-lang,pg13-type,pg13-util,pg13-func,pg13-admin,pg13-stat,pg13-sec,pg13-fdw,pg13-sim,pg13-etl,
]

要向本地仓库添加新扩展,修改上述参数并运行:

./infra.yml -t repo_build   # 重新下载并重建本地仓库

要在您环境中的所有其他节点上刷新仓库元数据,运行:

./node.yml  -t node_repo    # [可选] apt update / yum makecache

别名映射

PostgreSQL 拥有丰富的开源生态系统,在不同系统和架构中有众多包。

Pigsty 提供了一个抽象层,将 PostgreSQL 包分类为"别名",隐藏了系统、架构和 PG 版本之间的差异。

快速开始部分,我们使用了 pgsql-mainpgsql-core 等别名。这些别名根据您的系统和架构转换为特定的包名称。对于 EL 系统,pgsql-main 扩展为 postgresql$v* 内核包以及 pgvector_$v*pg_repack_$v*wal2json_$v* 扩展包。

pgsql-main:   "postgresql$v* pg_repack_$v* wal2json_$v* pgvector_$v*"

$v 占位符被 pg_version 值(默认:18)替换以指向正确的版本。* 通配符扩展以包括所有包变体(例如 server、libs、contrib、devel)。Pigsty 自动处理这些细节。

可用包和别名的完整列表在 roles/node_id/vars/<os_package>.yml 中。以下是在所有支持的系统中可用的常用别名:

postgresql:   "postgresql$v*"
pgsql-main:   "postgresql$v* pg_repack_$v* wal2json_$v* pgvector_$v*"
pgsql-core:   "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl postgresql$v-test postgresql$v-devel postgresql$v-llvmjit"
pgsql-simple: "postgresql$v postgresql$v-server postgresql$v-libs postgresql$v-contrib postgresql$v-plperl postgresql$v-plpython3 postgresql$v-pltcl"
pgsql-client: "postgresql$v"
pgsql-server: "postgresql$v-server postgresql$v-libs postgresql$v-contrib"
pgsql-devel:  "postgresql$v-devel"
pgsql-basic:  "pg_repack_$v* wal2json_$v* pgvector_$v*"

pgsql-time:   "timescaledb-tsl_$v* timescaledb-toolkit_$v pg_timeseries_$v periods_$v* temporal_tables_$v* e-maj_$v table_version_$v pg_cron_$v* pg_task_$v* pg_later_$v pg_background_$v*"
pgsql-gis:    "postgis35_$v* pgrouting_$v* pointcloud_$v* h3-pg_$v* q3c_$v* ogr_fdw_$v* geoip_$v pg_polyline_$v pg_geohash_$v*"
pgsql-rag:    "pgvector_$v* vchord_$v pgvectorscale_$v pg_vectorize_$v pg_similarity_$v* smlar_$v* pg_summarize_$v pg_tiktoken_$v pg4ml_$v"
pgsql-fts:    "pg_search_$v pgroonga_$v* pg_bigm_$v* zhparser_$v* pg_bestmatch_$v vchord_bm25_$v hunspell_cs_cz_$v hunspell_de_de_$v hunspell_en_us_$v hunspell_fr_$v hunspell_ne_np_$v hunspell_nl_nl_$v hunspell_nn_no_$v hunspell_ru_ru_$v hunspell_ru_ru_aot_$v"
pgsql-olap:   "citus_$v* pg_analytics_$v pg_duckdb_$v* pg_mooncake_$v* duckdb_fdw_$v* pg_parquet_$v pg_fkpart_$v pg_partman_$v* plproxy_$v*" #hydra_$v* #pg_strom_$v*
pgsql-feat:   "hll_$v* rum_$v pg_graphql_$v pg_jsonschema_$v jsquery_$v* pg_hint_plan_$v* hypopg_$v* index_advisor_$v pg_plan_filter_$v* imgsmlr_$v* pg_ivm_$v* pg_incremental_$v* pgmq_$v pgq_$v* pg_cardano_$v omnigres_$v" #apache-age_$v*
pgsql-lang:   "pg_tle_$v* plv8_$v* pllua_$v* pldebugger_$v* plpgsql_check_$v* plprofiler_$v* plsh_$v* pljava_$v*" #plprql_$v #plr_$v* #pgtap_$v* #postgresql_faker_$v* #dbt2-pgsql-extensions*
pgsql-type:   "prefix_$v* semver_$v* postgresql-unit_$v* pgpdf_$v* pglite_fusion_$v md5hash_$v* asn1oid_$v* pg_roaringbitmap_$v* pgfaceting_$v pgsphere_$v* pg_country_$v* pg_xenophile_$v pg_currency_$v* pgcollection_$v* pgmp_$v* numeral_$v* pg_rational_$v* pguint_$v* pg_uint128_$v* hashtypes_$v* ip4r_$v* pg_duration_$v* pg_uri_$v* pg_emailaddr_$v* acl_$v* timestamp9_$v* chkpass_$v*"
pgsql-util:   "pgsql_gzip_$v* pg_bzip_$v* pg_zstd_$v* pgsql_http_$v* pg_net_$v* pg_curl_$v* pgjq_$v* pgjwt_$v pg_smtp_client_$v pg_html5_email_address_$v url_encode_$v* pgsql_tweaks_$v pg_extra_time_$v pgpcre_$v icu_ext_$v* pgqr_$v* pg_protobuf_$v pg_envvar_$v* floatfile_$v* pg_readme_$v ddl_historization_$v data_historization_$v pg_schedoc_$v pg_hashlib_$v pg_xxhash_$v* postgres_shacrypt_$v* cryptint_$v* pg_ecdsa_$v* pgsparql_$v"
pgsql-func:   "pg_idkit_$v pg_uuidv7_$v* permuteseq_$v* pg_hashids_$v* sequential_uuids_$v topn_$v* quantile_$v* lower_quantile_$v* count_distinct_$v* omnisketch_$v* ddsketch_$v* vasco_$v* pgxicor_$v* tdigest_$v* first_last_agg_$v extra_window_functions_$v* floatvec_$v* aggs_for_vecs_$v* aggs_for_arrays_$v* pg_arraymath_$v* pg_math_$v* pg_random_$v* pg_base36_$v* pg_base62_$v* pg_base58_$v pg_financial_$v*"
pgsql-admin:  "pg_repack_$v* pg_squeeze_$v* pg_dirtyread_$v* pgfincore_$v* pg_cooldown_$v* ddlx_$v pg_prioritize_$v* pg_readonly_$v* pg_upless_$v pg_permissions_$v pg_catcheck_$v* preprepare_$v* pgcozy_$v pg_orphaned_$v* pg_crash_$v* pg_cheat_funcs_$v* pg_fio_$v pg_savior_$v* safeupdate_$v* pg_drop_events_$v table_log_$v" #pg_checksums_$v* #pg_auto_failover_$v* #pgagent_$v* #pgpool-II-pgsql-extensions
pgsql-stat:   "pg_profile_$v* pg_tracing_$v* pg_show_plans_$v* pg_stat_kcache_$v* pg_stat_monitor_$v* pg_qualstats_$v* pg_store_plans_$v* pg_track_settings_$v pg_wait_sampling_$v* system_stats_$v* pg_meta_$v pgnodemx_$v pg_sqlog_$v bgw_replstatus_$v* pgmeminfo_$v* toastinfo_$v* pg_explain_ui_$v pg_relusage_$v pagevis_$v powa_$v*"
pgsql-sec:    "passwordcheck_cracklib_$v* supautils_$v* pgsodium_$v* vault_$v* pg_session_jwt_$v pg_anon_$v pgsmcrypto_$v pgaudit_$v* pgauditlogtofile_$v* pg_auth_mon_$v* credcheck_$v* pgcryptokey_$v pg_jobmon_$v logerrors_$v* login_hook_$v* set_user_$v* pg_snakeoil_$v* pgextwlist_$v* pg_auditor_$v sslutils_$v* noset_$v*" #pg_tde_$v*
pgsql-fdw:    "wrappers_$v multicorn2_$v* odbc_fdw_$v* mysql_fdw_$v* tds_fdw_$v* sqlite_fdw_$v* pgbouncer_fdw_$v redis_fdw_$v* pg_redis_pubsub_$v* hdfs_fdw_$v* firebird_fdw_$v aws_s3_$v log_fdw_$v*" #jdbc_fdw_$v* #oracle_fdw_$v* #db2_fdw_$v* #mongo_fdw_$v* #kafka_fdw_$v
pgsql-sim:    "documentdb_$v* orafce_$v pgtt_$v* session_variable_$v* pg_statement_rollback_$v* pg_dbms_metadata_$v pg_dbms_lock_$v pgmemcache_$v*" #pg_dbms_job_$v #wiltondb
pgsql-etl:    "pglogical_$v* pglogical_ticker_$v* pgl_ddl_deploy_$v* pg_failover_slots_$v* db_migrator_$v wal2json_$v* postgres-decoderbufs_$v* decoder_raw_$v* mimeo_$v pg_fact_loader_$v* pg_bulkload_$v*" #wal2mongo_$v* #repmgr_$v*

使用这些别名时,$v 占位符会被来自 pg_version(默认:18)的 PostgreSQL 主版本号替换。

要为不同的 PostgreSQL 版本下载包,可以:

  • 更改 pg_version 参数,或
  • 通过将 pgsql- 前缀替换为 pg18-pg17-pg16- 等来使用特定版本的别名。

并非所有扩展在所有系统上都可用。某些扩展在别名中被注释掉,因为它们:

  • 在特定系统上不可用
  • 具有大量依赖项(如 pl/R
  • 依赖于商业软件(如 oracle_fdw
  • 在最新的 PG 18 中不可用但在早期版本中可用

如果需要,您仍然可以手动添加这些扩展。

17.4 - 安装

安装 PostgreSQL 扩展

Pigsty 依托标准的操作系统包管理器(yum/apt)来安装 PostgreSQL 扩展。


快速开始

在安装扩展时,Pigsty 使用与下载部分相同的别名映射

为集群 pg-meta 安装在 pg_extensions 参数中明确指定的所有扩展:

all:
  children:
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_extensions: # 要在此集群上安装的扩展
          - timescaledb timescaledb_toolkit pg_timeseries periods temporal_tables emaj table_version pg_cron pg_task pg_later pg_background
          - postgis pgrouting pointcloud pg_h3 q3c ogr_fdw geoip pg_polyline pg_geohash #mobilitydb
          - pgvector vchord pgvectorscale pg_vectorize pg_similarity smlar pg_summarize pg_tiktoken pg4ml #pgml
          - pg_search pgroonga pg_bigm zhparser pg_bestmatch vchord_bm25 hunspell
          - citus hydra pg_analytics pg_duckdb pg_mooncake duckdb_fdw pg_parquet pg_fkpart pg_partman plproxy #pg_strom
          - age hll rum pg_graphql pg_jsonschema jsquery pg_hint_plan hypopg index_advisor pg_plan_filter imgsmlr pg_ivm pg_incremental pgmq pgq pg_cardano omnigres #rdkit
          - pg_tle plv8 pllua plprql pldebugger plpgsql_check plprofiler plsh pljava #plr #pgtap #faker #dbt2
          - pg_prefix pg_semver pgunit pgpdf pglite_fusion md5hash asn1oid roaringbitmap pgfaceting pgsphere pg_country pg_xenophile pg_currency pg_collection pgmp numeral pg_rational pguint pg_uint128 hashtypes ip4r pg_uri pgemailaddr pg_acl timestamp9 chkpass #pg_duration #debversion #pg_rrule
          - pg_gzip pg_bzip pg_zstd pg_http pg_net pg_curl pgjq pgjwt pg_smtp_client pg_html5_email_address url_encode pgsql_tweaks pg_extra_time pgpcre icu_ext pgqr pg_protobuf envvar floatfile pg_readme ddl_historization data_historization pg_schedoc pg_hashlib pg_xxhash shacrypt cryptint pg_ecdsa pgsparql
          - pg_idkit pg_uuidv7 permuteseq pg_hashids sequential_uuids topn quantile lower_quantile count_distinct omnisketch ddsketch vasco pgxicor tdigest first_last_agg extra_window_functions floatvec aggs_for_vecs aggs_for_arrays pg_arraymath pg_math pg_random pg_base36 pg_base62 pg_base58 pg_financial
          - pg_repack pg_squeeze pg_dirtyread pgfincore pg_cooldown pg_ddlx pg_prioritize pg_checksums pg_readonly pg_upless pg_permissions pgautofailover pg_catcheck preprepare pgcozy pg_orphaned pg_crash pg_cheat_funcs pg_fio pg_savior safeupdate pg_drop_events table_log #pgagent #pgpool
          - pg_profile pg_tracing pg_show_plans pg_stat_kcache pg_stat_monitor pg_qualstats pg_store_plans pg_track_settings pg_wait_sampling system_stats pg_meta pgnodemx pg_sqlog bgw_replstatus pgmeminfo toastinfo pg_explain_ui pg_relusage pagevis powa
          - passwordcheck supautils pgsodium pg_vault pg_session_jwt pg_anon pg_tde pgsmcrypto pgaudit pgauditlogtofile pg_auth_mon credcheck pgcryptokey pg_jobmon logerrors login_hook set_user pg_snakeoil pgextwlist pg_auditor sslutils pg_noset
          - wrappers multicorn odbc_fdw jdbc_fdw mysql_fdw tds_fdw sqlite_fdw pgbouncer_fdw mongo_fdw redis_fdw pg_redis_pubsub kafka_fdw hdfs_fdw firebird_fdw aws_s3 log_fdw #oracle_fdw #db2_fdw
          - documentdb orafce pgtt session_variable pg_statement_rollback pg_dbms_metadata pg_dbms_lock pgmemcache #pg_dbms_job #wiltondb
          - pglogical pglogical_ticker pgl_ddl_deploy pg_failover_slots db_migrator wal2json wal2mongo decoderbufs decoder_raw mimeo pg_fact_loader pg_bulkload #repmgr

或者通过类别别名全局安装所有扩展:

all:
  vars:
    pg_version: 18   # v3.7 的默认版本,因此 pgsql-main 等同于 pg18-main
    pg_extensions: [ pgsql-main ,pgsql-time ,pgsql-gis ,pgsql-rag ,pgsql-fts ,pgsql-olap ,pgsql-feat ,pgsql-lang ,pgsql-type ,pgsql-util ,pgsql-func ,pgsql-admin ,pgsql-stat ,pgsql-sec ,pgsql-fdw ,pgsql-sim ,pgsql-etl]

您也可以在这些别名中明确指定 PG 主版本:

all:
  vars:

    pg_extensions: [pg17-time ,pg17-gis ,pg17-rag ,pg17-fts ,pg17-feat ,pg17-lang ,pg17-type ,pg17-util ,pg17-func ,pg17-admin ,pg17-stat ,pg17-sec ,pg17-fdw ,pg17-sim ,pg17-etl ] #,pg17-olap]

同时安装所有扩展是可行的(除了在 olap 类别中的两个冲突)但不推荐。只需在 pg_extensions 参数中明确指定您需要的扩展。


配置

在 PGSQL 集群初始化期间,Pigsty 将自动安装在 pg_packagespg_extensions 中指定的包(和别名)。

这两个参数都可以用来安装 PostgreSQL 相关的包。通常,pg_packages 用于全局指定应在环境中所有 PostgreSQL 集群上安装的包:如 PostgreSQL 内核、高可用代理(如 Patroni)、连接池(pgBouncer)、监控(pgExporter)等。

默认情况下,Pigsty 还在这里指定了 3 个重要扩展:pgvectorpg_repackwal2json,分别用于向量搜索、膨胀管理和 CDC 变更提取。

同时,pg_extensions 通常用于为特定集群指定扩展。默认值是一个空列表,表示默认不会安装其他扩展。

pg_packages:                      # 要安装的 pg 包,可以使用别名,状态=present
  - postgresql
  - wal2json pg_repack pgvector
  - patroni pgbouncer pgbackrest pg_exporter pgbadger vip-manager
pg_extensions: []                 # 要安装的 pg 扩展,可以使用别名,状态=latest

一个重要的区别:通过 pg_packages 安装的包只确保存在,而通过 pg_extensions 安装的包会自动升级到最新可用版本。

当使用本地软件仓库时,这个区别并不重要。但是,当使用上游互联网仓库时,请仔细考虑这一点,并将您不希望自动升级的扩展移至 pg_packages


安装

pg_extensions(和 pg_packages)中预定义的扩展将在集群置备期间安装。

要在已置备的 PostgreSQL 集群上安装新扩展:

首先,将扩展添加到 pg_extensions,然后执行 playbook 子任务:

./pgsql.yml -t pg_extension  # 安装在 pg_extensions 中指定的扩展

注意,在 pg_extension 任务中指定的扩展插件默认将升级到您当前环境中的最新可用版本。


仓库

要安装扩展,您需要确保满足以下条件之一:

  • 本地仓库:您已配置使用 Pigsty 的本地仓库,并且扩展已经下载到本地仓库。
  • 在线仓库:您已在目标节点上直接配置了上游互联网仓库,并且这些节点上有互联网访问。

对于生产环境,我们建议使用 Pigsty 的本地软件仓库来统一管理和安装扩展:首先将扩展下载到本地仓库,然后从那里安装它们。 这确保了您环境中扩展版本的一致性,并防止数据库节点直接访问互联网。从本地仓库安装时您无需做任何事情,只需确保它们已下载到本地仓库。

对于开发环境,您可以选择直接使用上游互联网仓库以便于操作。使用以下命令在目标集群上添加互联网仓库并直接安装扩展:

./node.yml  -l <cls> -t node_repo -e node_repo_modules=local,node,pgsql    # 在目标节点上启用互联网仓库
./pgsql.yml -l <cls> -t pg_extension                                        # 使用本地+互联网上游仓库安装扩展

包别名

在安装扩展时,用户可以使用扩展别名来指定扩展。

别名将被转换为当前活跃的 PG 主版本和操作系统环境。

并通过别名转换机制转换为相应的 RPM/DEB 包名称。


注意事项

  • 有两个已知冲突:
  • pgaudit 在 el 系统的 pg 15- 版本中有不同的命名模式:pg16+ = pgaudit,pg15=pgaudit17,pg14=pgaudit16,pg13=pgaudit15,pg12=pgaudit14
  • postgis 在 el 包名中有自己的版本:默认为 postgis35,遗留 el7 为 postgis33

17.5 - 配置

预加载扩展并配置扩展参数

虽然大多数用 SQL 编写的 PostgreSQL 扩展可以使用 CREATE EXTENSION 直接启用,但一些使用特殊 postgres 钩子的扩展在使用前需要额外的步骤来预加载它们。


预加载

大多数扩展都有一个或多个对应的动态库(.so.dylib.dll),其中一些在使用前需要预加载。 尝试在没有正确预加载的情况下 CREATE 这些扩展将导致错误。 错误配置的预加载库可能导致数据库重启/启动失败。

一些扩展可以在没有预加载的情况下部分工作,这意味着扩展功能的一部分可以直接使用,其余功能在预加载后可用。

要预加载扩展,将其添加到 shared_preload_libraries 并重启数据库服务器。 扩展目录 提供了需要动态预加载的扩展的完整列表。


配置

要在新 postgres 集群上配置预加载,可以使用 pg_libs 参数。 它将在 postgres 集群引导期间填充到 shared_preload_libraries 参数中。

示例:设置 Supabase 扩展预加载

此示例展示如何使用 pg_libs 参数指定预加载的扩展。

all:
  children:
pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_libs: 'timescaledb, plpgsql, plpgsql_check, pg_cron, pg_net, pg_stat_statements, auto_explain, pg_tle, plan_filter'

shared_preload_libraries 是一个以逗号分隔的扩展列表。

请注意,这仅在集群创建之前有效。之后, 您必须配置集群来更改现有集群上的 shared_preload_libraries 参数。(使用 patronictlALTER SYSTEM 等…)

将 timescaledb 添加到 shared_preload_libraries
pg edit-config pg-meta --force -p shared_preload_libraries='timescaledb, pg_stat_statements, auto_explain'
pg restart pg-meta    # 重启以应用更改

如果您想手动配置预加载,您可以自己更改 postgresql.conf


默认值

pg_libs 的默认值是 pg_stat_statements, auto_explain, 它默认预加载这两个 Contrib 扩展,这两个扩展提供基本的可观测性:


注意事项

预加载库是逐个加载的,因此 shared_preload_libraries 中扩展的顺序很重要, 以下是一些需要遵循的已知规则:

  • 对于 STAT 扩展,在 pg_stat_statements 之后添加它们以确保使用相同的 query_id。
  • timescaledbcitus 应该放在 shared_preload_libraries开头
  • 如果您同时使用 citustimescaledb,请将 citus 放在 timescaledb 之前。
  • 对于 documentdb,使用 pg_documentdbpg_documentdb_core 作为库名称。
  • pg_search 在 PostgreSQL 17 及更高版本中不需要预加载,但早期版本需要。

参数

一些扩展有可配置的参数,您可以在不同的地方管理它们。

有关详细信息,请查阅每个扩展的官方文档。

17.6 - 创建

创建和启用 PostgreSQL 扩展

快速开始

您可以使用 CREATE EXTENSION 语句启用(创建)扩展:

CREATE EXTENSION vector; -- 无需显式加载
CREATE EXTENSION timescaledb; -- 需要显式加载

扩展需要首先安装,一些扩展还需要在使用前进行预加载

一些扩展依赖于其他扩展。 在这种情况下,您可以先安装依赖项 或使用 CASCADE 子句一次安装所有依赖项。

CREATE EXTENSION documentdb CASCADE; -- 创建 documentdb 扩展及其所有依赖项

您也可以使用 Pigsty 配置扩展,它会自动为您创建扩展。


配置

扩展(数据库逻辑对象)在逻辑上是 PostgreSQL 数据库 的一部分。 在 Pigsty 中,您可以使用 pg_databases 参数指定在数据库中创建哪些扩展。

pg_databases:
  - { name: meta ,extensions: [ vector, postgis, timescaledb ] }

但您可以使用 object 格式显式指定扩展详细信息,比如在特定模式中创建它们。 或安装特定版本。这里是一个完整的示例(自托管 supabase):

pg_databases:
  - name: postgres
    baseline: supabase.sql
    schemas: [ extensions ,auth ,realtime ,storage ,graphql_public ,supabase_functions ,_analytics ,_realtime ]
    extensions:                                 # 在 postgres 数据库中启用的扩展
      - { name: pgcrypto  ,schema: extensions } # 加密函数
      - { name: pg_net    ,schema: extensions } # 异步 HTTP
      - { name: pgjwt     ,schema: extensions } # postgres 的 json web token API
      - { name: uuid-ossp ,schema: extensions } # 生成通用唯一标识符 (UUID)
      - { name: pgsodium        }               # pgsodium 是 Postgres 的现代密码学库
      - { name: supabase_vault  }               # Supabase Vault 扩展
      - { name: pg_graphql      }               # pg_graphql:GraphQL 支持
      - { name: pg_jsonschema   }               # pg_jsonschema:验证 json schema
      - { name: wrappers        }               # wrappers:FDW 集合
      - { name: http            }               # http:允许在数据库内检索网页
      - { name: pg_cron         }               # pg_cron:PostgreSQL 的作业调度器
      - { name: timescaledb     }               # timescaledb:为时间序列数据启用可扩展插入和复杂查询
      - { name: pg_tle          }               # pg_tle:PostgreSQL 的受信任语言扩展
      - { name: vector          }               # pgvector:向量相似性搜索
      - { name: pgmq            }               # pgmq:类似 AWS SQS 和 RSMQ 的轻量级消息队列

定义扩展

extensions 字段是要在数据库中创建的扩展(名称或对象)列表。 它将在 dbsu 的 search_path 中的第一个模式下创建(通常是 public 模式)。

这里,数据库对象中的 extensions 是一个列表,其中每个元素可以是:

  • 表示扩展名称的简单字符串,如 vector
  • 或者,可以使用包含以下字段的字典:
    • name:扩展名称,必需,注意它可能与扩展包名称不同。
    • schema:安装扩展的模式,可选,默认为当前 dbsu search_path 中的第一个模式,通常是默认的 public
    • version:指定扩展版本,可选,默认为最新版本,很少使用。

如果数据库尚不存在,这里定义的扩展将在通过 Pigsty 创建集群创建数据库时自动创建。

重新创建具有非平凡基线模式的数据库可能很危险(如果您在那里放置一些 DROP) 因此,对于现有集群/数据库,建议使用您自己的模式迁移工具来管理扩展。(pgadmin、psql、bytebase、flyway、sqlitch…) 但将它们列在配置清单中用于记录保存目的是有帮助的。(这样如果您想分叉这个集群,它包含这些扩展)


默认扩展

Pigsty 默认创建一些内置扩展和一个特殊的 pg_repack

这些扩展由 pg_default_extensions 定义,默认在 template1 数据库和 postgres 数据库中创建。 新创建的数据库将从 template1 继承这些扩展,因此您无需再次创建它们。

pg_default_extensions:
  - { name: pg_stat_statements ,schema: monitor }
  - { name: pgstattuple        ,schema: monitor }
  - { name: pg_buffercache     ,schema: monitor }
  - { name: pageinspect        ,schema: monitor }
  - { name: pg_prewarm         ,schema: monitor }
  - { name: pg_visibility      ,schema: monitor }
  - { name: pg_freespacemap    ,schema: monitor }
  - { name: postgres_fdw       ,schema: public  }
  - { name: file_fdw           ,schema: public  }
  - { name: btree_gist         ,schema: public  }
  - { name: btree_gin          ,schema: public  }
  - { name: pg_trgm            ,schema: public  }
  - { name: intagg             ,schema: public  }
  - { name: intarray           ,schema: public  }
  - { name: pg_repack } # <-- 默认创建的唯一第三方扩展

pg_default_schemas 定义的一个额外默认模式 monitor 也默认创建。 它用于包含监控相关的扩展、表、函数和视图。

在 Pigsty 中默认可用的有三个第三方扩展:

扩展 作用 位置
pg_repack 在线膨胀控制工具 pg_default_extensions
wal2json JSON 格式的变更数据捕获 无 DDL 扩展,安装意味着可用
vector 向量数据类型和索引 pg_databases 中作为示例

pg_repack 扩展是在线维护膨胀表的重要工具。

vector 是用于 RAG 的非常流行的扩展, 它默认安装(在 pgsql-main 别名中)并在大多数配置模板的占位符 meta 数据库中创建。

wal2json 是用于变更数据捕获(CDC)的另一个重要扩展。它默认安装,但它是一个无 DDL 的扩展, 因此您无需显式 CREATE 它。


无 DDL 扩展

无 DDL 扩展不需要 CREATE EXTENSION 命令即可工作

PostgreSQL 扩展通常由三部分组成:必需的控制文件、可选的 SQL 文件和可选的库。 如果扩展没有 SQL 文件,则不需要 CREATE EXTENSION 命令。

组件 描述 必需
控制文件 关键元数据,名称、依赖项、模式、版本… 必需
SQL 文件 SQL DDL 语句、类型、函数等… 可选
库文件 二进制共享库(.so.dylib.dll 可选

由于 SQL / LIB 文件是可选的,有四种可能的扩展类型组合:

LOAD / DDL 需要 CREATE EXTENSION 不需要 CREATE EXTENSION
需要 LOAD 使用钩子的扩展 无头扩展
不需要 LOAD 不使用钩子的扩展 逻辑解码输出插件

17.7 - 更新

如何将 PostgreSQL 扩展更新到新版本

要更新现有扩展,您需要首先使用操作系统的包管理器更新 RPM/DEB 包, 然后在 PostgreSQL 中使用 ALTER EXTENSION ... UPDATE 将扩展更改为新版本。

您可以使用以下命令升级扩展包

pig ext update extname...
yum upgrade extname...
apt upgrade extname...
./pgsql.yml -t pg_ext   # -l cls

pg_extensions 中列出的所有扩展将在 pgsql.yml playbook 执行期间升级。


升级扩展

pg_extensions 中列出的扩展(包别名)将通过 pgsql.ymlpg_ext 子任务升级:

~/pigsty
./pgsql.yml -t pg_ext

此 playbook 将自动安装您当前环境中可用的最新版本的扩展 RPM/DEB 包。 (从构建的本地仓库或直接通过互联网)。 您也可以直接使用 Linux 系统的 yum/apt upgrade 命令升级扩展,但您需要指定完整的包名称:

yum upgrade extname...
apt upgrade extname...

Pigsty 的 pig CLI 也可以帮助您完成此操作,无需指定完整包名称的负担:

pig ext update ext|pkg

更改扩展

执行 ALTER EXTENSION ... UPDATE SQL 命令将扩展更新到新版本:

ALTER EXTENSION name UPDATE [ TO new_version ]

如果省略 TO new_version 子句,扩展将更新到可用的最新版本。

17.8 - 移除

如何移除 PostgreSQL 扩展

移除扩展

要卸载扩展,您通常需要运行 DROP EXTENSION SQL 语句:

DROP EXTENSION "<extname>";

如果其他扩展或数据库对象依赖于此扩展,您需要先移除这些依赖项才能卸载扩展。 或者使用 CASCADE 选项一次性移除所有依赖:

DROP EXTENSION "<extname>" CASCADE;
Warning

CASCADE 选项将删除所有依赖于此扩展的对象,
包括数据库对象、函数、视图等。请谨慎使用!

某些扩展没有 DDL,这些扩展不需要 DROP EXTENSION 语句来卸载。 相反,您可以简单地从 shared_preload_libraries(如果已配置)中移除扩展并卸载包。 请参考无 DDL 扩展部分了解更多详细信息。


移除加载

如果您使用的扩展需要动态加载(修改 shared_preload_libraries 参数),您需要首先重新配置 shared_preload_libraries 参数。

shared_preload_libraries 中移除扩展名称,并重启数据库集群以使更改生效。

对于需要动态加载的扩展,请参考需要加载的扩展列表。


卸载包

在从集群中的所有数据库中移除扩展(逻辑对象)后,您可以安全地卸载扩展的软件包。Ansible 命令可以帮助您方便地执行此操作:

ansible <cls> -m package -a "name=<extname> state=absent"

您也可以使用 pig,或直接使用 apt/yum 命令来卸载。

如果您不知道扩展包名称,可以参考扩展列表或查看在 roles/node_id/vars 中定义的扩展包名称映射。