这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

概念

理解 Pigsty 的核心概念、架构设计与设计理念,掌握高可用、备份恢复、安全合规等关键能力。

Pigsty 是一个可移植、可扩展的开源 PostgreSQL 发行版,用于在本地环境中构建生产级数据库服务,方便进行声明式配置和自动化。它拥有庞大的生态系统,提供了一整套工具、脚本和最佳实践,让 PostgreSQL 真正达到企业级 RDS 的服务水准。

Pigsty 名字源自 PostgreSQL In Great STYle,也可理解为 Postgres, Infras, Graphics, Service, Toolbox, it’s all Yours —— 属于您的 PostgreSQL 图形化自建工具箱。您可以在 GitHub 上找到源代码,访问 官方文档 了解更多信息,或在 在线演示 中体验 Web 界面

pigsty-banner


为什么需要 Pigsty,它能做什么?

PostgreSQL 是一个足够完美的数据库内核,但它需要更多工具与系统的配合才能成为一个足够好的数据库服务。在生产环境中,您需要管理数据库的方方面面:高可用、备份恢复、监控告警、访问控制、参数调优、扩展安装、连接池化、负载均衡……

如果这些复杂的运维工作都能自动化处理,是不是会更容易一些?这正是 Pigsty 诞生的原因。

Pigsty 为您提供:

  • 开箱即用的 PostgreSQL 发行版

    Pigsty 整合了 PostgreSQL 生态中的 531 个扩展插件,提供开箱即用的分布式、时序、地理、空间、图、向量、搜索等多模态数据库能力。从内核到 RDS 发行版,在 EL/Debian/Ubuntu 下提供 14 - 18 版本的生产级数据库服务。

  • 故障自愈的高可用架构

    基于 Patroni、Etcd 和 HAProxy 打造的 高可用架构,让硬件故障自动切换,流量无缝衔接。主库故障恢复时间 RTO < 45s,数据恢复点 RPO ≈ 0。您可以在无需应用配合的情况下滚动维护升级整个集群。

  • 完整的时间点恢复能力

    基于 pgBackRest 与可选的 MinIO 集群,提供开箱即用的 PITR 时间点恢复 能力。让您可以回到恢复窗口内的任意时间点,为软件缺陷与人为删库兜底。

  • 灵活的服务接入与流量管理

    通过 HAProxy、Pgbouncer、VIP 提供灵活的 服务接入 模式,实现读写分离、连接池化、自动路由。交付稳定可靠、自动路由、事务池化的高性能数据库服务。

  • 惊艳的可观测性

    基于 Victoria 与 Grafana 的可观测性技术栈,提供无与伦比的 监控最佳实践。超过三千类监控指标描述系统的方方面面,从全局大盘到单个对象的增删改查都能一览无余。

  • 声明式的配置管理

    遵循 基础设施即代码 的理念,使用声明式配置描述整个环境。您只需告诉 Pigsty “想要什么样的数据库集群”,无需操心具体如何实现,系统会自动调整到期望状态。

  • 模块化的架构设计

    采用模块化 架构 设计,可自由组合以适应不同场景。除了核心的 PostgreSQL 模块外,还提供 Redis、MinIO、Etcd、FerretDB 等可选模块,以及对多种 PG 兼容内核的支持。

  • 扎实的安全最佳实践

    采用业界领先的安全最佳实践:自签名 CA 签发证书加密通信,AES 加密备份,SCRAM-SHA-256 口令哈希,开箱即用的 ACL 模型,遵循最小权限原则的 HBA 规则集,确保数据安全。

  • 简单易用的部署方案

    所有依赖被预先打包,可在无互联网访问的环境中一键安装。本地沙箱环境可运行在 1核2G 的微型虚拟机中,提供与生产环境完全一致的功能模拟。提供基于 Vagrant 的本地沙箱与基于 Terraform 的云端部署方案。


Pigsty 不是什么

Pigsty 并不是传统的、包罗万象的 PaaS(平台即服务)系统。

  • Pigsty 不提供基础硬件资源。它运行在您提供的节点之上,无论是裸金属、虚拟机还是云主机,但它本身不创建或管理这些资源(尽管提供了 Terraform 模板来简化云资源的准备)。

  • Pigsty 不是容器编排系统。它直接运行在操作系统之上,不需要 Kubernetes 或 Docker 作为基础设施。当然,它可以与这些系统共存,并提供 Docker 模块来运行无状态应用。

  • Pigsty 不是通用的数据库管理工具。它专注于 PostgreSQL 及其生态,虽然也支持 Redis、Etcd、MinIO 等周边组件,但核心始终是围绕 PostgreSQL 构建的。

  • Pigsty 不会锁定您。它基于开源组件构建,不修改 PostgreSQL 内核,不引入专有协议。您随时可以脱离 Pigsty 继续使用管理好的 PostgreSQL 集群。

Pigsty 不限制您应该或不应该如何构建数据库服务。例如:

  • Pigsty 为您提供了良好的参数默认值和配置模板,但您可以覆盖任何参数。
  • Pigsty 提供了声明式 API,但您依然可以使用底层工具(Ansible、Patroni、pgBackRest 等)进行手动管理。
  • Pigsty 可以管理完整的生命周期,也可以只使用其中的监控系统来观测现有的数据库实例或 RDS。

Pigsty 提供的抽象层次不同于硬件层面,它工作在数据库服务层面,聚焦于如何让 PostgreSQL 以最佳状态交付价值,而不是重新发明轮子。


PostgreSQL 部署方式的演进

要理解 Pigsty 的价值,让我们回顾一下 PostgreSQL 部署方式的演进历程。

手工部署时代

在传统的部署方式中,DBA 需要手工安装配置 PostgreSQL,手工设置复制,手工配置监控,手工处理故障。这种方式的问题显而易见:

  • 效率低下:每个实例都需要重复大量手工操作,容易出错。
  • 缺乏标准化:不同 DBA 配置的数据库可能千差万别,难以维护。
  • 可靠性差:故障处理依赖人工介入,恢复时间长,容易出现人为失误。
  • 观测性弱:缺乏统一的监控体系,问题发现和定位困难。

托管数据库时代

为了解决这些问题,云厂商提供了托管数据库服务(RDS)。云 RDS 确实解决了部分运维问题,但也带来了新的挑战:

  • 成本高昂:托管服务通常收取硬件成本数倍到十几倍的"服务费"。
  • 供应商锁定:迁移困难,受制于特定云平台。
  • 功能受限:无法使用某些高级特性,扩展插件受限,参数调整受限。
  • 数据主权:数据存储在云端,自主可控性降低。

本地 RDS 时代

Pigsty 代表了第三种方式:在本地环境中构建媲美甚至超越云 RDS 的数据库服务。

Pigsty 结合了前两种方式的优点:

  • 自动化程度高:一键部署,自动配置,故障自愈,像云 RDS 一样便捷。
  • 完全自主可控:运行在您自己的基础设施上,数据完全掌握在自己手中。
  • 成本极低:以接近纯硬件的成本运行企业级数据库服务。
  • 功能完整:无限制地使用 PostgreSQL 的全部能力和生态扩展。
  • 开放架构:基于开源组件,无供应商锁定,可随时迁移。

这种方式特别适合:

  • 私有云与混合云:需要在本地环境中运行数据库的企业。
  • 成本敏感型用户:希望降低数据库 TCO 的组织。
  • 高安全要求场景:需要完全自主可控的关键数据。
  • PostgreSQL 深度用户:需要使用高级特性和丰富扩展的场景。
  • 开发与测试:需要在本地快速搭建与生产环境一致的数据库。

接下来

现在您已经了解了 Pigsty 的基本概念,可以:

1 - 积木式架构

Pigsty 的模块化架构介绍 —— 声明式组合,按需定制,自由部署。

Pigsty 使用 模块化架构声明式接口,您可以像 搭积木一样自由按需组合模块


模块

Pigsty 采用模块化设计,有六个主要的默认模块:PGSQLINFRANODEETCDREDISMINIO

  • PGSQL:由 Patroni、Pgbouncer、HAproxy、PgBackrest 等驱动的自治高可用 Postgres 集群。
  • INFRA:本地软件仓库、Nginx、Grafana、Victoria、AlertManager、Blackbox Exporter 可观测性全家桶。
  • NODE:调整节点到所需状态、名称、时区、NTP、ssh、sudo、haproxy、docker、vector、keepalived
  • ETCD:分布式键值存储,用作高可用 Postgres 集群的 DCS:共识选主/配置管理/服务发现。
  • REDIS:Redis 服务器,支持独立主从、哨兵、集群模式,并带有完整的监控支持。
  • MINIO:与 S3 兼容的简单对象存储服务器,可作为 PG 数据库备份的可选目的地。

你可以声明式地自由组合它们。如果你想要主机监控,在基础设施节点上安装 INFRA 模块,并在纳管节点上安装 NODE 模块就足够了。 ETCDPGSQL 模块用于搭建高可用 PG 集群,将模块安装在多个节点上,可以自动形成一个高可用的数据库集群。 您可以复用 Pigsty 基础架构并开发您自己的模块,REDISMINIO 可以作为一个样例。后续还会有更多的模块加入,例如对 Mongo 与 MySQL 的初步支持已经提上了日程。

请注意,所有模块都强依赖 NODE 模块:在 Pigsty 中节点必须先安装 NODE 模块,被 Pigsty 纳管后方可部署其他模块。 当节点(默认)使用本地软件源进行安装时,NODE 模块对 INFRA 模块有弱依赖。因此安装 INFRA 模块的管理节点/基础设施节点会在 deploy.yml 剧本中完成 Bootstrap 过程,解决循环依赖。

pigsty-sandbox


单机安装

默认情况下,Pigsty 将在单个 节点 (物理机/虚拟机) 上安装。deploy.yml 剧本将在当前节点上安装 INFRAETCDPGSQL 和可选的 MINIO 模块, 这将为你提供一个功能完备的可观测性技术栈全家桶(VictoriaMetrics、VictoriaLogs、VictoriaTraces、Grafana、Alertmanager、Blackbox Exporter 等),以及一个内置的 PostgreSQL 单机实例作为 CMDB,也可以开箱即用。(集群名 pg-meta,库名为 meta

这个节点现在会有完整的自我监控系统、可视化工具集,以及一个自动配置有 PITR 的 Postgres 数据库(HA 不可用,因为你只有一个节点)。你可以使用此节点作为开发箱、测试、运行演示以及进行数据可视化和分析。或者,还可以把这个节点当作管理节点,部署纳管更多的节点!

pigsty-arch


监控

安装的 单机元节点 可用作管理节点监控中心,以将更多节点和数据库服务器置于其监视和控制之下。

Pigsty 的监控系统可以独立使用,如果你想安装 VictoriaMetrics / Grafana 可观测性全家桶,Pigsty 为你提供了最佳实践! 它为 主机节点PostgreSQL数据库 提供了丰富的仪表盘。 无论这些节点或 PostgreSQL 服务器是否由 Pigsty 管理,只需简单的配置,你就可以立即拥有生产级的监控和告警系统,并将现有的主机与 PostgreSQL 纳入监管。

pigsty-dashboard.jpg


高可用PG集群

Pigsty 帮助您在任何地方 拥有 您自己的生产级高可用 PostgreSQL RDS 服务。

要创建这样一个高可用 PostgreSQL 集群/RDS 服务,你只需用简短的配置来描述它,并运行剧本来创建即可:

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 }
$ bin/pgsql-add pg-test  # 初始化集群 'pg-test'

不到10分钟,您将拥有一个服务接入,监控,备份 PITR,高可用配置齐全的 PostgreSQL 数据库集群。

pigsty-ha.png

硬件故障由 patroni、etcd 和 haproxy 提供的自愈高可用架构来兜底,在主库故障的情况下,默认会在 45 秒内执行自动故障转移(Failover)。 客户端无需修改配置重启应用:Haproxy 利用 patroni 健康检查进行流量分发,读写请求会自动分发到新的集群主库中,并避免脑裂的问题。 这一过程十分丝滑,例如在从库故障,或主动切换(switchover)的情况下,客户端只有一瞬间的当前查询闪断,

软件故障、人为错误和 数据中心级灾难由 pgbackrest 和可选的 MinIO 集群来兜底。这为您提供了本地/云端的 PITR 能力,并在数据中心失效的情况下提供了跨地理区域复制,与异地容灾功能。

1.1 - 节点

节点(node)是对硬件资源/操作系统的抽象,可以是物理机,裸金属、虚拟机、或者容器与 pods。

节点(node) 是对硬件资源/操作系统的抽象,可以是物理机,裸金属、虚拟机、或者容器与 pods。

只要装着 Linux 操作系统(以及 systemd 守护进程),能使用 CPU/内存/磁盘/网络 等标准资源,即可视作节点。

节点上可以安装 模块,Pigsty 中存在几种不同类型节点,主要区别就在于安装了不同的模块。

类型说明
普通节点被 Pigsty 管理的节点
ADMIN 节点使用 Ansible 发出管理指令的节点
INFRA 节点安装 INFRA 模块的基础设施节点
ETCD 节点安装 ETCD 模块的分布式共识节点
MINIO 节点安装 MINIO 模块的对象存储节点
PGSQL 节点安装 PGSQL 模块的数据库节点
……安装了其他各类模块的节点……

单机部署 Pigsty 时,多者合而为一,当前节点将同时作为普通节点,管理节点、基础设施节点、ETCD 节点,以及数据库节点。


普通节点

使用 Pigsty 管理节点,可在其上安装模块。node.yml 剧本将调整节点至所需状态。 普通节点上可能会运行以下服务:

组件端口描述状态
node_exporter9100节点监控指标导出器✅ 默认启用
haproxy9101HAProxy 负载均衡器(管理端口)✅ 默认启用
vector9598日志收集代理✅ 默认启用
docker9323启用容器支持⚠️ 按需启用
keepalivedn/a管理节点集群 L2 VIP⚠️ 按需启用
keepalived_exporter9650监控 Keepalived 状态⚠️ 按需启用

这里,node_exporter 会向监控系统暴露主机上的各类监控指标,vector 会向日志收集系统发送日志,haproxy 则提供负载均衡功能,对外暴露服务。 这三项服务默认开启。而 Dockerkeepalivedkeepalived_exporter 这三项服务作为可选项,可按需启用。


ADMIN节点

一套 Pigsty 部署中有且只有一个 管理节点,管理节点是执行 Ansible 剧本,发起控制/部署命令的节点。

该节点拥有对所有其他节点的 ssh/sudo 访问权限。管理节点的安全至关重要,应严格控制访问;其信任范围与关键资产参见 安全模型:信任边界

单机安装配置过程 中,当前安装节点就是管理节点。 但也有其他的可能,例如,如果你的笔记本可以 ssh 访问所有被管理节点,并且安装了 Ansible,那么在这种情况下, 您的笔记本电脑就可以作为一个管理节点 —— 尽管这对于生产环境来说不太合适。

例如,您使用自己的笔记本电脑,管理一台云端上部署了 Pigsty 的虚拟机,这时候,您的笔记本电脑就是管理节点。

在严肃的生产环境中,管理节点通常是 1-2 台 DBA 专用的 管控机。在资源受限的环境中,则通常会复用 INFRA节点 作为管理节点。 因为所有的 INFRA 节点上都默认安装了 Ansible,可以作为额外的备用的管理节点。


INFRA节点

一套 Pigsty 部署可能有 1 个或多个 INFRA 节点,大型生产环境可能有 2-3 个。

配置清单中的 infra 分组指定哪些节点是 INFRA 节点,这些节点上会部署 INFRA 模块,包含下列组件:

组件端口描述
nginx80/443Web 图形界面,本地软件仓库
grafana3000可视化平台
victoriaMetrics8428时序数据库(收存监控指标)
victoriaLogs9428日志收集服务器
victoriaTraces10428链路追踪收集服务器
vmalert8880告警与衍生指标计算规则
alertmanager9059告警聚合分发/屏蔽管理
blackbox_exporter9115黑盒探测,ping 节点 / vip
dnsmasq53内部 DNS 域名解析
chronyd123NTP 时间服务器
ansible-执行剧本,发起管理

其中,Nginx 作为当前模块的入口,提供 Web 图形界面和本地软件仓库服务。 如果你部署多个 INFRA 节点,每个 Infra 节点上的服务是相互独立的。 但你确实可以从任意一个 Infra 节点上的 Grafana 访问所有的监控数据源。

Pigsty 使用 Apache-2.0 许可证开源,但请注意其中的 Grafana 组件使用 AGPLv3 许可证。


ETCD节点

ETCD 模块为 PostgreSQL 高可用提供分布式共识服务(DCS)。

配置清单 中的 etcd 分组指定哪些节点是 ETCD 节点,ETCD 节点上运行着 etcd 服务器,监听以下两个端口:

组件端口描述
etcd2379ETCD 分布式键值存储(客户端端口)
etcd2380ETCD 集群 Peer 通信端口

MINIO节点

MINIOn 模块为 PostgreSQL 提供了一个可选的 备份存储仓库

配置清单中的 minio 分组指定哪些节点是 MinIO 节点,这些节点上会运行 MinIO 服务器,监听以下端口:

组件端口描述
minio9000MinIO S3 API 服务端口
minio9001MinIO 管理控制台端口

PGSQL节点

安装了 PGSQL 模块的节点被称为 PGSQL 节点。节点与 PostgreSQL 实例为 1:1 部署,也就是每个节点上只运行一个 PG 实例。

PGSQL 节点可从相应 PostgreSQL 实例借用 身份 —— 由 node_id_from_pg 控制,默认为 true,即节点名会被设置为 PG 实例名。

PGSQL 节点在 普通节点 的基础上,还会额外运行以下组件:

组件端口描述状态
postgres5432PostgreSQL 数据库服务器✅ 默认启用
pgbouncer6432Pgbouncer 连接池✅ 默认启用
patroni8008Patroni 高可用管理组件✅ 默认启用
pg_exporter9630Postgres 监控指标导出器✅ 默认启用
pgbouncer_exporter9631PGBouncer 监控指标导出器✅ 默认启用
pgbackrest_exporter9854Pgbackrest 监控指标导出器✅ 默认启用
vip-managern/a将 L2 VIP 绑定在集群主库节点上⚠️ 按需启用
{{ pg_cluster }}-primary5433通过 haproxy 对外暴露数据库服务:主连接池:读/写服务✅ 默认启用
{{ pg_cluster }}-replica5434通过 haproxy 对外暴露数据库服务:副本连接池:只读服务✅ 默认启用
{{ pg_cluster }}-default5436通过 haproxy 对外暴露数据库服务:主直连服务✅ 默认启用
{{ pg_cluster }}-offline5438通过 haproxy 对外暴露数据库服务:离线直连:离线读服务✅ 默认启用
{{ pg_cluster }}-<service>543x通过 haproxy 对外暴露数据库服务:PostgreSQL 定制服务⚠️按需定制

其中,vip-manager 只有当用户配置了 PG VIP 时才会启用。 在 pg_services 中可以定义更多的 自定义服务,这些服务会被 haproxy 对外暴露,并使用更多的服务端口。

1.2 - INFRA 架构

Pigsty 中基础设施模块的架构,组件与功能详解。

运行生产级别高可用 PostgreSQL 集群,通常需要一套完善的基础设施服务(底座)来支撑,例如监控告警、日志收集、时间同步、DNS 解析,本地软件仓库等。 Pigsty 提供了 INFRA 模块 来解决这个问题 —— 这是一个 可选模块,但我们强烈推荐启用它。


概览

下图是 单机部署 时的架构示意图,图中右半部分即为 INFRA 模块 所包含的组件,其中包括:

组件种类描述
NginxWeb 服务器Web 界面 的统一入口,本地软件仓库,内部服务的反向代理
Repo软件仓库APT / DNF 仓库,下载有所有部署需要的 RPM/DEB 包及其依赖
Grafana可视化平台呈现监控指标、日志与链路追踪,承载监控大屏、巡检报表以及自定义数据应用。
VictoriaMetrics时序数据库拉取全部监控指标,兼容 Prometheus API,并通过 VMUI 提供查询界面。
VictoriaLogs日志平台集中收集存储日志,所有节点默认运行 Vector,将系统日志与数据库日志推送到此。
VictoriaTraces链路追踪收集慢 SQL、服务链路等追踪数据。
VMAlert告警计算评估告警规则,将事件推送至 Alertmanager。
AlertManager告警管理聚合告警事件,分发告警通知,支持邮件、Webhook 等渠道。
BlackboxExporter黑盒探测探测各个 IP/VIP/URL 的可达性。
DNSMASQDNS 解析提供 DNS 解析服务,解析 Pigsty 内部使用到的域名。【可选】
Chronyd时间同步提供 NTP 时间同步服务,确保所有节点时间一致。 【可选】
CA证书签发签发环境内的加密证书
Ansible发起管理批量,声明式,无 Agent 管理大量服务器的工具

pigsty-arch


Nginx

Nginx 是 Pigsty 所有 WebUI 类服务的访问入口,默认使用 80 / 443 端口对外提供 HTTP / HTTPS 服务。在线演示

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10http://i.pigstyhttps://i.pigstyhttps://demo.pigsty.cc

带有 WebUI 的基础设施组件可以通过 Nginx 统一对外暴露服务,例如 GrafanaVictoriaMetrics(VMUI)、AlertManager, 以及 HAProxy 控制台,此外,本地软件仓库 等静态文件资源也通过 Nginx 对内外提供服务。

Nginx 会根据 infra_portal 中的定义,配置本地 Web 服务器或反向代理服务器。

infra_portal:
  home : { domain: i.pigsty }

默认情况下将对外暴露 Pigsty 的管理首页:i.pigsty,上面不同的端点挂载代理了不同的组件:

端点组件原生端口备注公开演示
/Nginx80/443首页、本地仓库、文件服务demo.pigsty.cc/zh/
/ui/Grafana3000Grafana 仪表盘入口demo.pigsty.cc/ui/
/vmetrics/VictoriaMetrics8428时序数据库 Web UIdemo.pigsty.cc/vmetrics/
/vlogs/VictoriaLogs9428日志数据库 Web UIdemo.pigsty.cc/vlogs/
/vtraces/VictoriaTraces10428链路追踪 Web UIdemo.pigsty.cc/vtraces/
/vmalert/VMAlert8880告警规则管理demo.pigsty.cc/vmalert/
/alertmgr/AlertManager9059告警管理 Web UIdemo.pigsty.cc/alertmgr/
/blackbox/Blackbox9115黑盒探测器

Pigsty 允许对 Nginx 进行丰富的定制,将其作为本地文件服务器,或者反向代理服务器,配置自签名或者真正的 HTTPS 证书。

更多信息,请参阅:教程:Nginx:向外代理暴露Web服务教程:Certbot:申请与更新HTTPS证书


Repo

Pigsty 会在安装时,默认在 Infra 节点上创建一个 本地软件仓库,以加速后续软件安装。在线演示

该软件仓库默认位于 /www/pigsty 目录, 由 Nginx 对外提供服务,挂载在 /pigsty 路径上:

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10/pigstyhttp://i.pigsty/pigstyhttps://i.pigsty/pigstyhttps://demo.pigsty.cc/pigsty

Pigsty 支持 离线安装,实质上是将做好的本地软件仓库提前复制到目标环境中。 当 Pigsty 执行生产部署,需要创建本地软件仓库时,如果发现本地已经存在 /www/pigsty/repo_complete 标记文件,则会跳过从上游下载软件包的步骤,直接使用已有的软件包,避免联网下载。

repo

更多信息,请参阅:配置:INFRA - REPO


Grafana

Grafana 是 Pigsty 监控系统的核心组件,用于可视化展示监控指标、日志与各种信息。在线演示

Grafana 默认监听 3000 端口,挂载于 Nginx /ui 路径点上代理访问:

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10/uihttp://i.pigsty/uihttps://i.pigsty/uihttps://demo.pigsty.cc/ui

Pigsty 预置了基于 VictoriaMetrics / Logs / Traces 的大量监控面板,并通过 URL 跳转实现一键下钻上卷,帮助快速定位故障。

Grafana 亦可作为低代码可视化平台使用,因此默认安装 ECharts、victoriametrics-datasource、victorialogs-datasource 等插件, 同时将 Vector / Victoria 数据源统一注册为 vmetrics-*vlogs-*vtraces-*,方便扩展自定义仪表板。

dashboard

更多信息请参阅:配置:INFRA - GRAFANA


VictoriaMetrics

VictoriaMetrics 是 Pigsty 的时序数据库,负责拉取并存储所有监控指标。在线演示

默认监听 8428 端口,挂载于 Nginx /vmetrics 路径上,亦可通过 p.pigsty 域名直接访问:

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10/vmetricshttp://p.pigstyhttps://i.pigsty/vmetricshttps://demo.pigsty.cc/vmetrics

VictoriaMetrics 完全兼容 Prometheus API,支持 PromQL 查询、远程读写协议以及 Alertmanager API。 内置的 VMUI 提供即席查询界面,可直接探索指标数据,也可作为 Grafana 的数据源使用。

vmetrics

更多信息请参阅:配置:INFRA - VMETRICS


VictoriaLogs

VictoriaLogs 是 Pigsty 的日志平台,集中存储来自所有节点的结构化日志。在线演示

默认监听 9428 端口,挂载于 Nginx /vlogs 路径上:

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10/vlogshttp://i.pigsty/vlogshttps://i.pigsty/vlogshttps://demo.pigsty.cc/vlogs

所有纳管节点默认运行 Vector Agent,负责收集系统日志、PostgreSQL 日志、Patroni 日志、Pgbouncer 日志等,结构化处理后推送至 VictoriaLogs。 内置 Web UI 支持日志检索与过滤,也可配合 Grafana 的 victorialogs-datasource 插件进行可视化分析。

vlogs

更多信息请参阅:配置:INFRA - VLOGS


VictoriaTraces

VictoriaTraces 用于收集链路追踪数据与慢 SQL 记录。在线演示

默认监听 10428 端口,挂载于 Nginx /vtraces 路径上:

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10/vtraceshttp://i.pigsty/vtraceshttps://i.pigsty/vtraceshttps://demo.pigsty.cc/vtraces

VictoriaTraces 提供 Jaeger 兼容接口,可用于分析服务调用链路与数据库慢查询。 结合 Grafana 面板,能够快速定位性能瓶颈,追溯问题根因。

更多信息请参阅:配置:INFRA - VTRACES


VMAlert

VMAlert 是告警规则计算引擎,负责评估告警规则并将触发的事件推送至 Alertmanager在线演示

默认监听 8880 端口,挂载于 Nginx /vmalert 路径上:

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10/vmalerthttp://i.pigsty/vmalerthttps://i.pigsty/vmalerthttps://demo.pigsty.cc/vmalert

VMAlertVictoriaMetrics 读取指标数据,周期性执行告警规则评估。 Pigsty 预置了 PGSQL、NODE、REDIS 等模块的告警规则,覆盖常见故障场景,开箱即用。

vmalert

更多信息请参阅:配置:INFRA - VMALERT


AlertManager

AlertManager 负责告警事件的聚合、去重、分组与分发。在线演示

默认监听 9059 端口,挂载于 Nginx /alertmgr 路径上,亦可通过 a.pigsty 域名直接访问:

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10/alertmgrhttp://a.pigstyhttps://i.pigsty/alertmgrhttps://demo.pigsty.cc/alertmgr

AlertManager 支持多种通知渠道:邮件、Webhook、Slack、PagerDuty、企业微信等。 通过配置告警路由规则,可实现按严重程度、模块类型进行差异化分发,支持静默、抑制等高级功能。

alertmanager

更多信息请参阅:配置:INFRA - AlertManager


BlackboxExporter

Blackbox Exporter 用于主动探测目标的可达性,实现黑盒监控。

默认监听 9115 端口,挂载于 Nginx /blackbox 路径上:

IP 访问(替换)域名(HTTP)域名(HTTPS)公开演示
http://10.10.10.10/blackboxhttp://i.pigsty/blackboxhttps://i.pigsty/blackboxhttps://demo.pigsty.cc/blackbox

支持 ICMP Ping、TCP 端口、HTTP/HTTPS 端点等多种探测方式。 可用于监控 VIP 可达性、服务端口存活、外部依赖健康状态等场景,是判断故障影响范围的重要手段。

blackbox

更多信息请参阅:配置:INFRA - BLACKBOX


Ansible

Ansible 是 Pigsty 的核心编排工具,所有部署、配置、管理操作均通过 Ansible Playbook 完成。

Pigsty 在安装时会自动在管理节点(Infra 节点)上安装 Ansible。 它采用声明式配置风格与幂等剧本设计:同一剧本可重复执行,系统会自动收敛至期望状态,无需担心副作用。

Ansible 的核心优势:

  • 无 Agent:通过 SSH 远程执行,无需在目标节点安装额外软件。
  • 声明式:描述期望状态,而非执行步骤,配置即文档。
  • 幂等性:多次执行结果一致,支持部分失败后重试。

更多信息请参阅:剧本:Pigsty Playbook


DNSMASQ

DNSMASQINFRA节点 上提供环境内的 DNS 解析服务,将域名解析到对应 IP 地址。

DNSMASQ 默认监听 53 端口(UDP/TCP),为环境内所有节点提供 DNS 解析服务,解析记录位于 /etc/dnsmasq.d/pigsty 目录中。

其他模块在部署时会自动将域名注册到 INFRA 节点的 DNSMASQ 服务中,您可以按需使用。 DNS 是完全可选的模块,Pigsty 本身不依赖它即可正常运行。 客户端节点可将 INFRA 节点配置为 DNS 服务器,即可通过域名访问各服务,无需记忆 IP 地址。

更多信息请参阅:配置:INFRA - DNS教程:DNS:配置域名解析


Chronyd

Chronyd 提供 NTP 时间同步服务,确保环境内所有节点时钟一致。默认监听 123 端口(UDP),作为环境内的时间源。

时间同步对分布式系统至关重要:日志排查需要时间戳对齐,证书校验依赖时钟准确,PostgreSQL 流复制也对时钟偏移敏感。 在隔离网络环境中,INFRA 节点可作为内部 NTP 服务器,其他节点同步至此。

在 Pigsty 中,默认所有节点都会启动 chonyd 服务用于时间同步。默认使用 pool.ntp.org 公共 NTP 服务器作为上游时间源。 Chronyd 本质上归属 Node 模块 管理,但在网络隔离的环境中,你使用 admin_ip 指向 INFRA 节点上的 Chronyd 服务作为内部时间源。 此时 INFRA节点 上的 Chronyd 服务将充当内部时间同步基础设施的角色。 更多信息请参阅:配置:NODE - TIME


INFRA节点与普通节点

在 Pigsty 中,节点与基础设施的关系是 弱循环依赖:node_monitor → infra → node

NODE模块 本身不依赖 INFRA模块,但节点模块中的监控功能(node_monitor)需要依赖基础设施模块提供的监控平台与服务。

因此,在 infra.ymldeploy 剧本中, 采用了一种 “交织部署” 的技术:

  • 首先初始化所有 普通节点 上的 NODE模块,但是不配置监控,因为基础设施服务尚未部署完成。
  • 然后初始化 INFRA节点 上的 INFRA模块,此时监控已经可用
  • 然后回过头来,重新配置所有 普通节点 上的监控功能,连接到已经部署完成的监控平台

如果您不追求 “一次性” 部署所有节点,也可以采用 分阶段部署 的方式,先初始化 INFRA 节点,然后再初始化其他普通节点即可。

节点与基础设施是如何耦合的?

普通节点会通过 admin_ip 参数来引用某个 INFRA节点 作为它们的基础设施提供者。

例如,当你配置了全局的 admin_ip = 10.10.10.10,那么通常意味着所有节点都会使用这个 IP 上的基础设施服务。

这样的设计允许你快速,批量的切换节点的基础设施提供者 —— 以下是 可能 引用 ${admin_ip} 的配置参数列表:

参数模块默认值说明
repo_endpointINFRAhttp://${admin_ip}:80软件仓库访问地址
repo_upstream.baseurlINFRAhttp://${admin_ip}/pigsty本地软件源 baseurl
infra_portal.endpointINFRA${admin_ip}:<port>Nginx 反向代理后端地址
dns_recordsINFRA["${admin_ip} i.pigsty", ...]DNS 解析记录
node_default_etc_hostsNODE["${admin_ip} i.pigsty"]默认静态 DNS 记录
node_etc_hostsNODE[]自定义静态 DNS 记录
node_dns_serversNODE["${admin_ip}"]动态 DNS 服务器地址
node_ntp_serversNODE["pool pool.ntp.org iburst"]NTP 时间服务器(可选)

例如,当节点安装软件的时候,local 仓库指向的就是 admin_ip:80/pigsty 上的 Nginx 本地软件仓库。DNS 服务器指向的也是 admin_ip:53 上的 DNSMASQ。 但这并不是强制要求的,例如,节点完全可以忽略并不使用 local 仓库,直接从互联网上游源安装(大部分单机配置模板);DNS 服务器也完全可以不配置与不使用,Pigsty 本身并无对 DNS 服务器的依赖。


INFRA节点与ADMIN节点

通常发起管理的 ADMIN节点 会与基础设施节点(INFRA节点)重合。 在 单机部署 就是这样的。在多节点部署中,如果有多个 INFRA 节点,管理节点通常是 infra 分组中的第一个,其余作为备用。 不过,也有例外存在。您可能会出于各种原因,将两者分离开来:

例如在 大规模生产环境部署 中,一种经典模式是使用 1-2 台归属于 DBA 组的专用管理主机(微型虚拟机即可), 作为整个环境的控制中枢,并使用 2-3 台高配置的物理机(或者更多!),作为整个环境的监控基础设施。这时候管理节点就与基础设施节点分离开来了。 这时候,你在配置文件中填入的 admin_ip 应该指向某个 INFRA 节点的 IP 地址,而不是当前 ADMIN 节点的 IP 地址。 这是因为历史遗留原因:Pigsty 设计之初,ADMIN 节点 与 INFRA 节点 是强绑定的概念,后来才逐渐演化出分离的能力,因此参数名称未做修改。

另一种常见的情况是 本地管理云节点,例如,您可以在自己的笔记本上安装 Ansible,然后填入你的云节点作为 “被管理对象”。 在这种情况下,您的笔记本充当 ADMIN 节点,而云服务器充当 INFRA 节点。

all:
  children:
    infra:   { hosts: { 10.10.10.10: { infra_seq: 1 , ansible_host: your_ssh_alias } } }  # <--- 利用 ansible_host 指向云节点(填入 ssh 别名)
    etcd:    { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }    # ssh 连接会使用 ssh your_ssh_alias
    pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }, vars: { pg_cluster: pg-meta } }
  vars:
    version: v4.4.0
    admin_ip: 10.10.10.10
    region: default

多个 INFRA 节点

默认情况下,Pigsty 只需要一个 INFRA 节点即可满足大部分需求。INFRA 模块挂了,也不会影响其他节点上的数据库服务。

但是,在一些对监控与告警要求极高的生产环境中,您可能希望部署多个 INFRA 节点,来提升基础设施的可用性。 一种常见的部署是使用两个 Infra 节点,提供一份冗余副本,并互相监控对方… 或者使用更多,部署分布式的 Victoria 集群实现无限水平扩展。

每个 Infra 节点都是 独立 的,Nginx 指向的都是本机上的服务。 VictoriaMetrics 也是独立抓取环境中所有服务的监控指标, 日志会默认推送到所有 VictoriaLogs 日志采集端点上。 唯一的例外是 Grafana,每一个 Grafana 中都会注册所有的 VictoriaMetrics / Logs / Traces / PostgreSQL 实例作为数据源。 因此每一个 Grafana 实例都能看到完整的监控数据。

如果您对 Grafana 进行修改,例如添加新的仪表板,或者修改数据源配置,这些变更只会影响当前节点上的 Grafana 实例。 如果您希望所有节点上的 Grafana 保持一致,可以使用一个 PostgreSQL 数据库作为共享存储,详情参考 教程:配置 Grafana 高可用

1.3 - PGSQL 架构

PostgreSQL 模块的组件交互与数据流。

PGSQL 模块在生产环境中以 集群 的形式组织,这些 集群 是由一组通过 主-备 关联的数据库 实例 组成的 逻辑实体


概览

PGSQL 模块 包含下列组件,协同提供生产级 PostgreSQL 高可用集群服务:

组件简介描述
postgres数据库世界上最先进的开源关系型数据库,PGSQL 模块的核心。
patroni高可用托管 PostgreSQL 进程,协调故障转移、选主、配置变更。
pgbouncer连接池轻量级连接池中间件,复用连接、降低开销、提供额外灵活性。
pgbackrest备份恢复全量/增量备份与 WAL 归档,支持本地与对象存储。
pg_exporter指标导出导出 PostgreSQL 监控指标供 Prometheus 抓取。
pgbouncer_exporter指标导出导出 Pgbouncer 连接池指标。
pgbackrest_exporter指标导出导出 pgBackrest 备份状态指标。
vip-managerVIP 管理将 L2 VIP 绑定到当前主库节点,实现透明漂移。【可选】

其中 vip-manager 为按需启用的组件。此外,PGSQL 还会使用到其他模块中的组件:

组件模块简介描述
haproxyNODE负载均衡对外暴露服务端口,根据角色分发流量至主库或从库。
vectorNODE日志采集收集 PostgreSQL、PatroniPgbouncer 等日志推送至中心。
etcdETCDDCS分布式一致性存储,用于保存集群元数据与领导者信息。

如果用类比来形容,PostgreSQL 数据库内核就是 CPU,而整个 PGSQL 模块将其封装为一台完整的计算机。 PatroniEtcd 组成 高可用子系统pgBackRest 与 MinIO 组成 备份恢复子系统HAProxyPgbouncervip-manager 组成 接入子系统。 各种 Exporter 与 Vector 构成 可观测性子系统; 最后还可以替换不同的 内核 CPU扩展卡

子系统组件功能
高可用子系统Patroni + etcd故障检测、自动切换、配置管理
接入子系统HAProxy + Pgbouncer + vip-manager服务暴露、负载均衡、连接池、VIP
备份恢复子系统pgBackRest(+ MinIO)全量/增量备份、WAL 归档、PITR
可观测性子系统pg_exporter / pgbouncer_exporter / pgbackrest_exporter + Vector指标采集、日志收集

组件交互

pigsty-arch

  • 集群 DNS 由 infra 节点上的 DNSMASQ 负责解析
  • 集群 VIP 由 vip-manager 组件管理,它负责将 pg_vip_address 绑定到集群主库节点上。
  • 集群服务由节点上的 HAProxy 对外暴露,不同服务通过节点的不同端口(543x)区分。
  • Pgbouncer 是连接池中间件,默认监听 6432 端口,可以缓冲连接、暴露额外的指标,并提供额外的灵活性。
  • PostgreSQL 监听 5432 端口,提供关系型数据库服务
    • 在多个节点上安装 PGSQL 模块,并使用同一集群名,将自动基于流式复制组成高可用集群
    • PostgreSQL 进程默认由 patroni 管理。
  • Patroni 默认监听端口 8008,监管着 PostgreSQL 服务器进程
    • PatroniPostgres 服务器作为子进程启动
    • Patroni 使用 etcd 作为 DCS:存储配置、故障检测和领导者选举。
    • Patroni 通过健康检查提供 Postgres 信息(比如主/从),HAProxy 通过健康检查使用该信息分发服务流量
  • pg_exporter 在 9630 端口对外暴露 postgres 监控指标
  • pgbouncer_exporter 在端口 9631 暴露 pgbouncer 指标
  • pgBackRest 默认使用本地备份仓库 (pgbackrest_method = local
    • 如果使用 local(默认)作为备份仓库,pgBackRest 将在主库节点的 pg_fs_backup 下创建本地仓库
    • 如果使用 minio 作为备份仓库,pgBackRest 将在专用的 MinIO 集群上创建备份仓库
  • Vector 负责收集 Postgres 相关日志(postgres, pgbouncer, patroni, pgbackrest)
    • vector 监听 9598 端口,也对 infra 节点上的 VictoriaMetrics 暴露自身的监控指标
    • vector 将日志发送至 infra 节点上的 VictoriaLogs

高可用子系统

高可用 子系统由 Patronietcd 组成,负责 PostgreSQL 集群的故障检测、自动切换与配置管理。

工作原理Patroni 在每个节点上运行,托管本地 PostgreSQL 进程,并将集群状态(领导者、成员、配置)写入 etcd。 当主库故障时,Patroni 通过 etcd 协调选举,选出最健康的从库提升为新主库,整个过程自动完成,RTO 通常在 45 秒内。

关键交互

  • PostgreSQL:作为父进程启动、停止、重载 PG,控制其生命周期
  • etcd:外部依赖,写入/监视领导者键,实现分布式共识与故障检测
  • HAProxy:通过 REST API(:8008)提供健康检查,告知实例角色
  • vip-manager:监视 etcd 中的领导者键,自动漂移 VIP

更多信息请参阅:高可用配置:PGSQL - PG_BOOTSTRAP


服务接入子系统

接入子系统由 HAProxyPgbouncervip-manager 组成,负责对外暴露服务、路由流量与连接池化。

有多种不同的接入方法,一种典型的流量路径是:客户端 → DNS/VIP → HAProxy (543x) → Pgbouncer (6432) → PostgreSQL (5432)

层级组件端口职责
L2 VIPvip-manager-将 L2 VIP 绑定到主库节点(可选)
L4 负载均衡HAProxy543x服务暴露、负载均衡、健康检查
L7 连接池Pgbouncer6432连接复用、会话管理、事务池化

服务端口

  • 5433 primary:读写服务,路由至主库 Pgbouncer
  • 5434 replica:只读服务,路由至从库 Pgbouncer
  • 5436 default:默认服务,直连主库(绕过连接池)
  • 5438 offline:离线服务,直连离线从库(ETL/分析)

关键特性

  • HAProxy 通过 Patroni REST API 判断实例角色,自动路由流量
  • Pgbouncer 采用事务级池化,吸收连接峰值,降低 PG 连接开销
  • vip-manager 监视 etcd 领导者键,故障切换时自动漂移 VIP

更多信息请参阅:服务接入配置:PGSQL - PG_ACCESS


备份恢复子系统

备份恢复子系统由 pgBackRest 组成(可选配 MinIO 作为远程仓库),负责数据备份与时间点恢复(PITR)。

备份类型

  • 全量备份:完整的数据库副本
  • 增量/差异备份:仅备份变更的数据块
  • WAL 归档:持续归档事务日志,支持恢复到恢复窗口内的任意时间点

存储后端

  • local(默认):本地磁盘,备份存储在 pg_fs_backup 挂载点
  • minio:S3 兼容对象存储,支持集中化备份管理与异地容灾

关键交互

更多信息请参阅:PITR备份恢复配置:PGSQL - PG_BACKUP


可观测性子系统

可观测性子系统由三个 ExporterVector 组成,负责指标采集与日志收集。

组件端口采集对象关键指标
pg_exporter9630PostgreSQL会话、事务、复制延迟、缓冲命中
pgbouncer_exporter9631Pgbouncer连接池利用率、等待队列、命中率
pgbackrest_exporter9854pgBackRest最近备份时间、大小、类型
vector9598postgres/patroni/pgbouncer 日志结构化日志流

数据流向

  • 指标:Exporter → VictoriaMetrics(INFRA)→ Grafana 仪表盘
  • 日志Vector → VictoriaLogs(INFRA)→ Grafana 日志查询

pg_exporter / pgbouncer_exporter 通过本地 Unix Socket 连接目标服务,与 HA 拓扑解耦。在 精简安装 模式下,可禁用这些组件。

更多信息请参阅:配置:PGSQL - PG_MONITOR


PostgreSQL

PostgreSQL 是 PGSQL 模块的核心,默认监听 5432 端口提供关系型数据库服务,采用与 节点 1:1 对应的部署模型。

Pigsty 目前支持 PostgreSQL 14 - 18(生命周期内的大版本),使用 PGDG 官方仓库 提供的二进制包安装。 Pigsty 还允许您使用其他的 PG 内核分支 替换默认的 PostgreSQL 内核, 并在 PG 内核上加装多达 531 个扩展插件。

PostgreSQL 进程默认由 高可用 Agent —— Patroni 托管拉起。 当一个集群中只有一个节点时,该实例即为主库;当集群包含多个节点时,其余实例会自动作为从库加入: 通过物理复制,实时从主库同步数据变更。从库可以承载只读请求,并在主库故障时自动接管。

pigsty-ha.png

您可以直接访问 PostgreSQL,或者通过 HAProxyPgbouncer 连接池来访问。

更多信息请参阅:配置:PGSQL - PG_BOOTSTRAP


Patroni

Patroni 是 PostgreSQL 高可用控制组件,默认监听 8008 端口。

Patroni 接管 PostgreSQL 的启动、停止、配置与健康状态,将领导者、成员信息写入 etcd。 它负责自动故障转移、保持复制因子、协调参数变更,并提供 REST API 供 HAProxy、监控与管理员查询。

HAProxy 通过 Patroni 健康检查端点判断实例角色,将流量路由至正确的主库或从库。 vip-manager 监视 etcd 中的领导者键,在主库切换时自动漂移 VIP。

patroni

更多信息请参阅:配置:PGSQL - PG_BOOTSTRAP


Pgbouncer

Pgbouncer 是轻量级连接池中间件,默认监听 6432 端口,与 PostgreSQL 数据库与节点保持 1:1 部署。

Pgbouncer 以无状态方式运行在每个实例上,通过本地 Unix Socket 连接 PostgreSQL,默认通过 Transaction Pooling 的方式 对 PG 连接进行池化管理,能够吸收大量客户端的瞬时连接请求,稳定数据库会话,降低锁征用,显著提升高并发状态下的性能表现。

Pigsty 默认让生产流量(读写服务 5433 / 只读服务 5434)经由 Pgbouncer, 仅默认服务(5436)与离线服务(5438)绕过连接池直连 PostgreSQL

连接池模式由 pgbouncer_poolmode 控制,默认为 transaction(事务级复用),可通过 pgbouncer_enabled 关闭连接池。

pgbouncer.png

更多信息请参阅:配置:PGSQL - PG_ACCESS


pgBackRest

pgBackRest 是专业的 PostgreSQL 备份恢复工具,也是 PG 生态的最强备份工具之一,支持全量/增量/差异备份与 WAL 归档。

Pigsty 使用 pgBackRest 实现 PostgreSQL 的 PITR 能力, 您可以在备份保留的时间窗口内,将集群回滚到任意时间点。

pgBackRestPostgreSQL 配合,在主库上创建备份仓库,执行备份与归档任务。 默认使用本地备份仓库(pgbackrest_method = local),也可配置为 MinIO 等对象存储,实现集中化备份管理。

初始化完成后可通过 pgbackrest_init_backup 自动发起首次全量备份。 恢复过程与 Patroni 集成,支持将副本引导为新的主库或备库。

pgbackrest

更多信息请参阅:备份恢复配置:PGSQL - PG_BACKUP


HAProxy

HAProxy 是服务入口与负载均衡器,对外暴露多个数据库服务端口。

端口服务名目标说明
9101管理接口-HAProxy 统计与管理页面
5433primary主库 Pgbouncer读写服务,路由至主库连接池
5434replica从库 Pgbouncer只读服务,路由至从库连接池
5436default主库 Postgres默认服务,直连主库(绕过连接池)
5438offline离线库 Postgres离线服务,直连离线从库(ETL/分析)

HAProxy 通过 Patroni REST API 提供的健康检查信息判断实例角色,将流量路由至对应的主库或从库。 服务定义由 pg_default_servicespg_services 组合而成。

可通过 pg_service_provider 指定专用的 HAProxy 节点组承载更高流量, 默认使用本地节点上的 HAProxy 对外发布服务。

haproxy

更多信息请参阅:服务接入配置:PGSQL - PG_ACCESS


vip-manager

vip-manager 负责将 L2 VIP 绑定到当前主库节点,这是一个可选的组件,如果您的网络支持 L2 VIP,可以考虑启用。

vip-manager 在每个 PG 节点上运行,监视 etcd 中由 Patroni 写入的领导者键, 将 pg_vip_address 绑定到当前主库节点的网卡上。 当集群发生故障转移时,vip-manager 会立即释放旧主机上的 VIP,并在新主机上重新绑定,从而将流量切换到新的主库。

该组件可选,通过 pg_vip_enabled 启用。 启用后需确保所有节点处于同一 VLAN,否则 VIP 无法正确漂移。 通常公有云网络环境不支持 L2 VIP,建议仅在本地自建环境与私有云环境中启用。

node-vip

更多信息请参阅:教程:VIP 配置配置:PGSQL - PG_ACCESS


pg_exporter

pg_exporter 导出 PostgreSQL 监控指标,默认监听 9630 端口。

pg_exporter 运行在每个 PG 节点上,通过本地 Unix Socket 连接 PostgreSQL, 导出覆盖会话、缓冲命中、复制延迟、事务率等丰富指标,供 INFRA 节点上的 VictoriaMetrics 抓取。

采集配置由 pg_exporter_config 指定, 支持自动数据库发现(pg_exporter_auto_discovery), 并可通过 pg_exporter_cache_ttls 配置阶梯式缓存策略。

您可以通过参数禁用这个组件,在 精简安装 中,这个组件不会被启用。

pg-exporter

更多信息请参阅:配置:PGSQL - PG_MONITOR


pgbouncer_exporter

pgbouncer_exporter 导出 Pgbouncer 连接池指标,默认监听 9631 端口。

pgbouncer_exporter 使用的同样是 pg_exporter 的二进制程序,但是使用专用的指标配置文件,支持 pgbouncer 1.8 - 1.25+。 pgbouncer_exporter 读取 Pgbouncer 的统计视图,提供连接池利用率、等待队列与命中率指标。

若禁用 Pgbouncer,本组件也同时关闭。在 精简安装 中,这个组件也不会被启用。

更多信息请参阅:配置:PGSQL - PG_MONITOR


pgbackrest_exporter

pgbackrest_exporter 导出备份状态指标,默认监听 9854 端口。

pgbackrest_exporter 解析 pgBackRest 状态,生成最近备份时间、大小、类型等指标。结合告警策略可快速发现备份过期或失败,保障数据安全。 请注意,当备份很多,或者使用大型网络存储库时,采集过程开销较大,因此 pgbackrest_exporter 默认设置了 2分钟的采集间隔。 最慢情况下,您可能要在一个备份完成后的 2 分钟后,才能在监控系统中看到最新的备份状态。

更多信息请参阅:配置:PGSQL - PG_MONITOR


etcd

etcd 是分布式一致性存储(DCS),为 Patroni 提供集群元数据存储与领导者选举能力。

etcd 由独立的 ETCD 模块 部署管理,不属于 PGSQL 模块本身,但对 PostgreSQL 高可用至关重要。 Patroni 将集群状态、领导者信息、配置参数写入 etcd,所有节点通过 etcd 达成共识。 vip-manager 也从 etcd 读取领导者键,实现 VIP 的自动漂移。

更多信息请参阅:ETCD 模块


vector

Vector 是高性能日志采集组件,由 NODE 模块 部署,负责收集 PostgreSQL 相关日志。

Vector 常驻在节点上,跟踪 PostgreSQLPgbouncerPatronipgBackRest 的日志目录, 将结构化日志发送至 INFRA 节点上的 VictoriaLogs 进行集中存储与查询。

更多信息请参阅:NODE 模块

2 - 集群模型图

Pigsty 是如何将不同种类的功能抽象成为模块的,以及这些模块的逻辑模型,实体关系图。

在 Pigsty 中最大的实体概念叫做 部署(Deployment),一套部署中的主要实体与关系(E-R 图)如下所示:

一套部署也可以理解为一个 环境(Environment)。例如,生产环境(Prod),用户测试环境(UTA),预发环境(Staging),测试环境(Testing),开发环境(Devbox),等等。 每个环境中,都对应着一份 Pigsty 配置清单,描述了环境中的所有实体与属性。

通常来说,一套环境中也会带有一套共用的基础设施(INFRA),广义的基础设施还包括 ETCD(高可用 DCS)以及 MINIO(集中式备份仓库), 同时供环境中的多套 PostgreSQL 数据库集群(以及其他数据库模块组件)使用。(例外:也有 不带基础设施的部署

在 Pigsty 中,几乎所有数据库模块都是以 “集群"(Cluster)的方式组织起来的。每一个集群都是一个 Ansible 分组,包含有若干节点资源。 例如 PostgreSQL 高可用数据库集群,Redis,Etcd / MinIO 这些数据库都是以集群的形式存在。一套环境中可以包含多个集群。

2.1 - PGSQL 集群模型

介绍 Pigsty 中 PostgreSQL 集群的实体-关系模型,E-R 关系图,实体释义与命名规范。

PGSQL 模块在生产环境中以集群的形式组织,这些集群是由一组由主-备关联的数据库实例组成的逻辑实体

每个集群都是一个自治的业务单元,由至少一个 主库实例 组成,并通过服务向外暴露能力。

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

  • 集群(Cluster):自治的 PostgreSQL 业务单元,用作其他实体的顶级命名空间。
  • 服务(Service):对外暴露能力的命名抽象,路由流量,并使用节点端口暴露服务。
  • 实例(Instance):由在单个节点上的运行进程和数据库文件组成的单一 PostgreSQL 服务器。
  • 节点(Node):运行 Linux + Systemd 环境的硬件资源抽象,可以是裸机、VM、容器或 Pod。

辅以“数据库”“角色”两个业务实体,共同组成完整的逻辑视图。如下图所示:

er-pgsql


具体样例

让我们来看两个具体的例子,以四节点的 Pigsty 沙箱环境 为例,在这个环境中,有一套三节点的 pg-test 集群。

    pg-test:
      hosts:
        10.10.10.11: { pg_seq: 1, pg_role: primary }
        10.10.10.12: { pg_seq: 2, pg_role: replica }
        10.10.10.13: { pg_seq: 3, pg_role: replica }
      vars: { pg_cluster: pg-test }

上面的配置片段定义了一个如下所示的 高可用 PostgreSQL 集群,该集群中的相关实体包括:

集群Cluster
pg-testPostgreSQL 3 节点高可用集群
实例Instance
pg-test-11 号 PostgreSQL 实例,默认为主库
pg-test-22 号 PostgreSQL 实例,初始为从库
pg-test-33 号 PostgreSQL 实例,初始为从库
服务Service
pg-test-primary读写服务(路由到主库 pgbouncer)
pg-test-replica只读服务(路由到从库 pgbouncer)
pg-test-default直连读写服务(路由到主库 postgres)
pg-test-offline离线读取服务(路由到专用 postgres)
节点Nodes
node-110.10.10.11 1 号节点,对应 pg-test-1 PG 实例
node-210.10.10.12 2 号节点,对应 pg-test-2 PG 实例
node-310.10.10.13 3 号节点,对应 pg-test-3 PG 实例

ha


身份参数

Pigsty 使用 PG_ID 参数组为 PGSQL 模块的每个实体赋予确定的身份。以下三项为必选参数:

参数类型级别说明形式
pg_clusterstring集群PG 集群名称,必选身份参数有效的 DNS 名称,满足正则表达式 [a-zA-Z0-9-]+
pg_seqint实例PG 实例编号,必选身份参数自然数,可从 0 或 1 开始分配,集群内不重复
pg_roleenum实例PG 实例角色,必选身份参数枚举值,可为 primaryreplicaoffline

只要在集群层面定义了集群名称,实例层面分配了实例编号与角色,Pigsty 就能自动根据规则为每个实体生成唯一标识符。

实体生成规则示例
实例{{ pg_cluster }}-{{ pg_seq }}pg-test-1pg-test-2pg-test-3
服务{{ pg_cluster }}-{{ pg_role }}pg-test-primarypg-test-replicapg-test-offline
节点显示指定覆盖,或自动从 PG 实例借用pg-test-1pg-test-2pg-test-3

因为 Pigsty 采用节点与 PG 实例 1:1 的独占部署模型,因此默认情况下,主机节点的标识符会直接借用 PG 实例的标识符(node_id_from_pg)。 当然您也可以显式指定 nodename 进行覆盖,或者关闭 nodename_overwrite,直接使用当前默认值。


分片身份参数

当你使用多套 PostgreSQL (分片 / Sharding)集群服务同一业务时,还会使用到另外两个身份参数:pg_shardpg_group

在这种情况下,这一组 PostgreSQL 集群将拥有相同的 pg_shard 名称,以及各自的 pg_group 编号,例如下面的 Citus 集群

在这种情况下,pg_cluster 集群名通常由:{{ pg_shard }}{{ pg_group }} 组合而成,例如 pg-citus0pg-citus1 等。

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 } }
      vars: { pg_cluster: pg-citus3 , pg_group: 3 }

Pigsty 专门为水平分片集群提供专门的监控面板,便于对比各分片的性能与负载情况,但这需要您使用上述实体命名规则。

还有一些其他的身份参数,可能在特殊场景会使用到,例如,指定备份集群/级联复制上游的 pg_upstream,指定 Greenplum 集群身份的 gp_role, 指定外部监控实例的 pg_exporters,指定实例为离线查询库的 pg_offline_query 等,请参考 PG_ID 参数文档


监控标签体系

Pigsty 提供了一套开箱即用的监控系统,在这个系统中使用上面的 身份参数 来标识各个 PostgreSQL 实体对象。

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"}

例如,上面的 clsinsip 三个标签,分别对应集群名、实例名与节点 IP,这三个核心实体的标识符。 它们与 job 标签,在 所有 VictoriaMetrics 采集的原生监控指标,以及 VictoriaLogs 日志流中都会出现并可用。

采集 PostgreSQL 指标的 job 名固定为 pgsql; 用于监控远程 PG 实例的 job 名固定为 pgrds。 采集 PostgreSQL CSV 日志的 job 名固定为 postgres; 采集 pgbackrest 日志的 job 名固定为 pgbackrest,其余 PG 组件通过 job: syslog 采集日志。

此外,还有一些普通实体身份标签,会在实体相关的特定监控指标中出现,例如:

  • datname: 数据库名,如果一个监控指标属于某个具体的数据库,则会带上这个标签。
  • relname: 表名,如果一个监控指标属于某个具体的表,则会带上这个标签。
  • idxname: 索引名,如果一个监控指标属于某个具体的索引,则会带上这个标签。
  • funcname: 函数名,如果一个监控指标属于某个具体的函数,则会带上这个标签。
  • seqname: 序列名,如果一个监控指标属于某个具体的序列,则会带上这个标签。
  • query: 查询指纹,如果一个监控指标属于某个具体的查询,则会带上这个标签。

2.2 - ETCD 集群模型

介绍 Pigsty 中 ETCD 集群的实体-关系模型,E-R 关系图,实体释义与命名规范。

ETCD 模块在生产环境中以集群的形式组织,这些集群是由一组通过 Raft 共识协议关联的 ETCD 实例组成的逻辑实体

每个集群都是一个自治的分布式键值存储单元,由至少一个 ETCD 实例 组成,通过客户端端口向外暴露服务能力。

在 Pigsty 的 ETCD 模块中有三种核心实体:

  • 集群(Cluster):自治的 ETCD 服务单元,用作其他实体的顶级命名空间。
  • 实例(Instance):单个 ETCD 服务器进程,在节点上运行,参与 Raft 共识。
  • 节点(Node):运行 Linux + Systemd 环境的硬件资源抽象,隐含式声明。

相比于 PostgreSQL 集群,ETCD 集群模型更为简单,没有服务(Service)和复杂的角色(Role)区分。 所有 ETCD 实例在功能上是对等的,通过 Raft 协议选举出 Leader,其余为 Follower。 在扩容的中间状态,还允许不参与投票的 Learner 实例成员存在。


具体样例

让我们来看一个具体的例子,以三节点的 ETCD 集群为例:

etcd:
  hosts:
    10.10.10.10: { etcd_seq: 1 }
    10.10.10.11: { etcd_seq: 2 }
    10.10.10.12: { etcd_seq: 3 }
  vars:
    etcd_cluster: etcd

上面的配置片段定义了一个如下所示的三节点 ETCD 集群,该集群中的相关实体包括:

集群Cluster
etcdETCD 三节点高可用集群
实例Instance
etcd-11 号 ETCD 实例
etcd-22 号 ETCD 实例
etcd-33 号 ETCD 实例
节点Nodes
10.10.10.101 号节点,对应 etcd-1 实例
10.10.10.112 号节点,对应 etcd-2 实例
10.10.10.123 号节点,对应 etcd-3 实例

身份参数

Pigsty 使用 ETCD 参数组为 ETCD 模块的每个实体赋予确定的身份。以下两项为必选参数:

参数类型级别说明形式
etcd_clusterstring集群ETCD 集群名称,必选身份参数有效的 DNS 名称,默认为固定值 etcd
etcd_seqint实例ETCD 实例编号,必选身份参数自然数,从 1 开始分配,集群内不重复

只要在集群层面定义了集群名称,实例层面分配了实例编号,Pigsty 就能自动根据规则为每个实体生成唯一标识符。

实体生成规则示例
实例{{ etcd_cluster }}-{{ etcd_seq }}etcd-1etcd-2etcd-3

ETCD 模块不会为主机节点赋予额外的身份标识,节点使用其原有的主机名或 IP 地址进行标识。


端口协议

每个 ETCD 实例会监听以下两个端口:

端口参数用途
2379etcd_port客户端端口,供 Patroni、vip-manager 等客户端访问
2380etcd_peer_port节点间通信端口,用于 Raft 共识协议

ETCD 集群默认启用 TLS 加密通信,并使用 RBAC 认证机制。客户端需要使用正确的证书和密码才能访问 ETCD 服务。


集群规模

ETCD 作为分布式协调服务,集群规模直接影响其可用性,需要有超过半数(仲裁数)的节点存活才能维持服务。

集群规模仲裁数容忍故障数适用场景
1 节点10开发、测试、演示
3 节点21中小规模生产环境
5 节点32大规模生产环境

因此,偶数节点的 ETCD 集群没有意义,超过五节点的 ETCD 集群并不常见,因此通常使用的规格就是单节点、三节点、五节点。


监控标签体系

Pigsty 提供了一套开箱即用的监控系统,在这个系统中使用上面的 身份参数 来标识各个 ETCD 实体对象。

etcd_up{cls="etcd", ins="etcd-1", ip="10.10.10.10", job="etcd"}
etcd_up{cls="etcd", ins="etcd-2", ip="10.10.10.11", job="etcd"}
etcd_up{cls="etcd", ins="etcd-3", ip="10.10.10.12", job="etcd"}

例如,上面的 clsinsip 三个标签,分别对应集群名、实例名与节点 IP,这三个核心实体的标识符。 它们与 job 标签,在 所有 VictoriaMetrics 采集的 ETCD 监控指标中都会出现并可用。 采集 ETCD 指标的 job 名固定为 etcd

2.3 - MINIO 集群模型

介绍 Pigsty 中 MinIO 集群的实体-关系模型,E-R 关系图,实体释义与命名规范。

MinIO 模块在生产环境中以集群的形式组织,这些集群是由一组分布式 MinIO 实例组成的逻辑实体,共同提供高可用的对象存储服务。

每个集群都是一个自治的 S3 兼容对象存储单元,由至少一个 MinIO 实例 组成,通过 S3 API 端口向外暴露服务能力。

在 Pigsty 的 MinIO 模块中有三种核心实体:

  • 集群(Cluster):自治的 MinIO 服务单元,用作其他实体的顶级命名空间。
  • 实例(Instance):单个 MinIO 服务器进程,在节点上运行,管理本地磁盘存储。
  • 节点(Node):运行 Linux + Systemd 环境的硬件资源抽象,隐含式声明。

此外,MinIO 还有 存储池(Pool)的概念,用于集群平滑扩容。 一个集群可以包含多个存储池,每个存储池由一组节点和磁盘组成。


部署模式

MinIO 支持三种主要部署模式,适用于不同的场景:

模式代号说明适用场景
单机单盘SNSD单节点,单个数据目录,或单块磁盘开发、测试、演示
单机多盘SNMD单节点,使用多块磁盘,通常至少 4 块盘资源受限的小规模部署
多机多盘MNMD多节点,每节点多块磁盘生产环境推荐

单机单盘模式可以使用任意目录作为存储,适合快速体验;单机多盘和多机多盘模式需要使用真实的磁盘挂载点,否则会拒绝启动。


具体样例

让我们来看一个多机多盘模式的具体例子,以四节点的 MinIO 集群为例:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
    10.10.10.13: { minio_seq: 4 }
  vars:
    minio_cluster: minio
    minio_data: '/data{1...4}'
    minio_node: '${minio_cluster}-${minio_seq}.pigsty'

上面的配置片段定义了一个四节点的 MinIO 集群,每个节点使用四块磁盘,该集群中的相关实体包括:

集群Cluster
minioMinIO 四节点高可用集群
实例Instance
minio-11 号 MinIO 实例,管理 4 块磁盘
minio-22 号 MinIO 实例,管理 4 块磁盘
minio-33 号 MinIO 实例,管理 4 块磁盘
minio-44 号 MinIO 实例,管理 4 块磁盘
节点Nodes
10.10.10.101 号节点,对应 minio-1 实例
10.10.10.112 号节点,对应 minio-2 实例
10.10.10.123 号节点,对应 minio-3 实例
10.10.10.134 号节点,对应 minio-4 实例

身份参数

Pigsty 使用 MINIO 参数组为 MinIO 模块的每个实体赋予确定的身份。以下两项为必选参数:

参数类型级别说明形式
minio_clusterstring集群MinIO 集群名称,必选身份参数有效的 DNS 名称,默认为 minio
minio_seqint实例MinIO 实例编号,必选身份参数自然数,从 1 开始分配,集群内不重复

只要在集群层面定义了集群名称,实例层面分配了实例编号,Pigsty 就能自动根据规则为每个实体生成唯一标识符。

实体生成规则示例
实例{{ minio_cluster }}-{{ minio_seq }}minio-1minio-2minio-3minio-4

MinIO 模块不会为主机节点赋予额外的身份标识,节点使用其原有的主机名或 IP 地址进行标识。 minio_node 参数用于生成 MinIO 集群内部的节点名称(写入 /etc/hosts 供集群发现使用),而非主机节点的身份。


核心配置参数

除身份参数外,以下参数对 MinIO 集群配置至关重要:

参数类型说明
minio_datapath数据目录,使用 {x...y} 指定多盘
minio_nodestring节点名模式,用于多节点部署
minio_domainstring服务域名,默认为 sss.pigsty

这些参数共同决定了 MinIO 的核心配置 MINIO_VOLUMES

  • 单机单盘:直接使用 minio_data 的值,如 /data/minio
  • 单机多盘:使用 minio_data 展开的多个目录,如 /data{1...4}
  • 多机多盘:组合 minio_nodeminio_data,如 https://minio-{1...4}.pigsty:9000/data{1...4}

端口与服务

每个 MinIO 实例会监听以下端口:

端口参数用途
9000minio_portS3 API 服务端口
9001minio_admin_portWeb 管理控制台端口

MinIO 默认启用 HTTPS 加密通信(由 minio_https 控制)。这对于 pgBackREST 等备份工具访问 MinIO 是必需的。

多节点 MinIO 集群可以通过访问 任意一个节点 来访问其服务。最佳实践是使用负载均衡器(如 HAProxy + VIP)统一接入点。


资源置备

MinIO 集群部署后,Pigsty 会自动创建以下资源(由 minio_provision 控制):

默认存储桶(由 minio_buckets 定义):

存储桶用途
pgsqlPostgreSQL pgBackREST 备份存储
meta元数据存储,启用版本控制
data通用数据存储

默认用户(由 minio_users 定义):

用户默认密码策略用途
pgbackrestS3User.BackuppgsqlPostgreSQL 备份专用用户
s3user_metaS3User.Metameta访问 meta 存储桶
s3user_dataS3User.Datadata访问 data 存储桶

这些密码属于文档公开的 默认凭据,仅供演示与本地开发使用,生产部署前必须替换。

pgbackrest 是 PostgreSQL 集群备份时使用的用户,s3user_metas3user_data 是未实际使用的保留用户。


监控标签体系

Pigsty 提供了一套开箱即用的监控系统,在这个系统中使用上面的 身份参数 来标识各个 MinIO 实体对象。

minio_up{cls="minio", ins="minio-1", ip="10.10.10.10", job="minio"}
minio_up{cls="minio", ins="minio-2", ip="10.10.10.11", job="minio"}
minio_up{cls="minio", ins="minio-3", ip="10.10.10.12", job="minio"}
minio_up{cls="minio", ins="minio-4", ip="10.10.10.13", job="minio"}

例如,上面的 clsinsip 三个标签,分别对应集群名、实例名与节点 IP,这三个核心实体的标识符。 它们与 job 标签,在 所有 VictoriaMetrics 采集的 MinIO 监控指标中都会出现并可用。 采集 MinIO 指标的 job 名固定为 minio

2.4 - REDIS 集群模型

介绍 Pigsty 中 Redis 集群的实体-关系模型,E-R 关系图,实体释义与命名规范。

Redis 模块在生产环境中以集群的形式组织,这些集群是由一组 Redis 实例组成的逻辑实体,部署在一个或多个节点上。

每个集群都是一个自治的高性能缓存/存储单元,由至少一个 Redis 实例 组成,通过端口向外暴露服务能力。

在 Pigsty 的 Redis 模块中有三种核心实体:

  • 集群(Cluster):自治的 Redis 服务单元,用作其他实体的顶级命名空间。
  • 实例(Instance):单个 Redis 服务器进程,在节点上的特定端口运行。
  • 节点(Node):运行 Linux + Systemd 环境的硬件资源抽象,可以承载多个 Redis 实例,隐含式声明。

与 PostgreSQL 不同,Redis 采用 单机多实例 的部署模型:一个物理/虚拟机节点上通常会部署 多个 Redis 实例, 以充分利用多核 CPU。因此,节点与实例是 1:N 的关系。此外,生产中通常不建议设置单个内存规模大于 12GB 的 Redis 实例。


工作模式

Redis 有三种不同的工作模式,由 redis_mode 参数指定:

模式代号说明高可用机制
主从模式standalone经典主从复制,默认模式需配合 Sentinel 实现
哨兵模式sentinel为主从模式提供高可用监控与自动故障转移本身的多节点仲裁
原生集群模式clusterRedis 原生分布式集群,无需哨兵即可高可用内置自动故障转移
  • 主从模式:默认模式,通过 replica_of 参数设置主从复制关系。需要额外的 Sentinel 集群提供高可用。
  • 哨兵模式:不存储业务数据,专门用于监控主从模式的 Redis 集群,实现自动故障转移,本身多节点即可高可用。
  • 原生集群模式:数据自动分片到多个主节点,每个主节点可以有多个从节点,内置高可用能力,无需哨兵支持。

具体样例

让我们来看三种模式的具体例子:

主从集群

一个节点上部署一主一从的经典主从集群:

redis-ms:
  hosts:
    10.10.10.10:
      redis_node: 1
      redis_instances:
        6379: { }
        6380: { replica_of: '10.10.10.10 6379' }
  vars:
    redis_cluster: redis-ms
    redis_password: 'redis.ms'
    redis_max_memory: 64MB
集群Cluster
redis-msRedis 主从集群
节点Nodes
redis-ms-110.10.10.10 1 号节点,承载 2 个实例
实例Instance
redis-ms-1-6379主库实例,监听 6379 端口
redis-ms-1-6380从库实例,监听 6380 端口,复制自 6379

哨兵集群

一个节点上部署三个哨兵实例,用于监控主从集群。哨兵集群通过 redis_sentinel_monitor 参数指定要监控的主从集群列表:

redis-sentinel:
  hosts:
    10.10.10.11:
      redis_node: 1
      redis_instances: { 26379: {}, 26380: {}, 26381: {} }
  vars:
    redis_cluster: redis-sentinel
    redis_password: 'redis.sentinel'
    redis_mode: sentinel
    redis_max_memory: 16MB
    redis_sentinel_monitor:
      - { name: redis-ms, host: 10.10.10.10, port: 6379, password: redis.ms, quorum: 2 }

原生集群

下面的配置片段定义了由两个节点,六个实例组成的 Redis 原生分布式集群(最小规格,3主3从):

redis-test:
  hosts:
    10.10.10.12: { redis_node: 1, redis_instances: { 6379: {}, 6380: {}, 6381: {} } }
    10.10.10.13: { redis_node: 2, redis_instances: { 6379: {}, 6380: {}, 6381: {} } }
  vars:
    redis_cluster: redis-test
    redis_password: 'redis.test'
    redis_mode: cluster
    redis_max_memory: 32MB

该配置将创建一个 3 主 3 从 的原生 Redis 集群。

集群Cluster
redis-testRedis 原生集群(3 主 3 从)
实例Instance
redis-test-1-6379节点 1 上的实例,监听 6379 端口
redis-test-1-6380节点 1 上的实例,监听 6380 端口
redis-test-1-6381节点 1 上的实例,监听 6381 端口
redis-test-2-6379节点 2 上的实例,监听 6379 端口
redis-test-2-6380节点 2 上的实例,监听 6380 端口
redis-test-2-6381节点 2 上的实例,监听 6381 端口
节点Nodes
redis-test-110.10.10.12 1 号节点,承载 3 个实例
redis-test-210.10.10.13 2 号节点,承载 3 个实例

身份参数

Pigsty 使用 REDIS 参数组为 Redis 模块的每个实体赋予确定的身份。以下三项为必选参数:

参数类型级别说明形式
redis_clusterstring集群Redis 集群名称,必选身份参数有效的 DNS 名称,满足 [a-z][a-z0-9-]*
redis_nodeint节点Redis 节点编号,必选身份参数自然数,从 1 开始分配,集群内不重复
redis_instancesdict节点Redis 实例定义,必选身份参数JSON 对象,Key 为端口号,Value 为实例配置

只要在集群层面定义了集群名称,节点层面分配了节点编号与实例定义,Pigsty 就能自动根据规则为每个实体生成唯一标识符。

实体生成规则示例
实例{{ redis_cluster }}-{{ redis_node }}-{{ port }}redis-ms-1-6379redis-ms-1-6380

Redis 模块不会为主机节点赋予额外的身份标识,节点使用其原有的主机名或 IP 地址进行标识。 redis_node 参数用于实例命名,而非主机节点的身份。


实例定义

redis_instances 是一个 JSON 对象,Key 为 端口号,Value 为该实例的 配置项

redis_instances:
  6379: { }                                      # 主库实例,无需额外配置
  6380: { replica_of: '10.10.10.10 6379' }       # 从库实例,指定上游主库
  6381: { replica_of: '10.10.10.10 6379' }       # 从库实例,指定上游主库

每个 Redis 实例会监听一个唯一的端口,端口在节点上唯一不重复,您可以任意选择端口号, 但请不要使用系统保留端口(小于 1024),或者与 Pigsty 使用的端口 冲突。 实例配置中的 replica_of 参数用于在主从模式下设置复制关系,格式为 '<ip> <port>',用于指定一个 Redis 从库的上游主库地址与端口。

此外,每个 Redis 节点上会运行一个 Redis Exporter,用于汇总采集当前节点上 所有本地实例 的监控指标:

端口参数用途
9121redis_exporter_portRedis Exporter 端口

Redis 模块的单机多实例部署模型带有一些局限性:

  • 节点独占:一个节点只能属于一个 Redis 集群,不能同时分配给不同的 Redis 集群。
  • 端口唯一:同一节点上的 Redis 实例必须使用不同的端口号,避免端口冲突。
  • 密码共享:同一节点上的多个 Redis 实例无法设置不同的密码(受 redis_exporter 限制)。
  • 手动高可用:主从模式的 Redis 集群需要额外配置 Sentinel 才能实现自动故障转移。

监控标签体系

Pigsty 提供了一套开箱即用的监控系统,在这个系统中使用上面的 身份参数 来标识各个 Redis 实体对象。

redis_up{cls="redis-ms", ins="redis-ms-1-6379", ip="10.10.10.10", job="redis"}
redis_up{cls="redis-ms", ins="redis-ms-1-6380", ip="10.10.10.10", job="redis"}

例如,上面的 clsinsip 三个标签,分别对应集群名、实例名与节点 IP,这三个核心实体的标识符。 它们与 job 标签,在 所有 VictoriaMetrics 采集的 Redis 监控指标中都会出现并可用。 采集 Redis 指标的 job 名固定为 redis

2.5 - INFRA 集群模型

介绍 Pigsty 中 INFRA 基础设施节点的实体-关系模型,组件构成与命名规范。

INFRA 模块在 Pigsty 中承担着特殊的角色:它不是传统意义上的"集群",而是由一组 基础设施节点 构成的管理中枢,为整个 Pigsty 部署提供核心服务。 每个 INFRA 节点都是一个自治的基础设施服务单元,运行着 Nginx、Grafana、VictoriaMetrics 等核心组件,共同为纳管的数据库集群提供可观测性与管理能力。

在 Pigsty 的 INFRA 模块中有两种核心实体:

  • 节点(Node):运行基础设施组件的服务器,可以是裸机、VM、容器或 Pod。
  • 组件(Component):在节点上运行的各类基础设施服务,如 Nginx、Grafana、VictoriaMetrics 等。

INFRA 节点通常承担管理节点(Admin Node)的角色,是 Pigsty 的控制平面所在。


组件构成

每个 INFRA 节点上运行着以下核心组件:

组件端口说明
Nginx80/443Web 服务门户,本地软件仓库,统一反向代理入口
Grafana3000可视化平台,监控大屏,巡检与数据应用
VictoriaMetrics8428时序数据库,兼容 Prometheus API
VictoriaLogs9428日志数据库,接收 Vector 推送的结构化日志
VictoriaTraces10428链路追踪存储,用于慢 SQL / 请求追踪
VMAlert8880告警规则评估器,基于 VictoriaMetrics 触发告警
Alertmanager9059告警聚合与分发
Blackbox Exporter9115ICMP/TCP/HTTP 黑盒探测
DNSMASQ53DNS 服务器,提供内部域名解析
Chronyd123NTP 时间服务器

这些组件共同构成了 Pigsty 的可观测性基础设施。


具体样例

让我们来看一个具体的例子,以双节点的 INFRA 部署为例:

infra:
  hosts:
    10.10.10.10: { infra_seq: 1 }
    10.10.10.11: { infra_seq: 2 }

上面的配置片段定义了一个双节点的 INFRA 部署:

分组Group
infraINFRA 基础设施节点分组
节点Nodes
infra-110.10.10.10 1 号 INFRA 节点
infra-210.10.10.11 2 号 INFRA 节点

在生产环境中,建议部署至少两个 INFRA 节点,以实现基础设施组件的冗余。


身份参数

Pigsty 使用 INFRA_ID 参数组为 INFRA 模块的每个实体赋予确定的身份。以下一项为必选参数:

参数类型级别说明形式
infra_seqint节点INFRA 节点序号,必选身份参数自然数,从 1 开始分配,分组内不重复

只要在节点层面分配了节点序号,Pigsty 就能自动根据规则为每个实体生成唯一标识符。

实体生成规则示例
节点infra-{{ infra_seq }}infra-1infra-2

INFRA 模块会为节点赋予 infra-N 形式的标识,用于监控系统中区分多个基础设施节点。 但这并不改变节点本身的主机名或系统身份,节点仍然使用其原有的主机名或 IP 地址进行标识。


服务门户

INFRA 节点通过 Nginx 提供统一的 Web 服务入口。infra_portal 参数定义了通过 Nginx 暴露的服务列表。

默认配置只定义了首页服务器:

infra_portal:
  home : { domain: i.pigsty }

Pigsty 会自动为启用的组件(如 Grafana、VictoriaMetrics、AlertManager 等)配置反向代理端点。如果需要通过独立域名访问这些服务,可以显式添加配置:

infra_portal:
  home         : { domain: i.pigsty }
  grafana      : { domain: g.pigsty, endpoint: "${admin_ip}:3000", websocket: true }
  prometheus   : { domain: p.pigsty, endpoint: "${admin_ip}:8428" }   # VMUI
  alertmanager : { domain: a.pigsty, endpoint: "${admin_ip}:9059" }
域名服务说明
i.pigstyHomePigsty 首页
g.pigstyGrafana监控可视化平台
p.pigstyVictoriaMetrics时序数据库 Web UI
a.pigstyAlertmanager告警管理界面

建议通过域名访问 Pigsty 服务,而不是直接使用 IP + 端口的方式。


部署规模

INFRA 节点的数量取决于部署规模和高可用需求:

部署规模INFRA 节点数说明
开发测试1单节点部署,所有组件在同一节点
小规模生产1-2单节点或双节点,可与其他服务共用节点
中规模生产2-3独立的 INFRA 节点,组件冗余部署
大规模生产3+多 INFRA 节点,可根据组件分离部署

单机部署 时,INFRA 组件与 PGSQL、ETCD 等模块共用同一个节点。 通常在小规模部署中,INFRA 节点通常还承担着 “管理节点” / “备用管理节点”,以及本地软件仓库(/www/pigsty)的角色。 在更大规模的部署中,这些职责可以剥离至专用节点。


监控标签体系

Pigsty 的监控系统会采集 INFRA 组件自身的指标。与数据库模块不同,INFRA 模块的每个组件都被视为独立的监控对象,通过 cls(类)标签区分不同组件类型。

标签说明示例
cls组件类型,每种组件各自构成一个"类"nginx
ins实例名,格式为 {组件类型}-{infra_seq}nginx-1
ip运行该组件的 INFRA 节点 IP 地址10.10.10.10
jobVictoriaMetrics 采集任务名,固定为 infrainfra

以双节点 INFRA 部署(infra_seq: 1infra_seq: 2)为例,各组件的监控标签如下:

组件clsins 示例端口
Nginxnginxnginx-1nginx-29113
Grafanagrafanagrafana-1grafana-23000
VictoriaMetricsvmetricsvmetrics-1vmetrics-28428
VictoriaLogsvlogsvlogs-1vlogs-29428
VictoriaTracesvtracesvtraces-1vtraces-210428
VMAlertvmalertvmalert-1vmalert-28880
Alertmanageralertmanageralertmanager-1alertmanager-29059
Blackboxblackboxblackbox-1blackbox-29115

所有 INFRA 组件的监控指标都使用统一的 job="infra" 标签,通过 cls 标签区分组件类型:

nginx_up{cls="nginx", ins="nginx-1", ip="10.10.10.10", job="infra"}
grafana_info{cls="grafana", ins="grafana-1", ip="10.10.10.10", job="infra"}
vm_app_version{cls="vmetrics", ins="vmetrics-1", ip="10.10.10.10", job="infra"}
vlogs_rows_ingested_total{cls="vlogs", ins="vlogs-1", ip="10.10.10.10", job="infra"}
alertmanager_alerts{cls="alertmanager", ins="alertmanager-1", ip="10.10.10.10", job="infra"}

3 - 声明式配置 —— 基础设施即代码(IaC)

Pigsty 使用基础设施即代码(IaC)的理念管理所有组件,针对大规模集群提供声明式管理能力。

Pigsty 遵循 IaC 与 GitOPS 的理念:使用声明式的 配置清单 描述整个环境,并通过 幂等剧本 来实现。

用户用声明的方式通过 参数 来描述自己期望的状态,而剧本则以幂等的方式调整目标节点以达到这个状态。 这类似于 Kubernetes 的 CRD & Operator,然而 Pigsty 在裸机和虚拟机上,通过 Ansible 实现了这样的功能。

Pigsty 诞生之初是为了解决超大规模 PostgreSQL 集群的运维管理问题,背后的想法很简单 —— 我们需要有在十分钟内在就绪的服务器上复刻整套基础设施(100+数据库集群 + PG/Redis + 可观测性)的能力。 任何 GUI + ClickOps 都无法在如此短的时间内完成如此复杂的任务,这让 CLI + IaC 成为唯一的选择 —— 它提供了精确,高效的控制能力。

配置清单 pigsty.yml 文件描述了整个部署的状态,无论是 生产环境(prod),预发环境(staging), 测试环境(test),还是 开发环境(devbox), 基础设施的区别仅在于配置清单的不同,而部署交付的逻辑则是完全相同的。

您可以使用 git 对这份部署的 “种子/基因” 进行版本控制与审计,而且,Pigsty 甚至支持将配置清单以数据库表的形式存储在 PostgreSQL CMDB 中, 更进一步从 Infra as Code 升级为 Infra as Data,无缝与您现有的工作流程集成与对接。

IaC 面向专业用户与企业场景而设计,但也针对个人开发者,SMB 进行了深度优化。 即使您并非专业 DBA,也无需了解这几百个调节开关与旋钮,所有参数都带有表现良好的默认值, 您完全可以在 零配置 的情况下,获得一个开箱即用的单机数据库节点; 简单地再添加两行 IP 地址,就能获得一套企业级的高可用的 PostgreSQL 集群。


声明模块

以下面的默认配置片段为例,这段配置描述了一个节点 10.10.10.10,其上安装了 INFRANODEETCDPGSQL 模块。

# 监控、告警、DNS、NTP 等基础设施集群...
infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

# minio 集群,兼容 s3 的对象存储
minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

# etcd 集群,用作 PostgreSQL 高可用所需的 DCS
etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

# PGSQL 示例集群: pg-meta
pg-meta: { hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary }, vars: { pg_cluster: pg-meta } }

要真正安装这些模块,执行以下剧本:

./infra.yml -l 10.10.10.10  # 在节点 10.10.10.10 上初始化 infra 模块
./etcd.yml  -l 10.10.10.10  # 在节点 10.10.10.10 上初始化 etcd 模块
./minio.yml -l 10.10.10.10  # 在节点 10.10.10.10 上初始化 minio 模块
./pgsql.yml -l 10.10.10.10  # 在节点 10.10.10.10 上初始化 pgsql 模块

声明集群

您可以声明 PostgreSQL 数据库集群,在多个节点上安装 PGSQL 模块,并使其成为一个服务单元:

例如,要在以下三个已被 Pigsty 纳管的节点上,部署一个使用流复制组建的三节点高可用 PostgreSQL 集群, 您可以在配置文件 pigsty.ymlall.children 中添加以下定义:

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 }

定义完后,可以使用 剧本 将集群创建:

bin/pgsql-add pg-test   # 创建 pg-test 集群 

pigsty-iac.jpg

你可以使用不同的实例角色,例如 主库(primary),从库(replica),离线从库(offline),延迟从库(delayed),同步备库(sync standby); 以及不同的集群:例如 备份集群(Standby Cluster),Citus 集群,甚至是 Redis / MinIO / Etcd 集群


定制集群内容

您不仅可以使用声明式的方式定义集群,还可以定义集群中的数据库、用户、服务、HBA 规则 等内容,例如,下面的配置文件对默认的 pg-meta 单节点数据库集群的内容进行了深度定制:

包括:声明了六个业务数据库与七个业务用户,添加了一个额外的 standby 服务(同步备库,提供无复制延迟的读取能力),定义了一些额外的 pg_hba 规则,一个指向集群主库的 L2 VIP 地址,与自定义的备份策略。

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary , pg_offline_query: true } }
  vars:
    pg_cluster: pg-meta
    pg_databases:                       # define business databases on this cluster, array of database definition
      - name: meta                      # REQUIRED, `name` is the only mandatory field of a database definition
        baseline: cmdb.sql              # optional, database sql baseline path, (relative path among ansible search path, e.g files/)
        pgbouncer: true                 # optional, add this database to pgbouncer database list? true by default
        schemas: [pigsty]               # optional, additional schemas to be created, array of schema names
        extensions:                     # optional, additional extensions to be installed: array of `{name[,schema]}`
          - { name: postgis , schema: public }
          - { name: timescaledb }
        comment: pigsty meta database   # optional, comment string for this database
        owner: postgres                # optional, database owner, postgres by default
        template: template1            # optional, which template to use, template1 by default
        encoding: UTF8                 # optional, database encoding, UTF8 by default. (MUST same as template database)
        locale: C                      # optional, database locale, C by default.  (MUST same as template database)
        lc_collate: C                  # optional, database collate, C by default. (MUST same as template database)
        lc_ctype: C                    # optional, database ctype, C by default.   (MUST same as template database)
        tablespace: pg_default         # optional, default tablespace, 'pg_default' by default.
        allowconn: true                # optional, allow connection, true by default. false will disable connect at all
        revokeconn: false              # optional, revoke public connection privilege. false by default. (leave connect with grant option to owner)
        register_datasource: true      # optional, register this database to grafana datasources? true by default
        connlimit: -1                  # optional, database connection limit, default -1 disable limit
        pool_auth_user: dbuser_meta    # optional, all connection to this pgbouncer database will be authenticated by this user
        pool_mode: transaction         # optional, pgbouncer pool mode at database level, default transaction
        pool_size: 64                  # optional, pgbouncer pool size at database level, default 64
        pool_reserve: 32          # optional, pgbouncer pool size reserve at database level, default 32
        pool_size_min: 0               # optional, pgbouncer pool size min at database level, default 0
        pool_connlimit: 100          # optional, max database connections at database level, default 100
      - { 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 }
    pg_users:                           # define business users/roles on this cluster, array of user definition
      - name: dbuser_meta               # REQUIRED, `name` is the only mandatory field of a user definition
        password: DBUser.Meta           # optional, password, can be a scram-sha-256 hash string or plain text
        login: true                     # optional, can log in, true by default  (new biz ROLE should be false)
        superuser: false                # optional, is superuser? false by default
        createdb: false                 # optional, can create database? false by default
        createrole: false               # optional, can create role? false by default
        inherit: true                   # optional, can this role use inherited privileges? true by default
        replication: false              # optional, can this role do replication? false by default
        bypassrls: false                # optional, can this role bypass row level security? false by default
        pgbouncer: true                 # optional, add this user to pgbouncer user-list? false by default (production user should be true explicitly)
        connlimit: -1                   # optional, user connection limit, default -1 disable limit
        expire_in: 3650                 # optional, now + n days when this role is expired (OVERWRITE expire_at)
        expire_at: '2030-12-31'         # optional, YYYY-MM-DD 'timestamp' when this role is expired  (OVERWRITTEN by expire_in)
        comment: pigsty admin user      # optional, comment string for this user/role
        roles: [dbrole_admin]           # optional, belonged roles. default roles are: dbrole_{admin,readonly,readwrite,offline}
        parameters: {}                  # optional, role level parameters with `ALTER ROLE SET`
        pool_mode: transaction          # optional, pgbouncer pool mode at user level, transaction by default
        pool_connlimit: -1              # optional, max database connections at user level, default -1 disable limit
      - {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    }
    pg_services:                        # extra services in addition to pg_default_services, array of service definition
      # standby service will route {ip|name}:5435 to sync replica's pgbouncer (5435->6432 standby)
      - name: standby                   # required, service name, the actual svc name will be prefixed with `pg_cluster`, e.g: pg-meta-standby
        port: 5435                      # required, service exposed port (work as kubernetes service node port mode)
        ip: "*"                         # optional, service bind ip address, `*` for all ip by default
        selector: "[]"                  # required, service member selector, use JMESPath to filter inventory
        dest: default                   # optional, destination port, default|postgres|pgbouncer|<port_number>, 'default' by default
        check: /sync                    # optional, health check url path, / by default
        backup: "[? pg_role == `primary`]"  # backup server selector
        maxconn: 3000                   # optional, max allowed front-end connection
        balance: roundrobin             # optional, haproxy load balance algorithm (roundrobin by default, other: 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'
    pg_hba_rules:
      - {user: dbuser_view , db: all ,addr: infra ,auth: pwd ,title: 'allow grafana dashboard access cmdb from infra nodes'}
    pg_vip_enabled: true
    pg_vip_address: 10.10.10.2/24
    pg_vip_interface: eth1
    node_crontab:  # make a full backup 1 am everyday
      - '00 01 * * * postgres /pg/bin/pg-backup full'

声明访问控制

您还可以通过声明式的配置,深度定制 Pigsty 的 访问控制 能力。例如下面的配置文件对 pg-meta 集群进行了深度安全定制:

使用三节点核心集群模板:crit.yml,确保数据一致性有限,故障切换数据零丢失。 启用了 L2 VIP,并将数据库与连接池的监听地址限制在了本地环回 IP + 内网 IP + VIP 三个特定地址。 模板强制启用了 Patroni API 与 Pgbouncer 的 SSL,并在 HBA 规则中强制要求使用 SSL 访问数据库集群。 同时还在 pg_libs 中启用了 $libdir/passwordcheck 扩展,来强制执行 密码强度策略

最后,还单独声明了一个 pg-meta-delay 集群,作为 pg-meta 在一个小时前的延迟镜像从库,用于紧急数据误删恢复。

pg-meta:      # 3 instance postgres cluster `pg-meta`
  hosts:
    10.10.10.10: { pg_seq: 1, pg_role: primary }
    10.10.10.11: { pg_seq: 2, pg_role: replica }
    10.10.10.12: { pg_seq: 3, pg_role: replica , pg_offline_query: true }
  vars:
    pg_cluster: pg-meta
    pg_conf: crit.yml
    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: [{name: postgis, schema: public}, {name: timescaledb}]}
    pg_default_service_dest: postgres
    pg_services:
      - { name: standby ,src_ip: "*" ,port: 5435 , dest: default ,selector: "[]" , backup: "[? pg_role == `primary`]" }
    pg_vip_enabled: true
    pg_vip_address: 10.10.10.2/24
    pg_vip_interface: eth1
    pg_listen: '${ip},${vip},${lo}'
    patroni_ssl_enabled: true
    pgbouncer_sslmode: require
    pgbackrest_method: minio
    pg_libs: 'timescaledb, $libdir/passwordcheck, pg_stat_statements, auto_explain' # add passwordcheck extension to enforce strong password
    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  ,expire_in: 7300                        ,comment: system superuser }
      - { name: replicator ,replication: true  ,expire_in: 7300 ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
      - { name: dbuser_dba   ,superuser: true  ,expire_in: 7300 ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
      - { name: dbuser_monitor ,roles: [pg_monitor] ,expire_in: 7300 ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }
    pg_default_hba_rules:             # postgres host-based auth rules by default
      - {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 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: 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' }

# OPTIONAL delayed cluster for pg-meta
pg-meta-delay:                    # delayed instance for pg-meta (1 hour ago)
  hosts: { 10.10.10.13: { pg_seq: 1, pg_role: primary, pg_upstream: 10.10.10.10, pg_delay: 1h } }
  vars: { pg_cluster: pg-meta-delay }

Citus 分布式集群

下面是一个四节点的 Citus 分布式集群的声明式配置:

all:
  children:
    pg-citus0: # citus coordinator, pg_group = 0
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0 , pg_group: 0 }
    pg-citus1: # citus data node 1
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1 , pg_group: 1 }
    pg-citus2: # citus data node 2
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus2 , pg_group: 2 }
    pg-citus3: # citus data node 3, with an extra replica
      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:                               # global parameters for all citus clusters
    pg_mode: citus                    # pgsql cluster mode: citus
    pg_shard: pg-citus                # citus shard name: pg-citus
    patroni_citus_db: meta            # citus distributed database name
    pg_dbsu_password: DBUser.Postgres # all dbsu password access for citus cluster
    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'  }

Redis 集群

下面给出了 Redis 主从集群、哨兵集群、以及 Redis Cluster 的声明配置样例

redis-ms: # redis classic primary & replica
  hosts: { 10.10.10.10: { redis_node: 1 , redis_instances: { 6379: { }, 6380: { replica_of: '10.10.10.10 6379' } } } }
  vars: { redis_cluster: redis-ms ,redis_password: 'redis.ms' ,redis_max_memory: 64MB }

redis-meta: # redis sentinel x 3
  hosts: { 10.10.10.11: { redis_node: 1 , redis_instances: { 26379: { } ,26380: { } ,26381: { } } } }
  vars:
    redis_cluster: redis-meta
    redis_password: 'redis.meta'
    redis_mode: sentinel
    redis_max_memory: 16MB
    redis_sentinel_monitor: # primary list for redis sentinel, use cls as name, primary ip:port
      - { name: redis-ms, host: 10.10.10.10, port: 6379 ,password: redis.ms, quorum: 2 }

redis-test: # redis native cluster: 3m x 3s
  hosts:
    10.10.10.12: { redis_node: 1 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
    10.10.10.13: { redis_node: 2 ,redis_instances: { 6379: { } ,6380: { } ,6381: { } } }
  vars: { redis_cluster: redis-test ,redis_password: 'redis.test' ,redis_mode: cluster, redis_max_memory: 32MB }

ETCD 集群

下面给出了一个三节点的 Etcd 集群声明式配置样例:

etcd: # dcs service for postgres/patroni ha consensus
  hosts:  # 1 node for testing, 3 or 5 for production
    10.10.10.10: { etcd_seq: 1 }  # etcd_seq required
    10.10.10.11: { etcd_seq: 2 }  # assign from 1 ~ n
    10.10.10.12: { etcd_seq: 3 }  # odd number please
  vars: # cluster level parameter override roles/etcd
    etcd_cluster: etcd  # mark etcd cluster name etcd
    etcd_safeguard: false # safeguard against purging
    etcd_clean: true # purge etcd during init process

MinIO 集群

下面给出了一个三节点的 MinIO 集群声明式配置样例:

minio:
  hosts:
    10.10.10.10: { minio_seq: 1 }
    10.10.10.11: { minio_seq: 2 }
    10.10.10.12: { minio_seq: 3 }
  vars:
    minio_cluster: minio
    minio_data: '/data{1...2}'          # 每个节点使用两块磁盘
    minio_node: '${minio_cluster}-${minio_seq}.pigsty' # 节点名称的模式
    haproxy_services:
      - name: minio                     # [必选] 服务名称,需要唯一
        port: 9002                      # [必选] 服务端口,需要唯一
        options:
          - option httpchk
          - option http-keep-alive
          - http-check send meth OPTIONS uri /minio/health/live
          - http-check expect status 200
        servers:
          - { name: minio-1 ,ip: 10.10.10.10 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-2 ,ip: 10.10.10.11 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }
          - { name: minio-3 ,ip: 10.10.10.12 , port: 9000 , options: 'check-ssl ca-file /etc/pki/ca.crt check port 9000' }

3.1 - 配置清单

使用声明式的配置文件描述你需要的基础设施与集群

每一套 Pigsty 部署都对应着一份 配置清单 (Inventory),描述了基础设施与数据库集群的关键属性。


配置文件

Pigsty 默认使用 Ansible YAML 配置格式, 使用一个单一 YAML 配置文件 pigsty.yml 作为配置清单。

~/pigsty
  ^---- pigsty.yml   # <---- 默认配置文件

您可以直接修改该配置文件来定制您的部署,或者使用 Pigsty 提供的 配置向导 configure 脚本自动生成合适的配置文件。


配置结构

配置清单使用标准的 Ansible YAML 配置格式,由两部分组成:全局参数all.vars)和多个 all.children)。

您可以在 all.children 中定义新集群,并使用全局变量描述基础设施:all.vars,它看起来像这样:

all:                  # 顶级对象:all
  vars: {...}         # 全局参数
  children:           # 组定义
    infra:            # 组定义:'infra'
      hosts: {...}        # 组成员:'infra'
      vars:  {...}        # 组参数:'infra'
    etcd:    {...}    # 组定义:'etcd'
    pg-meta: {...}    # 组定义:'pg-meta'
    pg-test: {...}    # 组定义:'pg-test'
    redis-test: {...} # 组定义:'redis-test'
    # ...

集群定义

每个 Ansible 组可能代表一个集群,可以是节点集群、PostgreSQL 集群、Redis 集群、Etcd 集群或 MinIO 集群等…

集群定义由两部分组成:集群成员hosts)与 集群参数vars)。 您可以在 <cls>.hosts 中定义集群成员,并在 <cls>.vars 中使用 配置参数 描述集群。 下面是一个 3 节点高可用 PostgreSQL 集群的定义示例:

all:
  children:    # ansible 组列表
    pg-test:   # ansible 组名
      hosts:   # ansible 组内实例(集群成员)
        10.10.10.11: { pg_seq: 1, pg_role: primary } # 主机 1
        10.10.10.12: { pg_seq: 2, pg_role: replica } # 主机 2
        10.10.10.13: { pg_seq: 3, pg_role: offline } # 主机 3
      vars:    # ansible 组变量(集群参数)
        pg_cluster: pg-test

集群级别的 vars (集群参数)将覆盖全局参数,实例级别的 vars 将覆盖集群参数和全局参数。


拆分配置

如果您的部署规模较大,或者希望更好地组织配置文件, 可以将配置清单 拆分为多个文件,便于管理与维护。

inventory/
├── hosts.yml              # 主机和集群定义
├── group_vars/
│   ├── all.yml            # 全局默认变量 (对应 all.vars)
│   ├── infra.yml          # infra 组变量
│   ├── etcd.yml           # etcd 组变量
│   └── pg-meta.yml        # pg-meta 集群变量
└── host_vars/
    ├── 10.10.10.10.yml    # 特定主机变量
    └── 10.10.10.11.yml

您可以将集群成员定义放在 hosts.yml 文件中,将集群层面的 配置参数 放在 group_vars 目录下的对应文件中。


切换配置

您可以在执行剧本的时候,通过 -i 参数,临时指定另外的配置清单文件。

./pgsql.yml -i another_config.yml
./infra.yml -i nginx_config.yml

此外,Ansible 支持多种配置方式,您可以使用本地 yaml|ini 配置文件,或者是 CMDB 与任意的动态配置脚本作为配置源。

在 Pigsty 中,我们通过 Pigsty 主目录中的 ansible.cfg 指定同目录下的 pigsty.yml 作为默认的 配置清单,您可按需修改。

[defaults]
inventory = pigsty.yml

此外,Pigsty 还支持使用 CMDB 元数据库 来存储配置清单,便于与现有系统对接整合。

3.2 - 配置向导

使用 configure 脚本根据当前环境自动生成推荐的配置文件。

Pigsty 提供了一个 configure 脚本作为 配置向导,它能根据当前环境,自动生成合适的 pigsty.yml 配置文件。

这是一个 可选 的脚本:如果您已经了解了如何配置 Pigsty,大可以直接编辑 pigsty.yml 配置文件,跳过向导。


快速开始

进入 pigsty 源码家目录中,执行 ./configure 即可自动运行配置向导。不带任何参数时,默认使用 meta 单节点配置模板:

cd ~/pigsty
./configure          # 交互式配置向导,自动检测环境并生成配置

该命令会以选定的模板为基础,检测当前节点的 IP 地址与区域,并生成适合当前环境的 pigsty.yml 配置文件。

功能说明

configure 脚本会根据环境与输入执行以下调整,并默认在 Pigsty 目录下生成 pigsty.yml 配置文件。

  • 检测当前节点 IP 地址,如果有多个 IP,则要求用户输入一个 首要的 IP 地址 作为当前节点的身份标识
  • 使用 IP 地址替换配置模板中的占位符 10.10.10.10,并将其配置为 admin_ip 参数的值。
  • 检测当前区域,将 region 设置为 default (全球默认仓库)或 china (使用中国镜像仓库)
  • 针对小微实例(vCPU < 4),为 node_tunepg_conf 参数使用 tiny 参数模板,优化资源使用。
  • 如果指定了 -v PG 大版本,将 pg_version 与模板中的 pg18-* 包组别名切换到对应大版本;mssqlpolarpg19 是固定内核模板,不执行该替换。
  • 如果指定了 -g 参数,将配置向导识别的默认密码替换为随机生成的强密码;仍需按 默认凭证清单 检查未覆盖的凭据。(强烈推荐
  • 当 PG 大版本 ≥ 17 时优先使用内置的 C.UTF-8 Locale,次选由操作系统支持的 C.UTF-8
  • 检测当前环境中,用于执行部署的核心依赖 ansible 是否可用
  • 同时检测部署目标节点是否 ssh 可达,并可以使用 sudo 执行命令。(-s 跳过)

使用示例

# 基本用法
./configure                       # 交互式配置向导
./configure -i 10.10.10.10        # 指定主 IP 地址

# 指定配置模板
./configure -c meta               # 使用默认单节点模板(默认)
./configure -c rich               # 使用功能丰富的单节点模板
./configure -c slim               # 使用精简模板(仅 PGSQL + ETCD)
./configure -c ha/full            # 使用 4 节点高可用沙箱模板
./configure -c ha/trio            # 使用 3 节点高可用模板
./configure -c supabase           # 使用 Supabase 自托管模板
./configure -c app/immich         # 使用 Immich 相册模板

# 指定 PostgreSQL 版本
./configure -v 18                 # 使用 PostgreSQL 18(默认)
./configure -v 16                 # 使用 PostgreSQL 16
./configure -c rich -v 15         # rich 模板 + PG 15
./configure -c pg19               # 使用专用 PostgreSQL 19 Beta 模板

# 区域与代理
./configure -r china              # 使用中国镜像源
./configure -r europe             # 使用欧洲镜像源
./configure -x                    # 导入当前代理环境变量

# 跳过与自动化
./configure -s                    # 跳过 IP 探测,保留占位符
./configure -n -i 10.10.10.10     # 非交互模式,指定 IP
./configure -c ha/full -s         # 4 节点模板,跳过 IP 替换

# 安全增强
./configure -g                    # 生成随机密码
./configure -c meta -g -i 10.10.10.10  # 完整生产配置

# 指定输出与 SSH 端口
./configure -o prod.yml           # 输出到 prod.yml
./configure -p 2222               # 使用 SSH 端口 2222

命令参数

./configure
    [-c|--conf <template>]      # 配置模板名称(meta|rich|slim|ha/full|...)
    [-i|--ip <ipaddr>]          # 指定主 IP 地址
    [-v|--version <pgver>]      # PostgreSQL 大版本号(14|15|16|17|18|19)
    [-r|--region <region>]      # 上游软件仓库区域(default|china|europe)
    [-o|--output <file>]        # 输出配置文件路径(默认:pigsty.yml)
    [-s|--skip]                 # 跳过 IP 地址探测与替换
    [-x|--proxy]                # 从环境变量导入代理设置
    [-n|--non-interactive]      # 非交互模式(不询问任何问题)
    [-p|--port <port>]          # 指定 SSH 端口
    [-g|--generate]             # 生成随机密码
    [-h|--help]                 # 显示帮助信息

参数详解

参数说明
-c, --confconf/<template>.yml 生成配置文件,支持子目录如 ha/full
-i, --ip用指定 IP 替换配置模板中的占位符 10.10.10.10
-v, --version指定 PostgreSQL 大版本号(14-19);PG19 为 Beta,建议直接使用 pg19 模板
-r, --region设置软件仓库镜像区域:default(默认)、china(中国镜像)、europe(欧洲镜像)
-o, --output指定输出文件路径,默认为 pigsty.yml;相对路径基于 Pigsty 目录,绝对路径原样使用
-s, --skip跳过 IP 探测、目标节点 SSH/Sudo 检查与实质 IP 替换,保留 10.10.10.10 占位符
-x, --proxy将当前环境的代理变量(HTTP_PROXYHTTPS_PROXYALL_PROXYNO_PROXY)写入配置
-n, --non-interactive非交互模式;单 IP 或演示 IP 可自动选择,多 IP 歧义时需配合 -i
-p, --port指定环境检查所用 SSH 端口;不会自动把 ansible_port 写入输出配置
-g, --generate为配置文件中的密码生成随机值,提高安全性(强烈推荐)

执行流程

configure 脚本按照以下顺序执行检测与配置:

┌─────────────────────────────────────────────────────────────┐
│                    configure 执行流程                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. check_region          检测网络区域(GFW 检测)              │
│         ↓                                                   │
│  2. check_version         验证 PostgreSQL 版本号              │
│         ↓                                                   │
│  3. check_kernel          检测操作系统内核(Linux/Darwin)       │
│         ↓                                                   │
│  4. check_machine         检测 CPU 架构(x86_64/aarch64)      │
│         ↓                                                   │
│  5. check_package_manager 检测包管理器(dnf/yum/apt)           │
│         ↓                                                   │
│  6. check_vendor_version  检测 OS 发行版与版本                  │
│         ↓                                                   │
│  7. check_sudo            检测免密 sudo 权限                   │
│         ↓                                                   │
│  8. check_ssh             检测免密 SSH 到本机                   │
│         ↓                                                   │
│  9. check_proxy_env       处理代理环境变量                      │
│         ↓                                                   │
│ 10. check_ipaddr          探测/输入主 IP 地址                   │
│         ↓                                                   │
│ 11. check_admin           验证管理员 SSH + Sudo 权限            │
│         ↓                                                   │
│ 12. check_conf            选择配置模板                         │
│         ↓                                                   │
│ 13. check_config          生成配置文件                         │
│         ↓                                                   │
│ 14. check_utils           检测 Ansible 等工具是否安装           │
│         ↓                                                   │
│     ✓ 配置完成,输出 pigsty.yml                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

自动化行为

区域检测

脚本会自动检测网络环境,判断是否在中国大陆(GFW 内):

# 实际检测使用 HTTPS 与 2 秒总超时
curl -I -s --max-time 2 https://www.google.com
  • 如果可以访问 Google,使用 region: default 默认镜像
  • 如果 Google 不可达但 https://pigsty.cc 可达,设置 region: china 使用国内镜像
  • 如果两者都不可达,回退到 region: default 并给出网络不可达警告
  • 可通过 -r 参数手动指定区域

IP 地址处理

脚本按以下优先级确定主 IP 地址:

  1. 命令行参数:如果通过 -i 指定了 IP,直接使用
  2. 单 IP 探测:如果当前节点只有一个 IP,自动使用
  3. 演示 IP 检测:如果检测到 10.10.10.10,自动选择(用于沙箱环境)
  4. 交互式输入:多个 IP 时,提示用户选择或输入
[WARN] Multiple IP address candidates found:
    (1) 192.168.1.100   inet 192.168.1.100/24 scope global eth0
    (2) 10.10.10.10     inet 10.10.10.10/24 scope global eth1
[ IN ] INPUT primary_ip address (of current meta node, e.g 10.10.10.10):
=> 10.10.10.10

低端硬件优化

当检测到 CPU 核心数小于 4(即 1~3 核)时,脚本会自动调整配置:

[WARN] replace oltp template with tiny due to cpu < 4

这样可以确保在低配虚拟机上也能顺利运行。

Locale 设置

脚本会在以下情况自动启用 C.UTF-8 作为默认 Locale:

  • PostgreSQL 版本 ≥ 17(内置 Locale Provider 支持)
  • 或者 当前系统支持 C.UTF-8 / C.utf8 Locale
pg_locale: C.UTF-8
pg_lc_collate: C.UTF-8
pg_lc_ctype: C.UTF-8

中国区特殊处理

当区域设置为 china 时,脚本会自动:

  • 启用 docker_registry_mirrors Docker 镜像加速
  • 启用 PIP_MIRROR_URL Python 镜像加速

密码生成

使用 -g 参数时,脚本会为以下密码生成 24 位随机字符串:

密码参数说明
grafana_admin_passwordGrafana 管理员密码
pg_admin_passwordPostgreSQL 管理员密码
pg_monitor_passwordPostgreSQL 监控用户密码
pg_replication_passwordPostgreSQL 复制用户密码
patroni_passwordPatroni API 密码
haproxy_admin_passwordHAProxy 管理密码
minio_secret_keyMinIO Secret Key
etcd_root_passwordETCD Root 密码

同时还会替换以下占位符密码:

  • DBUser.Meta → 随机密码
  • DBUser.Viewer → 随机密码
  • S3User.Backup → 随机密码
  • S3User.Meta → 随机密码
  • S3User.Data → 随机密码
  • DBUser.Supa → 随机密码
  • Vibe.Coding → 随机密码
$ ./configure -g
[INFO] generating random passwords...
    grafana_admin_password   : xK9mL2nP4qR7sT1vW3yZ5bD8
    pg_admin_password        : aB3cD5eF7gH9iJ1kL2mN4oP6
    ...
[INFO] random passwords generated, check and save them

配置模板

脚本从 conf/ 目录读取配置模板。-c 的值是相对于 conf/、不带 .yml 后缀的路径,例如 ha/fullapp/immich

核心模板

模板说明
meta默认模板:单节点安装,包含 INFRA + NODE + ETCD + PGSQL
rich功能丰富版:包含几乎所有扩展、MinIO、本地仓库
slim精简版:仅 PostgreSQL + ETCD,无监控基础设施
fat完整版:rich 基础上安装更多扩展
pgsql纯 PostgreSQL 模板
pg19PostgreSQL 19 Beta 单节点试用模板
infra纯基础设施模板

高可用模板 (ha/)

模板说明
ha/dual2 节点高可用集群
ha/trio3 节点高可用集群
ha/full4 节点完整沙箱环境
ha/safe安全加固版高可用配置
ha/simu20 节点生产仿真环境
ha/citus13 节点 Citus 分布式集群

应用模板

模板说明
supabaseSupabase 自托管配置
app/difyDify AI 平台配置
app/odooOdoo ERP 配置
app/electricElectric 同步引擎配置
app/insforgeInsforge 后端平台配置
app/hindsightHindsight 应用配置
app/teableTeable 表格数据库配置
app/mattermostMattermost 协作平台配置
app/maybeMaybe 财务应用配置
app/registryDocker Registry 配置
app/immichImmich 相册与视频管理配置
app/jumpserverJumpServer 堡垒机配置

特殊内核模板/模式

模板说明
ivoryIvorySQL:Oracle 兼容 PostgreSQL
mssqlBabelfish:SQL Server 兼容 PostgreSQL
polarPolarDB:阿里云开源分布式 PostgreSQL
ha/citusCitus:分布式 PostgreSQL 高可用集群
mysqlOpenHalo:MySQL 协议兼容 PostgreSQL
pgtdePercona PostgreSQL Server:透明加密
orioleOrioleDB:新一代存储引擎
agensAgensGraph:图数据库内核
pgedgepgEdge:分布式 PostgreSQL 内核
mongoMongoDB 兼容栈模板

演示与构建模板

模板说明
vibeVibe Coding 开发环境模板
dockerDocker 容器内运行模板
demo/bare最小可读单节点配置示例
demo/elEL 系发行版完整参数示例
demo/debianDebian/Ubuntu 完整参数示例
demo/demo多模块演示环境配置
demo/kernel十节点数据库内核矩阵
demo/redisRedis 主从、哨兵与原生集群演示
demo/minioMinIO 多节点多盘集群演示
demo/remote远程 PostgreSQL/RDS 监控示例
demo/saas传统单节点 SaaS 组件组合示例
demo/wool中国区低配云主机示例
build/oss跨发行版开源软件包构建环境
build/dev三节点开发与构建环境

输出示例

$ ./configure
configure pigsty v4.4.0 begin
[ OK ] region = china
[ OK ] kernel  = Linux
[ OK ] machine = x86_64
[ OK ] package = rpm,dnf
[ OK ] vendor  = rocky (Rocky Linux)
[ OK ] version = 9 (9.5)
[ OK ] sudo = vagrant ok
[ OK ] ssh = vagrant@127.0.0.1 ok
[WARN] Multiple IP address candidates found:
    (1) 192.168.121.193	    inet 192.168.121.193/24 brd 192.168.121.255 scope global dynamic noprefixroute eth0
    (2) 10.10.10.10	    inet 10.10.10.10/24 brd 10.10.10.255 scope global noprefixroute eth1
[ OK ] primary_ip = 10.10.10.10 (from demo)
[ OK ] admin = vagrant@10.10.10.10 ok
[ OK ] mode = meta (el9)
[ OK ] locale  = C.UTF-8
[ OK ] ansible = ready
[ OK ] pigsty configured
[WARN] don't forget to check it and change passwords!
proceed with ./deploy.yml

环境变量

脚本支持以下环境变量:

环境变量说明默认值
PIGSTY_HOMEPigsty 安装目录~/pigsty
METADB_URL元数据库连接 URLservice=meta
HTTP_PROXYHTTP 代理-
HTTPS_PROXYHTTPS 代理-
ALL_PROXY通用代理-
NO_PROXY代理白名单内置默认值

注意事项

  1. 免密访问:运行 configure 前,确保当前用户具有免密 sudo 权限和免密 SSH 到本机的能力。可以通过 bootstrap 脚本自动配置。

  2. IP 地址选择:请选择内网 IP 作为主 IP 地址,不要使用公网 IP 或 127.0.0.1

  3. 密码安全:生产环境务必修改配置文件中的默认密码。可以使用 -g 参数随机化向导识别的凭据,并按 默认凭证清单 检查其余值。

  4. 配置检查:脚本执行完成后,建议检查生成的 pigsty.yml 文件,确认配置符合预期。

  5. 多次执行:可以多次运行 configure 重新生成配置,每次会覆盖现有的 pigsty.yml

  6. macOS 限制:在 macOS 上运行时,脚本会跳过部分 Linux 特有的检测,并使用占位符 IP 10.10.10.10。macOS 只能作为管理节点使用。


常见问题

如何使用自定义配置模板?

将您的配置文件放到 conf/ 目录下,然后使用 -c 参数指定:

cp my-config.yml ~/pigsty/conf/myconf.yml
./configure -c myconf

如何为多集群生成不同配置?

使用 -o 参数指定不同的输出文件:

./configure -c ha/full -o cluster-a.yml
./configure -c ha/trio -o cluster-b.yml

然后在执行剧本时指定配置文件:

./deploy.yml -i cluster-a.yml

非交互模式下如何处理多 IP?

必须使用 -i 参数明确指定 IP 地址:

./configure -n -i 10.10.10.10

如何保留模板中的占位符 IP?

使用 -s 参数跳过 IP 替换:

./configure -c ha/full -s   # 保留 10.10.10.10 占位符

相关文档

3.3 - 配置参数

使用配置参数对 Pigsty 进行精细化定制

配置清单 中,您可以使用各种参数对 Pigsty 进行精细化定制。这些参数涵盖了从基础设施设置到数据库配置的各个方面。


参数列表

Pigsty 提供了 359 个配置参数,分布在 10 个模块中,用于精细控制系统的各个方面,完整列表见 参考-参数列表

模块参数组参数数说明
PGSQL9124PostgreSQL 高可用集群配置
INFRA1072软件仓库与 Victoria 可观测基础设施
NODE1173节点初始化、系统调优与运维基线
ETCD213ETCD 集群与移除保护参数
MINIO221MinIO 部署与移除参数
REDIS221Redis 部署与移除参数
FERRET19FerretDB(Mongo API)参数
DOCKER18Docker 引擎参数
JUICE12JuiceFS 实例与缓存参数
VIBE116Code/Jupyter/Node.js/Claude 配置

参数形式

参数 是用于描述实体的 键值对(Key)是字符串,(Value)可以是五种类型之一:布尔值、字符串、数字、数组或对象。

all:                            # <------- 顶级对象:all
  vars: 
    admin_ip: 10.10.10.10       # <------- 全局配置参数
  children:
    pg-meta:                    # <------- pg-meta 分组
      vars:
        pg_cluster: pg-meta     # <------- 集群级别参数
      hosts:
        10.10.10.10:            # <------- 主机节点 IP
          pg_seq: 1
          pg_role: primary      # <------- 实例级别参数
  

参数优先级

参数可以在不同级别设置,具有以下优先级:

级别位置描述优先级
命令行-e 命令行参数通过命令行传入最高 (5)
主机/实例<group>.hosts.<host>特定于单个主机的参数较高 (4)
分组/集群<group>.vars组/集群中主机共享的参数中等 (3)
全局all.vars所有主机共享的参数较低 (2)
默认<roles>/default/main.yml角色实现默认值最低 (1)

以下是关于参数优先级的一些示例:

  • 执行剧本时,使用命令行参数 -e grafana_clean=true 来抹除 Grafana 数据
  • 使用主机变量上的实例级别参数 pg_role 覆盖 pg 实例角色
  • 使用组变量上的集群级别参数 pg_cluster 覆盖 pg 集群名称。
  • 使用全局变量上的全局参数 node_ntp_servers 指定全局 NTP 服务器
  • 如果没有设置 pg_version,Pigsty 将使用 pgsql 角色实现的默认值(默认为 18

除了身份参数 外,每个参数都有适当的默认值,因此无需显式设置。


身份参数

身份参数是特殊的参数,它们会作为实体的 ID 标识符,因此 没有默认值,必须 显式设置

模块身份参数
PGSQLpg_cluster, pg_seq, pg_role, …
NODEnodename, node_cluster
ETCDetcd_cluster, etcd_seq
MINIOminio_cluster, minio_seq
REDISredis_cluster, redis_node, redis_instances
INFRAinfra_seq

例外是,etcd_clusterminio_cluster 有默认值。 它假设每套部署只有一套 etcd 集群用于 DCS,和一套可选 MinIO 集群用于集中备份存储,因此为其分配了默认的集群名称 etcdminio。 但您依然可以使用其他名称部署多套 etcd 或 MinIO 集群。

3.4 - 配置模板

使用预制的配置模板,快速生成适配当前环境的配置文件

在 Pigsty 中,部署的蓝图细节由 配置清单 所定义,也就是 pigsty.yml 配置文件,您可以通过声明式配置进行定制。

然而,直接编写配置文件可能会让新用户望而生畏。为此,我们提供了一些开箱即用的配置模板,涵盖了常见的使用场景。

每一个模板都是一个预定义的 pigsty.yml 配置文件,包含了适用于特定场景的合理默认值。

您可以根据自己的需要,选择一个模板作为定制起点,然后根据需要进行修改,以满足您的具体需求。


使用模板

Pigsty 提供了 configure 脚本作为可选的配置向导,它将根据您的环境和输入,生成具有良好默认值的 配置清单

使用 ./configure -c <conf> 指定配置模板,其中 <conf> 是相对于 conf 目录的路径(可省略 .yml 后缀)。

./configure                     # 默认使用 meta.yml 配置模板
./configure -c meta             # 显式指定使用 meta.yml 单节点模板
./configure -c rich             # 使用包含全部扩展与 MinIO 的富功能模板
./configure -c slim             # 使用最小化的单节点模板

# 使用不同的数据库内核
./configure -c pgsql            # 原生 PostgreSQL 内核,基础功能 (14~18)
./configure -c mssql            # Babelfish 内核,兼容 SQL Server 协议 (17/18)
./configure -c polar            # PolarDB PG 内核,Aurora/RAC 风格 (17)
./configure -c ivory            # IvorySQL 内核,兼容 Oracle 语法 (18)
./configure -c mysql            # OpenHalo 内核,兼容 MySQL (14)
./configure -c pgtde            # Percona PostgreSQL Server 透明加密 (18)
./configure -c oriole           # OrioleDB 内核,OLTP 增强 (16~18)
./configure -c agens            # AgensGraph 图数据库内核 (17)
./configure -c pgedge           # pgEdge 分布式数据库内核 (15~18,默认 18)
./configure -c ha/citus         # Citus 分布式高可用 PostgreSQL (14~18)
./configure -c supabase         # Supabase 自托管配置 (15~18)

# 使用多节点高可用模板
./configure -c ha/dual          # 使用 2 节点高可用模板
./configure -c ha/trio          # 使用 3 节点高可用模板
./configure -c ha/full          # 使用 4 节点高可用模板

如果不指定模板,Pigsty 默认使用 meta.yml 单节点配置模板。


模板列表

主要模板

以下是单节点配置模板,可用于在单台服务器上安装 Pigsty:

模板说明
meta.yml默认模板,单节点 PostgreSQL 在线安装
rich.yml富功能模板,包含本地软件源、MinIO 及更多示例
slim.yml精简模板,仅安装 PostgreSQL,不含监控与基础设施

数据库内核模板

适用于各类数据库管理系统与内核的模板:

模板说明
pgsql.yml原生 PostgreSQL 内核,基础功能 (14~18)
mssql.ymlBabelfish 内核,兼容 SQL Server 协议 (17/18)
polar.ymlPolarDB PG 内核,Aurora/RAC 风格 (17)
ivory.ymlIvorySQL 内核,兼容 Oracle 语法 (18)
mysql.ymlOpenHalo 内核,兼容 MySQL (14)
pgtde.ymlPercona PostgreSQL Server 透明加密 (18)
oriole.ymlOrioleDB 内核,OLTP 增强 (16~18)
agens.ymlAgensGraph 图数据库内核 (17)
pgedge.ymlpgEdge 分布式数据库内核 (15~18,默认 18)
supabase.ymlSupabase 自托管配置 (15~18)

您可以后续添加更多节点,或使用 高可用模板 在一开始就规划好集群。


高可用模板

您可以配置 Pigsty 在多节点上运行,组成高可用(HA)集群:

模板说明
dual.yml2 节点半高可用部署
trio.yml3 节点标准高可用部署
full.yml4 节点标准部署
safe.yml4 节点安全增强部署,含延迟从库
simu.yml20 节点生产环境模拟
ha/citus.ymlCitus 分布式高可用 PostgreSQL (14~18)

应用模板

您可以使用以下模板运行 Docker 应用/软件:

模板说明
supabase.yml启动单节点 Supabase
odoo.yml启动 Odoo ERP 系统
dify.yml启动 Dify AI 工作流系统
electric.yml启动 Electric 同步引擎
insforge.yml启动 Insforge 后端平台
hindsight.yml启动 Hindsight 应用
mattermost.yml启动 Mattermost 协作平台
teable.yml启动 Teable 表格数据库
maybe.yml启动 Maybe 财务应用
registry.yml启动 Docker Registry

演示模板

除主要模板外,Pigsty 还提供了一组面向不同场景的演示模板:

模板说明
el.ymlEL 8/9 系统的全参数配置文件
debian.ymlDebian/Ubuntu 系统的全参数配置文件
remote.yml监控远程 PostgreSQL 集群或 RDS 的示例配置
redis.ymlRedis 集群示例配置
minio.yml3 节点 MinIO 集群示例配置
demo.ymlPigsty 公开演示站 的配置文件
fat.yml含本地软件源与完整功能的单节点配置文件
infra.yml仅部署基础设施模块
vibe.ymlVibe Coding / AI 应用开发模板
mongo.ymlFerretDB / MongoDB 兼容示例
docker.ymlDocker 应用宿主模板

构建模板

以下配置模板用于开发和测试目的:

模板说明
build/oss.ymlEL 9/10、Debian 12/13、Ubuntu 22.04/24.04/26.04 开源构建配置
build/dev.yml开发测试构建配置

3.5 - 元数据库

使用 PostgreSQL 作为 CMDB 元数据库,存储 Ansible 配置清单。

Pigsty 允许您使用 PostgreSQL 元数据库 作为动态配置源,取代静态的 YAML 配置文件,实现更强大的配置管理能力。


概览

CMDB(Configuration Management Database,配置管理数据库)是一种将配置信息存储在数据库中进行管理的方式。

在 Pigsty 中,默认的配置源是一个静态 YAML 文件 pigsty.yml, 它作为 Ansible 的 配置清单 使用。

这种方式简单直接,但当基础设施规模扩大、需要复杂精细的管理与外部集成时,单一的静态文件难以满足需求。

特性静态 YAML 文件CMDB 元数据库
查询能力手工搜索/grepSQL 任意条件查询,聚合分析
版本控制依赖 Git 或手工备份数据库事务,审计日志,时间旅行快照
权限控制文件系统权限,粗粒度PostgreSQL 数据库 精细访问控制
并发编辑需要锁文件或合并冲突数据库事务天然支持并发
外部集成需要解析 YAML标准 SQL 接口,任意语言轻松对接
规模扩展文件过大时难以维护管理规模伸缩至物理极限
动态生成静态文件,修改后需手动应用即时生效,实时反映配置变更

Pigsty 在样板数据库 pg-meta.meta 的模式基线定义中,提供了 Pigsty CMDB 的数据库模式。


工作原理

CMDB 的核心思想是用一个 动态脚本 替换静态配置文件。 Ansible 支持使用可执行脚本作为配置清单,只要脚本输出符合 JSON 格式的清单数据即可。 当您启用 CMDB 后,Pigsty 会创建一个名为 inventory.sh 的动态清单脚本:

#!/bin/bash
psql ${METADB_URL} -AXtwc 'SELECT text FROM pigsty.inventory;'

这个脚本的作用很简单:每次 Ansible 需要读取配置清单时,它会从 PostgreSQL 数据库的 pigsty.inventory 视图中查询配置数据,并以 JSON 格式返回。

整体架构如下:

flowchart LR
    conf["bin/inventory_conf"]
    tocmdb["bin/inventory_cmdb"]
    load["bin/inventory_load"]
    ansible["🚀 Ansible"]

    subgraph static["📄 静态配置模式"]
        yml[("pigsty.yml")]
    end

    subgraph dynamic["🗄️ CMDB 动态模式"]
        sh["inventory.sh"]
        cmdb[("PostgreSQL CMDB")]
    end

    conf -->|"切换"| yml
    yml -->|"加载配置"| load
    load -->|"写入"| cmdb
    tocmdb -->|"切换"| sh
    sh --> cmdb

    yml --> ansible
    cmdb --> ansible

数据模型

CMDB 的数据库模式定义在 files/cmdb.sql 文件中,所有对象都位于 pigsty 模式下。

核心数据表

表名说明主键
pigsty.group集群/分组定义,对应 Ansible 的 groupcls
pigsty.host主机定义,属于某个分组(cls, ip)
pigsty.global_var全局变量,对应 all.varskey
pigsty.group_var分组变量,对应 all.children.<cls>.vars(cls, key)
pigsty.host_var主机变量,对应主机级别的变量(cls, ip, key)
pigsty.default_var默认变量定义,存储参数的元信息key
pigsty.job作业记录表,记录执行的任务id

表结构详解

集群表 pigsty.group

CREATE TABLE pigsty.group (
    cls     TEXT PRIMARY KEY,        -- 集群名称,主键
    ctime   TIMESTAMPTZ DEFAULT now(), -- 创建时间
    mtime   TIMESTAMPTZ DEFAULT now()  -- 修改时间
);

主机表 pigsty.host

CREATE TABLE pigsty.host (
    cls    TEXT NOT NULL REFERENCES pigsty.group(cls),  -- 所属集群
    ip     INET NOT NULL,                               -- 主机 IP 地址
    ctime  TIMESTAMPTZ DEFAULT now(),
    mtime  TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, ip)
);

全局变量表 pigsty.global_var

CREATE TABLE pigsty.global_var (
    key   TEXT PRIMARY KEY,           -- 变量名
    value JSONB NULL,                 -- 变量值(JSON 格式)
    mtime TIMESTAMPTZ DEFAULT now()   -- 修改时间
);

分组变量表 pigsty.group_var

CREATE TABLE pigsty.group_var (
    cls   TEXT NOT NULL REFERENCES pigsty.group(cls),
    key   TEXT NOT NULL,
    value JSONB NULL,
    mtime TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, key)
);

主机变量表 pigsty.host_var

CREATE TABLE pigsty.host_var (
    cls   TEXT NOT NULL,
    ip    INET NOT NULL,
    key   TEXT NOT NULL,
    value JSONB NULL,
    mtime TIMESTAMPTZ DEFAULT now(),
    PRIMARY KEY (cls, ip, key),
    FOREIGN KEY (cls, ip) REFERENCES pigsty.host(cls, ip)
);

核心视图

CMDB 提供了一系列视图,用于查询和展示配置数据:

视图名说明
pigsty.inventory核心视图:生成 Ansible 动态清单 JSON
pigsty.raw_config原始配置的 JSON 格式展示
pigsty.global_config全局配置视图,合并默认值和全局变量
pigsty.group_config分组配置视图,包含主机列表和分组变量
pigsty.host_config主机配置视图,合并分组和主机级别变量
pigsty.pg_clusterPostgreSQL 集群视图
pigsty.pg_instancePostgreSQL 实例视图
pigsty.pg_databasePostgreSQL 数据库定义视图
pigsty.pg_usersPostgreSQL 用户定义视图
pigsty.pg_servicePostgreSQL 服务定义视图
pigsty.pg_hbaPostgreSQL HBA 规则视图
pigsty.pg_remote远程 PostgreSQL 实例视图

pigsty.inventory 是最核心的视图,它将数据库中的配置数据转换为 Ansible 所需的 JSON 格式:

SELECT text FROM pigsty.inventory;

工具脚本

Pigsty 提供了三个便利脚本来管理 CMDB:

脚本功能
bin/inventory_load将 YAML 配置文件加载到 PostgreSQL 数据库中
bin/inventory_cmdb切换配置源为 CMDB(动态清单脚本)
bin/inventory_conf切换配置源为静态配置文件 pigsty.yml

inventory_load

将 YAML 配置文件解析并导入到 CMDB 中:

bin/inventory_load                     # 加载默认的 pigsty.yml 到默认 CMDB
bin/inventory_load -p /path/to/conf.yml  # 指定配置文件路径
bin/inventory_load -d "postgres://..."   # 指定数据库连接 URL
bin/inventory_load -n myconfig           # 指定配置名称

脚本会执行以下操作:

  1. 清空 pigsty 模式中的现有数据
  2. 解析 YAML 配置文件
  3. 将全局变量写入 global_var
  4. 将集群定义写入 group
  5. 将集群变量写入 group_var
  6. 将主机定义写入 host
  7. 将主机变量写入 host_var

环境变量

  • PIGSTY_HOME:Pigsty 安装目录,默认为 ~/pigsty
  • METADB_URL:数据库连接 URL,默认为 service=meta

inventory_cmdb

切换 Ansible 使用 CMDB 作为配置源:

bin/inventory_cmdb

脚本会执行以下操作:

  1. 创建动态清单脚本 ${PIGSTY_HOME}/inventory.sh
  2. 修改 ansible.cfginventory 设置为 inventory.sh

生成的 inventory.sh 内容如下:

#!/bin/bash
psql ${METADB_URL} -AXtwc 'SELECT text FROM pigsty.inventory;'

inventory_conf

切换回使用静态 YAML 配置文件:

bin/inventory_conf

脚本会修改 ansible.cfginventory 设置回 pigsty.yml


使用流程

首次启用 CMDB

  1. 初始化 CMDB 模式(通常在安装 Pigsty 时已自动完成):
psql -f ~/pigsty/files/cmdb.sql
  1. 加载配置到数据库
bin/inventory_load
  1. 切换到 CMDB 模式
bin/inventory_cmdb
  1. 验证配置
ansible all --list-hosts          # 列出所有主机
ansible-inventory --list          # 查看完整清单

查询配置

启用 CMDB 后,您可以使用 SQL 灵活查询配置:

-- 查看所有集群
SELECT cls FROM pigsty.group;

-- 查看某集群的所有主机
SELECT ip FROM pigsty.host WHERE cls = 'pg-meta';

-- 查看全局变量
SELECT key, value FROM pigsty.global_var;

-- 查看某集群的变量
SELECT key, value FROM pigsty.group_var WHERE cls = 'pg-meta';

-- 查看所有 PostgreSQL 集群
SELECT cls, name, pg_databases, pg_users FROM pigsty.pg_cluster;

-- 查看所有 PostgreSQL 实例
SELECT cls, ins, ip, seq, role FROM pigsty.pg_instance;

-- 查看所有数据库定义
SELECT cls, datname, owner, encoding FROM pigsty.pg_database;

-- 查看所有用户定义
SELECT cls, name, login, superuser FROM pigsty.pg_users;

修改配置

您可以直接通过 SQL 修改配置:

-- 添加新集群
INSERT INTO pigsty.group (cls) VALUES ('pg-new');

-- 添加集群变量
INSERT INTO pigsty.group_var (cls, key, value)
VALUES ('pg-new', 'pg_cluster', '"pg-new"');

-- 添加主机
INSERT INTO pigsty.host (cls, ip) VALUES ('pg-new', '10.10.10.20');

-- 添加主机变量
INSERT INTO pigsty.host_var (cls, ip, key, value)
VALUES ('pg-new', '10.10.10.20', 'pg_seq', '1'),
       ('pg-new', '10.10.10.20', 'pg_role', '"primary"');

-- 修改全局变量
UPDATE pigsty.global_var SET value = '"new-value"' WHERE key = 'some_param';

-- 删除集群(级联删除主机和变量)
DELETE FROM pigsty.group WHERE cls = 'pg-old';

修改后立即生效,无需重新加载或重启任何服务。

切换回静态配置

如需切换回静态配置文件模式:

bin/inventory_conf

高级用法

配置导出

将 CMDB 中的配置导出为 YAML 格式:

psql service=meta -AXtwc "SELECT jsonb_pretty(jsonb_build_object('all', jsonb_build_object('children', children, 'vars', vars))) FROM pigsty.raw_config;"

或者使用 ansible-inventory 命令:

ansible-inventory --list --yaml > exported_config.yml

配置审计

利用 mtime 字段追踪配置变更:

-- 查看最近修改的全局变量
SELECT key, value, mtime FROM pigsty.global_var
ORDER BY mtime DESC LIMIT 10;

-- 查看某时间点之后的变更
SELECT * FROM pigsty.group_var
WHERE mtime > '2024-01-01'::timestamptz;

与外部系统集成

CMDB 使用标准 PostgreSQL,可以轻松与其他系统集成:

  • Web 管理界面:通过 REST API(如 PostgREST)暴露配置数据
  • CI/CD 流水线:在部署脚本中直接读写数据库
  • 监控告警:基于配置数据生成监控规则
  • ITSM 系统:与企业 CMDB 系统同步

注意事项

  1. 数据一致性:修改配置后,需要重新执行相应的 Ansible 剧本才能将变更应用到实际环境

  2. 备份:CMDB 中的配置数据非常重要,请确保定期备份

  3. 权限:建议为 CMDB 配置适当的数据库访问权限,避免误操作

  4. 事务:批量修改配置时,建议在事务中进行,以便出错时回滚

  5. 连接池inventory.sh 脚本每次执行都会建立新连接,如果 Ansible 执行频繁,建议考虑使用连接池


小结

CMDB 是 Pigsty 配置管理的高级方案,适用于需要管理大量集群、复杂查询、外部集成或精细权限控制的场景。通过将配置数据存储在 PostgreSQL 中,您可以充分利用数据库的强大能力来管理基础设施配置。

功能说明
数据存储PostgreSQL pigsty 模式
动态清单inventory.sh 脚本
配置加载bin/inventory_load
切换到 CMDBbin/inventory_cmdb
切换到 YAMLbin/inventory_conf
核心视图pigsty.inventory

4 - PG 高可用

Pigsty 使用 Patroni 实现了 PostgreSQL 的高可用,确保主库不可用时自动进行故障转移,由从库接管。

概览

Pigsty 的 PostgreSQL 集群带有开箱即用的高可用方案,由 PatroniEtcdHAProxy 提供核心能力。

当您的 PostgreSQL 集群含有两个或更多实例时,您无需任何配置即拥有了硬件故障自愈的数据库高可用能力 —— 只要集群中有任意实例存活,集群就可以对外提供完整的服务,而客户端只要连接至集群中的任意节点,即可获得完整的服务,而无需关心主从拓扑变化。

在默认配置下,主库故障恢复时间目标 RTO ≈ 45s,数据恢复点目标 RPO < 1MB;从库故障 RPO = 0,RTO ≈ 0 (闪断);在一致性优先模式下,可确保故障切换数据零损失: RPO = 0。以上指标均可通过参数,根据您的实际硬件条件与可靠性要求 按需配置

Pigsty 内置了 HAProxy 负载均衡器用于自动流量切换,提供 DNS/VIP/LVS 等多种接入方式供客户端选用。故障切换与主动切换对业务侧除零星闪断外几乎无感知,应用不需要修改连接串重启。 极小的维护窗口需求带来了极大的灵活便利:您完全可以在无需应用配合的情况下滚动维护升级整个集群。硬件故障可以等到第二天再抽空善后处置的特性,让研发,运维与 DBA 都能在故障时安心睡个好觉。

pigsty-ha

许多大型组织与核心机构已经在生产环境中长时间使用 Pigsty,最大的部署有 25K CPU 核心与 220+ PostgreSQL 超大规格实例(64c / 512g / 3TB NVMe SSD);在这一部署案例中,五年内经历了数十次硬件故障与各类事故,但依然可以保持高于 99.999% 的总体可用性战绩。


高可用(High-Availability)解决什么问题?

  • 数据安全 C/IA 中的可用性提高到一个新高度:RPO ≈ 0,RTO < 45s。
  • 获得无缝滚动维护的能力,最小化维护窗口需求,带来极大便利。
  • 硬件故障可以立即自愈,无需人工介入,运维 DBA 可以睡个好觉。
  • 从库可以用于承载只读请求,分担主库负载,让资源得以充分利用。

高可用有什么代价?

  • 基础设施依赖:高可用需要依赖 DCS (etcd/zk/consul) 提供共识。
  • 起步门槛增加:一个有意义的高可用部署环境至少需要 三个节点
  • 额外的资源消耗:一个新从库就要消耗一份额外资源,不算大问题。
  • 复杂度代价显著升高:备份成本显著加大,需要使用工具压制复杂度。

高可用的局限性

因为复制实时进⾏,所有变更被⽴即应⽤⾄从库。因此基于流复制的高可用方案⽆法应对⼈为错误与软件缺陷导致的数据误删误改。(例如:DROP TABLE,或 DELETE 数据) 此类故障需要使用 延迟集群,或使用先前的基础备份与 WAL 归档进行 时间点恢复

配置策略RTORPO
单机 + 什么也不做 数据永久丢失,无法恢复 数据全部丢失
单机 + 基础备份 取决于备份大小与带宽(几小时) 丢失上一次备份后的数据(几个小时到几天)
单机 + 基础备份 + WAL 归档 取决于备份大小与带宽(几小时) 丢失最后尚未归档的数据(几十 MB)
主从 + 手工故障切换 十分钟 丢失复制延迟中的数据(约百 KB)
主从 + 自动故障切换 一分钟内 丢失复制延迟中的数据(约百 KB)
主从 + 自动故障切换 + 同步提交 一分钟内 无数据丢失

原理

在 Pigsty 中,高可用架构的实现原理如下:

  • PostgreSQL 使⽤标准流复制搭建物理从库,主库故障时由从库接管。
  • Patroni 负责管理 PostgreSQL 服务器进程,处理高可用相关事宜。
  • Etcd 提供分布式配置存储(DCS)能力,并用于故障后的领导者选举
  • Patroni 依赖 Etcd 达成集群领导者共识,并对外提供健康检查接口。
  • HAProxy 对外暴露集群服务,并利⽤ Patroni 健康检查接口,自动分发流量至健康节点。
  • vip-manager 提供一个可选的二层 VIP,从 Etcd 中获取领导者信息,并将 VIP 绑定在集群主库所在节点上。

当主库故障时,将触发新一轮领导者竞选,集群中最为健康的从库将胜出(LSN 位点最高,数据损失最小者),并被提升为新的主库。 胜选从库提升后,读写流量将立即路由至新的主库。 主库故障影响是 写服务短暂不可用:从主库故障到新主库提升期间,写入请求将被阻塞或直接失败,不可用时长通常在 15秒 ~ 30秒,通常不会超过 1 分钟。

当从库故障时,只读流量将路由至其他从库,如果所有从库都故障,只读流量才会最终由主库承载。 从库故障的影响是 部分只读查询闪断:当前从库上正在运行查询将由于连接重置而中止,并立即由其他可用从库接管。

故障检测由 Patroni 和 Etcd 共同完成,集群领导者将持有一个租约, 如果集群领导者因为故障而没有及时续租(10s),租约将会被释放,并触发 故障切换(Failover) 与新一轮集群选举。

即使没有出现任何故障,您依然可以主动通过 主动切换(Switchover)变更集群的主库。 在这种情况下,主库上的写入查询将会闪断,并立即路由至新主库执行。这一操作通常可用于滚动维护/升级数据库服务器。

4.1 - RPO 利弊权衡

针对 RPO (Recovery Point Objective)进行利弊权衡,在可用性与数据损失之间找到最佳平衡点。

RPO(Recovery Point Objective,恢复点目标)定义了在主库发生故障时,允许丢失的最大数据量

对于金融交易这类数据完整性至关重要的场景,通常要求 RPO = 0,即不允许任何数据丢失;

然而更为严格的 RPO 指标是有代价的,它会引入更高的写入延迟,降低系统吞吐量,并且存在从库故障导致主库不可用的风险。 因此对于常规场景,通常可以接受一定量的数据丢失(例如允许丢失不超过 1MB 的数据),以换取更高的可用性与性能。


利弊权衡

通常在异步复制场景下,从库和主库之间会存在一定的复制延迟(取决于网络和吞吐量,正常在 10KB-100KB / 100µs-10ms 的数量级), 这意味着当主库发生故障时,从库可能还没有完全同步主库的最新数据。这时候如果出现故障切换,新的主库可能会丢失一些尚未复制的数据。

潜在数据丢失量的上限由 pg_rpo 参数控制,默认为 10485761MB),这意味着在故障转移期间最多可以容忍 1MiB 的数据丢失。

当集群主库宕机时,如果有任何一个从库的复制延迟在这个值以内,Pigsty 将自动提升该从库为新的主库。 然而当所有从库副本的复制延迟都超出这个阈值时,Pigsty 将拒绝进行 [自动故障切换] 以避免数据丢失。 此时需要人工介入进行决策 —— 等待主库恢复(可能永远也不会恢复),还是接受数据损失并强制提升一个从库为新的主库。

您需要根据业务的需求偏好配置这个值,在 可用性一致性 之间进行 利弊权衡。 增大这个值可以提高自动故障切换的成功率,但也会增加潜在的数据丢失量上限。

当您指定 pg_rpo = 0 时,Pigsty 将启用 同步复制,确保主库在确认至少一个从库持久化数据后才返回写入成功。 这种配置能确保没有复制延迟,但会带来显著的写入延迟,并降低整体的吞吐量。

flowchart LR
    A([主库故障]) --> B{同步复制?}

    B -->|否| C{延迟 < RPO?}
    B -->|是| D{同步从库<br/>可用?}

    C -->|是| E[有损自动故障切换<br/>RPO < 1MB]
    C -->|否| F[拒绝自动切换<br/>等待主库恢复<br/>或人工介入决策]

    D -->|是| G[无损自动故障切换<br/>RPO = 0]
    D -->|否| H{严格模式?}

    H -->|否| C
    H -->|是| F

    style A fill:#dc3545,stroke:#b02a37,color:#fff
    style E fill:#F0AD4E,stroke:#146c43,color:#fff
    style G fill:#198754,stroke:#146c43,color:#fff
    style F fill:#BE002F,stroke:#565e64,color:#fff

保护模式

Pigsty 提供三种保护模式,以帮助用户在不同的 RPO 要求下进行利弊权衡,类似于 Oracle Data Guard 的数据保护模式。

名称最大性能 Performance最大可用 Availability最大保护 Protection
复制方式异步复制同步复制严格同步复制
数据丢失可能丢失(复制延迟量)正常零丢失,降级少量丢失零丢失
主库写延迟最低中等(+1 次网络往返)中等(+1 次网络往返)
吞吐量最高降低降低
从库故障影响无影响自动降级,继续服务主库停写
RPO< 1MB= 0(正常)/ < 1MB(降级)= 0
适用场景常规业务、性能优先重要业务、安全优先金融核心、安全合规第一
配置方法默认配置pg_rpo = 0pg_conf: crit.yml

实现原理

三种保护模式的区别在于 Patroni 的两个核心参数:synchronous_modesynchronous_mode_strict 如何配置:

  • synchronous_mode:Patroni 是否启用同步复制,如果启用,再看 synchronous_mode_strict 是否启用严格同步模式。
  • synchronous_mode_strict = false,默认配置,允许当从库故障时降级为异步模式,主库继续服务(最大可用性)
  • synchronous_mode_strict = true,禁止降级,主库停止写入直到同步从库恢复(最大保护)
模式synchronous_modesynchronous_mode_strict复制模式从库故障行为
最大性能false-异步复制无影响
最大可用truefalse同步复制自动降级为异步
最大保护truetrue严格同步复制主库拒绝写入

通常情况下,您只需要将 pg_rpo 参数设置为 0,即可打开 synchronous_mode 开关,启用 最大可用性模式。 如果您使用 pg_conf = crit.yml 模板,则会同时额外打开 synchronous_mode_strict 严格模式开关,启用 最大保护模式。 此外,您可以启用 watchdog,在节点/Patroni 假死场景下直接 Fencing 主库而不是降级,实现与 Oracle 最大保护模式相同的行为表现

当然,您可以直接按需 配置 这些 Patroni 参数,您还可以参阅 Patroni 与 PostgreSQL 文档,通过配置实现更强的数据保护,例如:

  • 可以指定 同步从库列表,配置更多同步从库以提高容灾能力,使用法定人数同步,甚至要求所有从库都执行同步提交。
  • 您可以 配置 synchronous_commit: 'remote_apply',严格确保主从读写一致性。(Oracle 最大保护模式相当于 remote_write

配置建议

最大性能模式(异步复制)是 Pigsty 默认使用的模式,对于绝大多数业务来说已经足够使用。 容许故障时丢失少量数据(正常在 几 KB - 几百 KB 的数量级),换来更大的性能吞吐量与服务可用性水平,是常规业务场景的推荐配置。 在这种情况下,您可以通过 pg_rpo 参数调整允许的最大数据丢失量,以适应不同的业务需求。

最大可用性模式(同步复制)适用于对据完整性要求高的场景,不允许数据丢失。 在这种模式下,最少需要一主一从的两节点 PostgreSQL 集群才有意义。 将 pg_rpo 设置为 0 即可启用该模式。

最大保护模式 (严格同步复制) 适用于金融交易、医疗记录等对数据完整性要求极高的场景,我们建议至少使用一主二从的三节点集群, 因为两节点的情况下,只要从库故障,主库就会停止写入,导致业务不可用,这会降低系统的整体可靠性。而三节点的规格下,如果只有一个从库故障,主库仍然可以继续服务。

4.2 - RTO 利弊权衡

针对 RTO (Recovery Time Objective)进行利弊权衡,在故障恢复速度与误切风险之间找到最佳平衡点。

RTO(Recovery Time Objective,恢复时间目标)定义了在主库发生故障时,系统恢复写入能力所需的最长时间

对于核心交易系统这类可用性至关重要的场景,通常要求 RTO 尽可能短,例如一分钟内。

然而更短的 RTO 指标是有代价的,它会增加误切风险:网络抖动可能被误判为故障,导致不必要的故障切换。 因此对于跨机房/跨地域部署的场景,通常需要放宽 RTO 要求(例如 1-2 分钟),以降低误切风险。


利弊权衡

故障切换时的不可用时长上限由 pg_rto 参数控制。Pigsty 提供了四种预设的 RTO 模式: fastnormsafewide,分别针对不同的网络条件与部署场景进行了优化,默认使用 norm 模式(约 45 秒)。 您也可以使用秒数直接指定 RTO 上限,系统会自动映射到最接近的模式。

当主库发生故障时,整个恢复流程涉及多个阶段:Patroni 检测故障、DCS 锁过期、新主选举、执行 promote、HAProxy 感知新主。 减小 RTO 意味着缩短各阶段的超时时间,这会使集群对网络抖动更加敏感,从而增加误切风险。

您需要根据实际网络条件选择合适的模式,在 恢复速度误切风险 之间取得平衡。 网络质量越差,越应该选择保守的模式;网络质量越好,越可以选择激进的模式。

flowchart LR
    A([主库故障]) --> B{Patroni<br/>检测到?}

    B -->|PG崩溃| C[尝试本地重启]
    B -->|节点宕机| D[等待 TTL 过期]

    C -->|成功| E([本地恢复])
    C -->|失败/超时| F[释放 Leader 锁]

    D --> F
    F --> G[从库竞选]
    G --> H[执行 Promote]
    H --> I[HAProxy 感知]
    I --> J([服务恢复])

    style A fill:#dc3545,stroke:#b02a37,color:#fff
    style E fill:#198754,stroke:#146c43,color:#fff
    style J fill:#198754,stroke:#146c43,color:#fff

四种模式

Pigsty 提供四种 RTO 模式,以帮助用户在不同的网络条件下进行利弊权衡。

名称fastnormsafewide
适用场景同机柜同机房内(默认)同省跨机房跨地域/跨洲
网络条件< 1ms,极稳定1-5ms,正常10-50ms,跨机房100-200ms,公网
目标 RTO30s45s90s150s
误切风险较高中等较低极低
配置方法pg_rto: fastpg_rto: normpg_rto: safepg_rto: wide

RTO时序图

Patroni / PG HA 有两条关键故障路径:主动故障检测(PG 崩溃后 Patroni 检测到并尝试重启)与 被动租约过期(节点宕机后等待 TTL 过期触发选举)。


实现原理

四种 RTO 模式的区别在于以下 10 个 PatroniHAProxy HA 相关参数如何配置。

组件参数fastnormsafewide说明
patronittl203060120Leader 锁生存时间(秒)
loop_wait551020HA 循环检查间隔(秒)
retry_timeout5102030DCS 操作重试超时(秒)
primary_start_timeout15254595主库重启等待时间(秒)
safety_margin551015Watchdog 安全边际(秒)
haproxyinter1s2s3s4s正常状态检查间隔
fastinter0.5s1s1.5s2s状态变化期检查间隔
downinter1s2s3s4sDOWN 状态检查间隔
rise3333标记 UP 所需连续成功次数
fall3333标记 DOWN 所需连续失败次数

Patroni 参数

  • ttl:Leader 锁生存时间,主库须在此时间内续租,否则锁过期触发选举,直接决定被动故障的检测延迟。
  • loop_wait:Patroni 主循环间隔,每个循环执行一次健康检查与状态同步,影响故障发现的及时性。
  • retry_timeout:DCS 操作重试超时,网络分区时 Patroni 在此期间持续重试,超时后主库主动降级防止脑裂。
  • primary_start_timeout:PG 崩溃后 Patroni 尝试本地重启的等待时间,超时后释放 Leader 锁触发切换。
  • safety_margin:Watchdog 安全边际,确保故障时有足够时间触发系统重启,避免脑裂。

HAProxy 参数

  • inter:正常状态下的健康检查间隔,服务状态稳定时使用。
  • fastinter:状态变化期的检查间隔,检测到状态变化时使用更短间隔加速确认。
  • downinter:DOWN 状态下的检查间隔,服务标记为 DOWN 后使用此间隔探测恢复。
  • rise:标记 UP 所需连续成功次数,新主上线后需连续通过 rise 次检查才能接收流量。
  • fall:标记 DOWN 所需连续失败次数,服务需连续失败 fall 次才会被标记为 DOWN。

关键约束

Patroni 核心约束:确保主库能在 TTL 过期前完成降级,防止脑裂。

loop_wait+2×retry_timeoutttlloop\_wait + 2 \times retry\_timeout \leq ttl

数据汇总


配置建议

fast 模式 适用于对 RTO 要求极高的场景,但需要确保网络质量足够好(延迟 < 1ms,极低丢包率)。 建议仅在同机柜或同交换机部署时使用,并在生产环境充分测试后再启用。

norm 模式默认)是 Pigsty 默认使用的配置,对于绝大多数同机房部署的业务来说已经足够使用。 平均 21 秒的恢复时间在可接受范围内,同时提供了合理的容错窗口,避免网络抖动导致的误切。

safe 模式 适用于同城跨机房部署,网络延迟较高或存在偶发抖动的场景。 更长的容错窗口可以有效避免网络抖动导致的误切,是跨机房容灾的推荐配置。

wide 模式 适用于跨地域甚至跨大洲部署,网络延迟高且可能存在公网级别的丢包率。 这种场景下,稳定性比恢复速度更重要,因此使用极宽的容错窗口来确保极低的误切率。

模式目标 RTO被动检测 RTO主动检测 RTO场景
fast3016 / 23 / 291 / 24 / 29同交换机,高质量网络
norm4527 / 34 / 412 / 35 / 41默认,同机房,标准网络
safe9053 / 66 / 783 / 61 / 73同城双活 / 跨机房容灾
wide150104 / 127 / 1504 / 122 / 145异地容灾 / 跨国部署
default32622 / 34 / 462 / 314 / 326Patroni 默认参数

通常只需将 pg_rto 设为模式名称,Pigsty 会自动配置 Patroni 与 HAProxy 参数。 为了保持向后兼容性,Pigsty 仍然支持直接使用秒数配置 RTO,但效果相当于指定 norm 模式。

配置模式实际上是从 pg_rto_plan 中加载对应参数集,您可以修改或覆盖此配置以实现自定义 RTO 策略。

pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
  fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]  # rto < 30s
  norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]  # rto < 45s
  safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]  # rto < 90s
  wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]  # rto < 150s

4.3 - 故障切换模型

详细分析三种经典故障检测/恢复路径下,最差,最优,平均 RTO 的计算逻辑与结果

Patroni 故障按故障对象分类可以分为以下 10 类,按照检测路径不同,可以进一步归纳为五类,在本节内详细展开。

#故障场景描述最终走哪条路径
1PG 进程崩溃crash、OOM killed主动检测
2PG 拒绝连接max_connections主动检测
3PG 假活进程在但无响应主动检测 (检测超时)
4Patroni 进程崩溃kill -9、OOM被动检测
5Patroni 假活进程在但卡住Watchdog
6节点宕机断电、硬件故障被动检测
7节点假活IO hang、CPU 饥饿Watchdog
8主库 ↔ DCS 网络中断防火墙、交换机故障网络分区
9存储故障磁盘坏、磁盘满、挂载失败主动检测Watchdog
10手动切换Switchover/Failover手动触发

但是在 RTO 计算上,最终所有故障都会收敛到两条路径上,本节深入探讨了这两种情况下的 RTO 上下限与均值。

flowchart LR
    A([主库故障]) --> B{Patroni<br/>检测到?}

    B -->|PG崩溃| C[尝试本地重启]
    B -->|节点宕机| D[等待 TTL 过期]

    C -->|成功| E([本地恢复])
    C -->|失败/超时| F[释放 Leader 锁]

    D --> F
    F --> G[从库竞选]
    G --> H[执行 Promote]
    H --> I[HAProxy 感知]
    I --> J([服务恢复])

    style A fill:#dc3545,stroke:#b02a37,color:#fff
    style E fill:#198754,stroke:#146c43,color:#fff
    style J fill:#198754,stroke:#146c43,color:#fff

4.3.1 - 被动故障切换

节点宕机,导致领导者租约过期触发集群领导竞选的故障路径

RTO 时序图


故障模型

项目最好最坏平均说明
租约过期ttl - loopttlttl - loop/2最好:即将刷新时宕机
最坏:刚刷新完就宕机
从库检测0looploop / 2最好:恰好在检测点
最坏:刚错过检测点
抢锁提拔021最好:直接抢锁提升
最坏:API 超时+Promote
健康检查(rise-1) × fastinter(rise-1) × fastinter + inter(rise-1) × fastinter + inter/2最好:检查前状态变化
最坏:检查后瞬间状态变化

被动故障与主动故障的核心区别

场景Patroni 状态租约处理主要等待时间
主动故障(PG 崩溃)存活,健康主动尝试重启 PG,超时后释放租约primary_start_timeout
被动故障(节点宕机)随节点一起死亡无法主动释放,只能等待 TTL 过期ttl

在被动故障场景中,Patroni 随节点一起宕机,无法主动释放 Leader Key。 DCS 中的租约只能等待 TTL 自然过期后触发集群选举。


时序分析

阶段 1:租约过期

Patroni 主库会在每个 loop_wait 周期刷新 Leader Key,将 TTL 重置为配置值。

时间线:
     t-loop        t          t+ttl-loop    t+ttl
       |           |              |           |
    上次刷新    故障发生        最好情况      最坏情况
       |←── loop ──→|              |           |
       |←──────────── ttl ─────────────────────→|
  • 最好情况:故障发生在即将刷新租约之前(距上次刷新已过 loop),剩余 TTL = ttl - loop
  • 最坏情况:故障发生在刚刷新租约之后,需等待完整 ttl
  • 平均情况ttl - loop/2
Texpire={ttlloop最好ttlloop/2平均ttl最坏T_{expire} = \begin{cases} ttl - loop & \text{最好} \\ ttl - loop/2 & \text{平均} \\ ttl & \text{最坏} \end{cases}

阶段 2:从库检测

从库在 loop_wait 周期醒来后检查 DCS 中的 Leader Key 状态。

时间线:
    租约过期      从库醒来
       |            |
       |←── 0~loop ─→|
  • 最好情况:租约过期时从库恰好醒来,等待 0
  • 最坏情况:租约过期后从库刚进入睡眠,等待 loop
  • 平均情况loop/2
Tdetect={0最好loop/2平均loop最坏T_{detect} = \begin{cases} 0 & \text{最好} \\ loop/2 & \text{平均} \\ loop & \text{最坏} \end{cases}

阶段 3:抢锁提拔

从库发现 Leader Key 过期后,开始竞选过程,获得 Leader Key 的从库执行 pg_ctl promote,将自己提升为新主库。

  1. 通过 Rest API,并行发起查询,查询各从库的复制位置,通常 10ms,硬编码 2 秒超时。
  2. 比较 WAL 位置,确定最优候选,各从库尝试创建 Leader Key(CAS 原子操作)
  3. 执行 pg_ctl promote 提升自己为主库(很快,通常忽略不计)
选举流程:
  从库A ──→ 查询复制位置 ──→ 比较 ──→ 尝试抢锁 ──→ 成功
  从库B ──→ 查询复制位置 ──→ 比较 ──→ 尝试抢锁 ──→ 失败
  • 最好情况:单从库或直接抢到锁并提升,常数开销 0.1s
  • 最坏情况:DCS API 调用超时:2s
  • 平均情况1s 常数开销
Telect={0.1最好1平均2最坏T_{elect} = \begin{cases} 0.1 & \text{最好} \\ 1 & \text{平均} \\ 2 & \text{最坏} \end{cases}

阶段 4:健康检查

HAProxy 检测新主库上线,需要连续 rise 次健康检查成功。

检测时序:
  新主提升    首次检查    第二次检查   第三次检查(UP)
     |          |           |           |
     |←─ 0~inter ─→|←─ fast ─→|←─ fast ─→|
  • 最好情况:新主提升时恰好赶上检查,(rise-1) × fastinter
  • 最坏情况:新主提升后刚错过检查,(rise-1) × fastinter + inter
  • 平均情况(rise-1) × fastinter + inter/2
Thaproxy={(rise1)×fastinter最好(rise1)×fastinter+inter/2平均(rise1)×fastinter+inter最坏T_{haproxy} = \begin{cases} (rise-1) \times fastinter & \text{最好} \\ (rise-1) \times fastinter + inter/2 & \text{平均} \\ (rise-1) \times fastinter + inter & \text{最坏} \end{cases}

RTO 公式

将各阶段时间相加,得到总 RTO:

最好情况

RTOmin=ttlloop+0.1+(rise1)×fastinterRTO_{min} = ttl - loop + 0.1 + (rise-1) \times fastinter

平均情况

RTOavg=ttl+1+inter/2+(rise1)×fastinterRTO_{avg} = ttl + 1 + inter/2 + (rise-1) \times fastinter

最坏情况

RTOmax=ttl+loop+2+inter+(rise1)×fastinterRTO_{max} = ttl + loop + 2 + inter + (rise-1) \times fastinter

模型计算

将四种 RTO 模型的参数带入上面的公式:

pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
  fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]  # rto < 30s
  norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]  # rto < 45s
  safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]  # rto < 90s
  wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]  # rto < 150s

四种模式计算结果(单位:秒,格式:min / avg / max)

阶段fastnormsafewide
租约过期15 / 17 / 2025 / 27 / 3050 / 55 / 60100 / 110 / 120
从库检测0 / 3 / 50 / 3 / 50 / 5 / 100 / 10 / 20
抢锁提拔0 / 1 / 20 / 1 / 20 / 1 / 20 / 1 / 2
健康检查1 / 2 / 22 / 3 / 43 / 5 / 64 / 6 / 8
总计16 / 23 / 2927 / 34 / 4153 / 66 / 78104 / 127 / 150

4.3.2 - 主动故障检测

PostgreSQL 主库进程崩溃,Patroni 存活并尝试重启,超时后触发故障切换的路径

RTO 时序图


故障模型

项目最好最坏平均说明
故障检测0looploop/2最好:PG 恰好在检测前崩溃
最坏:PG 刚检测完就崩溃
重启超时0startstart最好:PG 瞬间自愈
最坏:等满 start 超时才释放租约
从库检测0looploop/2最好:恰好在检测点
最坏:刚错过检测点
抢锁提拔021最好:直接抢锁提升
最坏:API 超时 + Promote
健康检查(rise-1) × fastinter(rise-1) × fastinter + inter(rise-1) × fastinter + inter/2最好:检查前状态变化
最坏:检查后瞬间状态变化

主动故障与被动故障的核心区别

场景Patroni 状态租约处理主要等待时间
主动故障(PG 崩溃)存活,健康主动尝试重启 PG,超时后释放租约primary_start_timeout
被动故障(节点宕机)随节点一起死亡无法主动释放,只能等待 TTL 过期ttl

在主动故障场景中,Patroni 仍然存活,能够主动检测到 PG 崩溃并尝试重启。 如果重启成功,服务自愈;如果超时仍未恢复,Patroni 会主动释放 Leader Key,触发集群选举。


时序分析

阶段 1:故障检测

Patroni 在每个 loop_wait 周期检查 PostgreSQL 状态(通过 pg_isready 或检查进程)。

时间线:
    上次检测      PG崩溃      下次检测
       |           |           |
       |←── 0~loop ─→|          |
  • 最好情况:PG 恰好在 Patroni 检测前崩溃,立即被发现,等待 0
  • 最坏情况:PG 刚检测完就崩溃,需等待下一个周期,等待 loop
  • 平均情况loop/2
Tdetect={0最好loop/2平均loop最坏T_{detect} = \begin{cases} 0 & \text{最好} \\ loop/2 & \text{平均} \\ loop & \text{最坏} \end{cases}

阶段 2:重启超时

Patroni 检测到 PG 崩溃后,会尝试重启 PostgreSQL。此阶段有两种可能的结果:

时间线:
  检测到崩溃     尝试重启     重启成功/超时
      |           |             |
      |←──── 0 ~ start ────────→|

路径 A:自愈成功(最好情况)

  • PG 成功重启,服务恢复
  • 不触发故障切换,RTO 极短
  • 等待时间:0(相对于 Failover 路径)

路径 B:需要 Failover(平均/最坏情况)

  • 等待 primary_start_timeout 超时后 PG 仍未恢复
  • Patroni 主动释放 Leader Key
  • 等待时间:start
Trestart={0最好(自愈成功)start平均(需要 Failover)start最坏T_{restart} = \begin{cases} 0 & \text{最好(自愈成功)} \\ start & \text{平均(需要 Failover)} \\ start & \text{最坏} \end{cases}

注意:平均情况假设需要进行故障切换。如果 PG 能够快速自愈,则整体 RTO 会大幅降低。

阶段 3:从库检测

从库在 loop_wait 周期醒来后检查 DCS 中的 Leader Key 状态。当主库 Patroni 释放 Leader Key 后,从库发现后开始竞选。

时间线:
    租约释放      从库醒来
       |            |
       |←── 0~loop ─→|
  • 最好情况:租约释放时从库恰好醒来,等待 0
  • 最坏情况:租约释放后从库刚进入睡眠,等待 loop
  • 平均情况loop/2
Tstandby={0最好loop/2平均loop最坏T_{standby} = \begin{cases} 0 & \text{最好} \\ loop/2 & \text{平均} \\ loop & \text{最坏} \end{cases}

阶段 4:抢锁提拔

从库发现 Leader Key 空缺后,开始竞选过程,获得 Leader Key 的从库执行 pg_ctl promote,将自己提升为新主库。

  1. 通过 Rest API,并行发起查询,查询各从库的复制位置,通常 10ms,硬编码 2 秒超时。
  2. 比较 WAL 位置,确定最优候选,各从库尝试创建 Leader Key(CAS 原子操作)
  3. 执行 pg_ctl promote 提升自己为主库(很快,通常忽略不计)
选举流程:
  从库A ──→ 查询复制位置 ──→ 比较 ──→ 尝试抢锁 ──→ 成功
  从库B ──→ 查询复制位置 ──→ 比较 ──→ 尝试抢锁 ──→ 失败
  • 最好情况:单从库或直接抢到锁并提升,常数开销 0.1s
  • 最坏情况:DCS API 调用超时:2s
  • 平均情况1s 常数开销
Telect={0.1最好1平均2最坏T_{elect} = \begin{cases} 0.1 & \text{最好} \\ 1 & \text{平均} \\ 2 & \text{最坏} \end{cases}

阶段 5:健康检查

HAProxy 检测新主库上线,需要连续 rise 次健康检查成功。

检测时序:
  新主提升    首次检查    第二次检查   第三次检查(UP)
     |          |           |           |
     |←─ 0~inter ─→|←─ fast ─→|←─ fast ─→|
  • 最好情况:新主提升时恰好赶上检查,(rise-1) × fastinter
  • 最坏情况:新主提升后刚错过检查,(rise-1) × fastinter + inter
  • 平均情况(rise-1) × fastinter + inter/2
Thaproxy={(rise1)×fastinter最好(rise1)×fastinter+inter/2平均(rise1)×fastinter+inter最坏T_{haproxy} = \begin{cases} (rise-1) \times fastinter & \text{最好} \\ (rise-1) \times fastinter + inter/2 & \text{平均} \\ (rise-1) \times fastinter + inter & \text{最坏} \end{cases}

RTO 公式

将各阶段时间相加,得到总 RTO:

最好情况(PG 瞬间自愈)

RTOmin=0+0+0+0.1+(rise1)×fastinter(rise1)×fastinterRTO_{min} = 0 + 0 + 0 + 0.1 + (rise-1) \times fastinter \approx (rise-1) \times fastinter

平均情况(需要 Failover)

RTOavg=loop+start+1+inter/2+(rise1)×fastinterRTO_{avg} = loop + start + 1 + inter/2 + (rise-1) \times fastinter

最坏情况

RTOmax=loop×2+start+2+inter+(rise1)×fastinterRTO_{max} = loop \times 2 + start + 2 + inter + (rise-1) \times fastinter

模型计算

将四种 RTO 模型的参数带入上面的公式:

pg_rto_plan:  # [ttl, loop, retry, start, margin, inter, fastinter, downinter, rise, fall]
  fast: [ 20  ,5  ,5  ,15 ,5  ,'1s' ,'0.5s' ,'1s' ,3 ,3 ]  # rto < 30s
  norm: [ 30  ,5  ,10 ,25 ,5  ,'2s' ,'1s'   ,'2s' ,3 ,3 ]  # rto < 45s
  safe: [ 60  ,10 ,20 ,45 ,10 ,'3s' ,'1.5s' ,'3s' ,3 ,3 ]  # rto < 90s
  wide: [ 120 ,20 ,30 ,95 ,15 ,'4s' ,'2s'   ,'4s' ,3 ,3 ]  # rto < 150s

四种模式计算结果(单位:秒,格式:min / avg / max)

阶段fastnormsafewide
故障检测0 / 3 / 50 / 3 / 50 / 5 / 100 / 10 / 20
重启超时0 / 15 / 150 / 25 / 250 / 45 / 450 / 95 / 95
从库检测0 / 3 / 50 / 3 / 50 / 5 / 100 / 10 / 20
抢锁提拔0 / 1 / 20 / 1 / 20 / 1 / 20 / 1 / 2
健康检查1 / 2 / 22 / 3 / 43 / 5 / 64 / 6 / 8
总计1 / 24 / 292 / 35 / 413 / 61 / 734 / 122 / 145

与被动故障对比

阶段主动故障(PG 崩溃)被动故障(节点宕机)说明
检测机制Patroni 主动检测TTL 被动过期主动检测更快发现故障
核心等待startttlstart 通常小于 ttl,但需要额外的故障检测时间
租约处理主动释放被动过期主动释放更及时
自愈可能✅ 有❌ 无主动检测可尝试本地恢复

RTO 对比(平均情况):

模式主动故障(PG 崩溃)被动故障(节点宕机)差异
fast24s23s+1s
norm35s34s+1s
safe61s66s-5s
wide122s127s-5s

分析:在 fastnorm 模式下,主动故障的 RTO 略高于被动故障,因为需要等待 primary_start_timeoutstart); 但在 safewide 模式下,由于 start < ttl - loop,主动故障反而更快。 不过主动故障有自愈的可能性,最好情况下 RTO 可以极短。

4.4 - 服务接入

Pigsty 使用 HAProxy 提供服务接入,并提供可选的 pgBouncer 池化连接,以及可选的 L2 VIP 与 DNS 接入。

分离读写操作,正确路由流量,稳定可靠地交付 PostgreSQL 集群提供的能力。

服务 是一种抽象:它是数据库集群对外提供能力的形式,并封装了底层集群的细节。

服务对于生产环境中的 稳定接入 至关重要,在 高可用 集群自动故障时方显其价值,单机用户 通常不需要操心这个概念。


单机用户

“服务” 的概念是给生产环境用的,个人用户/单机集群可以不折腾,直接拿实例名/IP 地址访问数据库。

例如,Pigsty 默认的单节点 pg-meta.meta 数据库,就可以直接用下面三个不同的用户连接上去。

psql postgres://dbuser_dba:DBUser.DBA@10.10.10.10/meta     # 直接用 DBA 超级用户连上去
psql postgres://dbuser_meta:DBUser.Meta@10.10.10.10/meta   # 用默认的业务管理员用户连上去
psql postgres://dbuser_view:DBUser.View@pg-meta/meta       # 用默认的只读用户走实例域名连上去

服务概述

在真实世界生产环境中,我们会使用基于复制的主从数据库集群。集群中有且仅有一个实例作为领导者(主库)可以接受写入。 而其他实例(从库)则会从持续从集群领导者获取变更日志,与领导者保持一致。同时,从库还可以承载只读请求,在读多写少的场景下可以显著分担主库的负担, 因此对集群的写入请求与只读请求进行区分,是一种十分常见的实践。

此外对于高频短连接的生产环境,我们还会通过连接池中间件(Pgbouncer)对请求进行池化,减少连接与后端进程的创建开销。但对于 ETL 与变更执行等场景,我们又需要绕过连接池,直接访问数据库。 同时,高可用集群在故障时会出现故障切换(Failover),故障切换会导致集群的领导者出现变更。因此高可用的数据库方案要求写入流量可以自动适配集群的领导者变化。 这些不同的访问需求(读写分离,池化与直连,故障切换自动适配)最终抽象出 服务 (Service)的概念。

通常来说,数据库集群都必须提供这种最基础的服务:

  • 读写服务(primary):可以读写数据库

对于生产数据库集群,至少应当提供这两种服务:

  • 读写服务(primary):写入数据:只能由主库所承载。
  • 只读服务(replica):读取数据:可以由从库承载,没有从库时也可由主库承载

此外,根据具体的业务场景,可能还会有其他的服务,例如:

  • 默认直连服务(default):允许(管理)用户,绕过连接池直接访问数据库的服务
  • 离线从库服务(offline):不承接线上只读流量的专用从库,用于 ETL 与分析查询
  • 同步从库服务(standby):没有复制延迟的只读服务,由 同步备库 /主库处理只读查询
  • 延迟从库服务(delayed):访问同一个集群在一段时间之前的旧数据,由 延迟从库 来处理

接入服务

Pigsty 的服务交付边界止步于集群的 HAProxy,用户可以用各种手段访问这些负载均衡器。

典型的做法是使用 DNS 或 VIP 接入,将其绑定在集群所有或任意数量的负载均衡器上。

pigsty-access.jpg

你可以使用不同的 主机 & 端口 组合,它们以不同的方式提供 PostgreSQL 服务。

主机

类型样例描述
集群域名pg-test通过集群域名访问(由 dnsmasq @ infra 节点解析)
集群 VIP 地址10.10.10.3通过由 vip-manager 管理的 L2 VIP 地址访问,绑定到主节点
实例主机名pg-test-1通过任何实例主机名访问(由 dnsmasq @ infra 节点解析)
实例 IP 地址10.10.10.11访问任何实例的 IP 地址

端口

Pigsty 使用不同的 端口 来区分 pg services

端口服务类型描述
5432postgres数据库直接访问 postgres 服务器
6432pgbouncer中间件访问 postgres 前先通过连接池中间件
5433primary服务访问主 pgbouncer (或 postgres)
5434replica服务访问备份 pgbouncer (或 postgres)
5436default服务访问主 postgres
5438offline服务访问离线 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://test@10.10.10.3:5432/test # L2 VIP -> 主直接访问
postgres://test@10.10.10.3:6432/test # L2 VIP -> 主连接池 -> 主
postgres://test@10.10.10.3:5433/test # L2 VIP -> HAProxy -> 主连接池 -> 主
postgres://test@10.10.10.3:5434/test # L2 VIP -> HAProxy -> 备份连接池 -> 备份
postgres://dbuser_dba@10.10.10.3:5436/test # L2 VIP -> HAProxy -> 主直接连接 (用于管理员)
postgres://dbuser_stats@10.10.10.3::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://test@10.10.10.11:5432/test # 数据库实例直接连接 (直接指定实例, 没有自动流量分配)
postgres://test@10.10.10.11:6432/test # 连接池 -> 数据库
postgres://test@10.10.10.11:5433/test # HAProxy -> 连接池 -> 数据库读/写
postgres://test@10.10.10.11:5434/test # HAProxy -> 连接池 -> 数据库只读
postgres://dbuser_dba@10.10.10.11:5436/test # HAProxy -> 数据库直接连接
postgres://dbuser_stats@10.10.10.11:5438/test # HAProxy -> 数据库离线读-写

# 智能客户端:通过URL读写分离
postgres://test@10.10.10.11:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=primary
postgres://test@10.10.10.11:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=prefer-standby

5 - 时间点恢复 —— 数据库的时间机器(PITR)

高可用解决"机器坏了",时间点恢复解决"数据错了"。Pigsty 基于 pgBackRest 提供开箱即用的 PITR 能力,让您可以将集群回滚至恢复窗口内的任意时刻,为人为失误与软件缺陷兜底。

当您不小心删除了数据、表、甚至整个数据库时,时间点恢复(Point-in-Time Recovery,PITR)让您可以回到过去。

—— 这个曾经只有资深 DBA 才能施展的『魔法』,在 Pigsty 的标准配置中零配置开箱即用。


复制不是备份

高可用 可以在硬件故障时自动切换主库,让服务免于中断。但它有一个天然的盲区:复制不是备份

流复制会以毫秒级的延迟,把主库上发生的一切忠实地同步到所有从库 —— 包括那条忘了加 WHEREDELETE, 和那句敲错了目标库的 DROP TABLE。故障切换应对的是"机器坏了";而当"数据错了"的时候,每一个副本上的数据都错得整整齐齐。

数据库的灾难大体可以分为这两类。前者靠冗余解决:多个副本、自动切换,这是高可用的职责范围。 后者的唯一解药是 历史:基础备份与 WAL 归档让数据库回到错误发生之前。这正是时间点恢复所做的事情。

威胁高可用延迟集群时间点恢复
硬件故障,实例宕机✔ 自动切换✔ 但 RTO 较长
误删数据 / 误删表 / 误删库✘ 错误被复制✔ 延迟窗口内✔ 恢复窗口内任意时刻
软件缺陷批量污染数据✘ 错误被复制✔ 延迟窗口内✔ 可反复尝试不同时间点
整个集群 / 机房级灾难✔ 需使用远程备份仓库

三者并非互相替代,而是互相补位:高可用负责秒级止血,延迟集群提供快速反悔窗口,而 PITR 是所有防线失守之后的最终兜底。


时间机器的原理

PITR 并不神秘。数据库本质上是一台状态机:基础备份 是某个时刻状态的完整快照, WAL(预写式日志)则是此后每一次状态变更的完整历史。拥有一份快照,再加上从快照开始的完整历史, 就可以把数据库重放到这段历史所覆盖的 任意时刻 —— 快照决定了您能回到多早,归档的进度决定了您能回到多近。

基础备份 + WAL 归档 = 时间点恢复

这两样原料的生产在 Pigsty 中都是自动编排的:集群初始化时默认尝试执行首次全量备份,主库持续将 WAL 段文件推送至备份仓库归档; 关于快照、历史、恢复目标与时间线的完整模型,请参阅 工作原理


开箱即用

在 Pigsty 的标准配置中,PITR 默认启用:每套 PostgreSQL 集群都带有备份仓库、WAL 归档与恢复工具, 由 pgBackRest 驱动。您也可以用几行声明式配置对备份策略进行深度定制:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pgbackrest_method: minio       # 备份写入 MinIO 对象存储仓库(默认为 local 本地仓库)
    pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]  # 每天凌晨一点执行全量备份

默认使用主库本地磁盘作为备份仓库(/pg/backup),保留最近两个全量备份;每日全备时,恢复窗口约为 24~48 小时。 切换到专用 MinIO 集群或 S3 对象存储后,备份获得独立于数据库主机的故障域与 AES-256 加密; 按时间保留十四天并每周全备时,恢复窗口约为 14~21 天。只要存储管够,恢复窗口丰俭由人。

恢复同样是声明式的:指定恢复目标,剧本完成停库、还原、重放与重建高可用,业务数据由人验证。

./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": { "time": "2026-07-11 10:00:00+08", "action": "promote" }}'

这个设计与 声明式配置 的理念一脉相承:备份策略是集群定义的一部分, 而"回到过去"也不过是一个 参数


收益与代价

PITR 为数据安全提供的是 完整性可用性 的跃升:

  • RPO(最大数据损失):通常降至分钟级,只丢失最后尚未归档的 WAL。
  • RTO(恢复耗时):从 ∞(永久丢失)降至几十分钟到几小时,取决于备份大小与磁盘/网络带宽。
单实例配置策略事件RTORPO
什么也不做主机与本地数据同时丢失永久丢失全部丢失
基础备份主机与本地数据同时丢失取决于备份大小与带宽(几小时)丢失上次备份后的数据(几小时到几天)
基础备份 + WAL 归档主机与本地数据同时丢失取决于备份大小与带宽(几小时)丢失最后尚未归档的数据

而它的代价,则主要落在另外三处:

  • 机密性:备份本身是额外的数据泄露面,需要加密与访问控制的保护(Pigsty 的远程仓库预设启用 AES-256 加密)。
  • 资源:备份占用存储空间,归档占用网络带宽 —— 在 zstd 压缩与块级增量备份的加持下,这通常不构成问题。
  • 复杂度:备份需要管理、监控,以及最容易被忽略的一环 —— 恢复演练。

也要清醒地认识 PITR 的局限:单靠"单机 + PITR",故障时的 RTO 与 RPO 都显著逊色于高可用集群。 所以在严肃的生产环境中,两者应当组合使用 —— 高可用应对硬件故障,PITR 应对删库跑路。


接下来

  • 工作原理:快照与历史、恢复窗口、恢复目标与时间线 —— 建立 PITR 的心智模型
  • 实现架构:pgBackRest 引擎、仓库抽象、归档链路,以及"备份跟随主库"的工程细节
  • 策略权衡:故障域、空间与窗口、备份频率 —— 如何为您的场景设计备份策略
  • 声明式恢复pg_pitr 参数、pgsql-pitr.yml 剧本与 pig pitr 命令行工具
  • 典型场景:误删数据、发布事故、机房灾难 —— 事故发生时如何决策

具体操作手册请参阅任务层文档 PGSQL 备份恢复

5.1 - 时间点恢复的工作原理

快照与历史、恢复窗口、恢复目标与时间线:理解 PITR 的四个核心概念,建立正确的心智模型。

如果把数据库看作一台状态机,那么 WAL(Write-Ahead Log,预写式日志)就是它的完整变更历史 —— PostgreSQL 的每一次写入,都会先以日志记录的形式落盘,然后才应用到数据文件上。 这个为崩溃恢复而生的机制带来了一个副产品:只要把某个时刻的数据文件快照保存下来, 再持续保留此后产生的 WAL,就可以把数据库 重放 到这段历史所覆盖的任意时间点。

这就是时间点恢复的全部原理。它不是魔法,而是三个朴素概念的组合:快照(基础备份)、历史(WAL 归档)、目标(恢复到哪一刻)。


快照:基础备份

基础备份(Base Backup)是数据库集群在某一时刻的物理快照,它决定了恢复的 起点。 Pigsty 使用 pgBackRest 制作与管理基础备份,支持三种备份类型:

类型内容特点
全量备份(full)复制整个数据库集群独立可用,恢复最快,占用空间最大
差异备份(diff)相对最近一次 全量备份 的变化恢复需要:全量 + 差异
增量备份(incr)相对最近一次 任意备份 的变化空间最省,恢复需要完整备份链

备份通过封装脚本 pg-backup [full|diff|incr] 触发,不带参数时默认执行增量备份, 若仓库中尚无全量备份则自动升级为全量。备份任务由 pg_crontab 参数声明, 写入 postgres 用户的 crontab 定时执行。

基础备份的频率决定了恢复的速度:备份越新,恢复时需要重放的 WAL 就越少。 这是 策略权衡 中的关键变量之一。


历史:WAL 归档

快照只能让您回到备份的那一刻,而 WAL 归档 补全了此后的每一步。 Pigsty 默认在集群上开启归档,由 PostgreSQL 在每个 WAL 段文件(16 MB)写满后触发归档命令,交给 pgBackRest 推送至备份仓库:

archive_mode: 'on'                                            # 开启 WAL 归档
archive_command: 'pgbackrest --stanza=pg-meta archive-push %p' # 交由 pgBackRest 推送
archive_timeout: 300                                          # 低写入时最多五分钟触发切段归档

两个细节值得注意:

  • archive_timeout: 300 给恢复窗口的右边界上了一道保险:只要期间产生过 WAL,即使段文件迟迟写不满, 五分钟后也会触发切段归档,通常把归档延迟控制在分钟级。
  • 异步归档archive-async=y):pgBackRest 使用本地假脱机目录(/pg/spool)异步批量推送 WAL, 避免归档吞吐成为主库写入的瓶颈。Pigsty 将归档队列上限设为 4 GiB —— 队列指主库上尚未归档的 WAL 积压; 仓库长期不可用导致积压超限时,pgBackRest 会丢弃这些 WAL 以保护主库磁盘,代价是归档断链 —— 需要执行新的全量备份才能重新建立 PITR 能力。

归档的清理是自动的:pgBackRest 在过期备份被清除时,一并清理不再被任何备份需要的 WAL 归档。


恢复窗口

快照与历史合在一起,构成了 恢复窗口(Recovery Window)—— 您能够回到的时间范围:

  • 左边界:仓库中最早的那个基础备份的完成时刻 —— 再往前的历史已被保留策略清除。
  • 右边界:最新已归档的 WAL 位置 —— 通常距当前时刻不超过几分钟。

恢复窗口是滑动的:新备份不断产生,旧备份按保留策略过期,窗口随时间整体前移。 在 Pigsty 的仓库预设中,本地仓库保留最近两个全量备份(每日全备时窗口约一至两天), MinIO / S3 仓库按时间至少保留十四天。每周全备时,稳态窗口约为十四至二十一天。 窗口的长短本质上是空间与需求的权衡,详见 策略权衡


目标:恢复到哪一刻

恢复窗口内的定位方式不止"时间"一种。PostgreSQL 提供了六类恢复目标,Pigsty 通过 pg_pitr 参数统一封装:

目标类型说明典型场景
default重放全部 WAL,恢复到归档流末尾整库丢失后的灾难恢复
time恢复到指定时间戳误删数据 —— 最常用
xid恢复到指定事务 ID精确回退某个错误事务
lsn恢复到指定 WAL 位点按日志位置精确定位
name恢复到命名还原点事先用 pg_create_restore_point() 打点
immediate到达一致状态即停止最快可用,验证备份

边界语义

恢复目标默认是 包含(inclusive)的:目标点上的那个事务会被保留。 若要停在目标 之前(例如 xid 正是那个误删事务),使用 exclusive: true, 对应 PostgreSQL 的 recovery_target_inclusive = false

事务是恢复的原子单位:重放停止后,目标点前已提交的事务全部保留,未提交的事务全部回滚 —— 数据库最终呈现的一定是某个一致的瞬间,而不会出现"半个事务"。


时间线

恢复到过去并继续写入,历史就产生了 分叉。PostgreSQL 用 时间线(Timeline)来区分这些平行历史: 每次 PITR 恢复完成并提升后,都会创建一条新时间线,此后产生的 WAL 归属于新时间线,不会覆盖旧历史。

gitGraph
    commit id: "全量备份"
    commit id: "正常写入"
    commit id: "误删数据 ✗"
    commit id: "继续写入"
    branch Timeline-2
    checkout Timeline-2
    commit id: "PITR 恢复至误删前"
    commit id: "新的写入"

时间线的意义在于 可以反悔:旧时间线的 WAL 仍在仓库中,如果发现恢复的时间点选早了, 可以再次恢复到旧时间线上更晚的位置 —— 甚至"回到未来"。除 PITR 外,从库提升(Promote)与故障切换(Failover)同样会产生新时间线。

恢复时可以用 timeline 参数指定目标时间线,Pigsty 默认使用 latest


想知道这套机制在 Pigsty 中如何落地为具体的组件与配置?请继续阅读 实现架构

5.2 - 时间点恢复的实现架构

Pigsty 以 pgBackRest 为引擎实现 PITR:仓库抽象、归档链路、调度机制,以及"备份跟随主库"的工程设计。

原理 一页就能讲完,工程却没有那么简单: 归档不能拖垮主库的写入性能,备份放到对象存储上要加密,主从切换之后备份不能中断, 多套集群共用一个仓库时要相互隔离,海量小文件会拖垮备份吞吐……

Pigsty 选择 pgBackRest 作为备份引擎,并把这些工程问题的答案预置在了出厂配置中。 本文说明这套架构的组成:引擎、仓库、链路、调度,以及一个关键设计 —— 备份跟随主库。


备份引擎:pgBackRest

pgBackRest 是 PostgreSQL 生态中事实上的标准备份工具,Pigsty 用它承担三项职责: 执行基础备份(backup)、接收 WAL 归档(archive-push)、执行恢复(restore / archive-get)。 选择它的理由,恰好对应上面那些工程问题:

  • 并行:备份、归档、恢复都支持多进程并行,吞吐可以随核数扩展。
  • 增量:支持差异/增量备份与 块级增量(block incremental),只传输文件内部变化的块。
  • 压缩与加密:内置 zstd 压缩与 AES-256-CBC 加密,密文落盘,仓库泄露不等于数据泄露。
  • 多种仓库:本地磁盘、S3 兼容对象存储(MinIO、云厂商 OSS)、Azure、GCS、SFTP 皆可作为后端。
  • 打包bundle 特性将海量小文件合并为大对象存储,避免对象存储的小文件惩罚。

在仓库内部,pgBackRest 使用 stanza(节)隔离不同集群的备份。Pigsty 将 stanza 直接映射为集群名 pg_cluster,因此多套集群可以安全地共享同一个备份仓库:

备份仓库
├── backup/
│   ├── pg-meta/          # pg-meta 集群的基础备份
│   └── pg-test/          # pg-test 集群的基础备份
└── archive/
    ├── pg-meta/          # pg-meta 集群的 WAL 归档
    └── pg-test/          # pg-test 集群的 WAL 归档

仓库抽象

备份放在哪里,是备份策略中最重要的决定。Pigsty 把这个决定抽象为两个参数: pgbackrest_method 选择使用哪个仓库, pgbackrest_repo 定义所有候选仓库。默认提供两个开箱即用的选项:

pgbackrest_method: local          # 使用哪个仓库:local,minio,或自定义仓库名
pgbackrest_repo:                  # 仓库定义:https://pgbackrest.org/configuration.html#section-repository
  local:                          # 默认仓库:主库本地文件系统
    path: /pg/backup              # 备份目录,默认挂在主数据盘上
    retention_full_type: count    # 按份数保留全量备份
    retention_full: 2             # 保留最近 2 个全量备份(清理前最多 3 个)
  minio:                          # 可选仓库:MinIO / S3 兼容对象存储
    type: s3                      # MinIO 走 S3 兼容协议
    s3_endpoint: sss.pigsty       # MinIO 服务端点(负载均衡域名)
    s3_bucket: pgsql              # 桶名称
    s3_key: pgbackrest            # 访问密钥
    s3_key_secret: S3User.Backup  # MinIO 用户密钥
    storage_ca_file: /etc/pki/ca.crt  # 使用 Pigsty 自签名 CA 验证 HTTPS
    block: y                      # 启用块级增量备份
    bundle: y                     # 小文件打包存储
    cipher_type: aes-256-cbc      # 仓库加密:AES-256-CBC
    cipher_pass: pgBackRest       # 仓库加密密码
    retention_full_type: time     # 按时间保留全量备份
    retention_full: 14            # 按时间保留 14 天

注意两套预置仓库的策略差异:本地仓库 追求简单直接 —— 不加密、不打包、按份数保留; MinIO 仓库 面向生产 —— 加密、打包、块级增量、按时间保留两周。 这不是随意的默认值,而是对两种使用场景的判断:本地仓库与数据同生共死,重点是快; 远程仓库承担容灾职责,重点是安全与可追溯。

仓库定义到 pgBackRest 配置的转换是机械的:键名中的下划线替换为连字符,加上 repo1- 前缀, 渲染进 /etc/pgbackrest/pgbackrest.conf。所以 pgBackRest 支持的任何仓库选项都可以直接写进 pgbackrest_repo —— 例如添加一个云上 S3 仓库用于异地冷备:

s3:    # 自定义仓库 ------> /etc/pgbackrest/pgbackrest.conf
  type: s3                        # ----> repo1-type=s3
  s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
  s3_region: oss-cn-beijing       # ----> repo1-s3-region=oss-cn-beijing
  s3_bucket: <your_bucket>        # ----> repo1-s3-bucket=<your_bucket>
  s3_key: <your_access_key>       # ----> repo1-s3-key=<your_access_key>
  s3_key_secret: <your_secret>    # ----> repo1-s3-key-secret=<your_secret>
  s3_uri_style: host              # ----> repo1-s3-uri-style=host
  path: /pgbackrest               # ----> repo1-path=/pgbackrest
  cipher_type: aes-256-cbc        # ----> repo1-cipher-type=aes-256-cbc
  cipher_pass: <your_password>    # ----> repo1-cipher-pass=<your_password>
  retention_full_type: time       # ----> repo1-retention-full-type=time
  retention_full: 90              # ----> repo1-retention-full=90

各类仓库的完整配置方法(MinIO、阿里云 OSS、AWS S3、版本控制与对象锁定)请参阅 备份仓库


归档与调度

WAL 归档链路在集群初始化时自动接通:只要 pgbackrest_enabled 为真(默认),Patroni 配置模板就会为集群设置 archive_mode: onarchive_command: pgbackrest --stanza=<集群名> archive-push %p,WAL 段从此源源不断地流入备份仓库。

基础备份的生产则有两个入口:

  • 初始备份:集群初始化完成后,Pigsty 默认在主库上尝试执行一次全量备份(留下 /etc/pgbackrest/initial.done 标记,避免重复)。 可通过 pgbackrest_init_backup 关闭。
  • 定时备份pg_crontab 参数声明备份计划,写入 postgres 用户的 crontab。 Pigsty 随附的标准集群配置声明每天凌晨一点的全量备份;角色参数本身的默认值为空列表:
pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]

pg-backup 是 pgBackRest 的薄封装:自动解析 stanza,执行 pgbackrest backup,并做一件重要的事 —— 角色检查


备份跟随主库

pgBackRest 安装在集群的 所有 节点上,但任何时刻只有 当前主库 实际执行备份与归档: pg-backup 在运行前检查节点角色,从库上直接退出。这个看似简单的设计带来一个重要性质 —— 备份链路与高可用拓扑解耦

  • 所有节点的备份配置完全相同,crontab 也完全相同;
  • 故障切换 后,新主库自动接续后续备份与 WAL 归档,无需人工干预;
  • 备份仓库只有一份由当前主库写入的权威数据流,不存在双写冲突。

仓库在另一个方向上也参与高可用:当使用远程仓库时,Pigsty 将 pgBackRest 注册为 Patroni 的备用副本创建方式 (create_replica_methods)。默认仍先尝试 basebackup,失败后才使用 pgbackrest --delta restore 从仓库拉取数据; 走到这一后备路径时,造从库的流量压力会从主库转移到备份仓库。


性能取舍

出厂配置中还有几处针对性能的预置判断,体现同一个原则:备份为生产让路,恢复全力以赴

配置默认值考量
压缩算法zstd高压缩比与高吞吐的平衡点,备份体积通常远小于原库
备份/归档并行度约 1/4 核数(2~4 进程)备份不与生产负载争抢 CPU
恢复并行度核数(至多 8 进程)恢复时争分夺秒,资源全开
异步归档archive-async=y/pg/spool 假脱机批量推送,归档不阻塞写入
归档队列上限4 GiB未归档 WAL 积压超限时丢弃归档,保护主库磁盘不被写满
快速启动start-fast=y备份开始时立即执行检查点,不等常规检查点周期
增量恢复delta=y恢复时复用数据目录中未变化的文件,大幅缩短 RTO

归档队列上限的具体故障行为见 工作原理


可观测性

备份不被观测,就等于没有备份。每个 PostgreSQL 节点默认运行 pgbackrest_exporter(端口 9854), 将仓库中的备份状态导出为监控指标:最近一次备份的时刻、类型、大小、持续时间、错误状态 —— Grafana 监控面板与告警规则开箱即用。此外还有几个便捷入口:

入口说明
pb infopgbackrest info 的别名封装,查看仓库中的备份列表
/pg/log/pgbackrest/备份、归档、恢复的详细日志
pg-backup手动触发备份:full / diff / incr

关于备份的日常管理命令,请参阅 管理命令; 理解了架构之后,下一个问题是如何为您的场景选择策略 —— 请继续阅读 策略权衡

5.3 - 时间点恢复的策略权衡

备份是一份保险:备在哪里决定容灾等级,保留多久决定恢复窗口,多久备一次决定恢复速度 —— 三个问题定义一份备份策略。

备份本质上是一份保险:保费 是存储空间、网络带宽与管理成本,保额 是灾难来临时能挽回多少数据、多快恢复服务。 和所有保险一样,这里没有免费的午餐 —— 更长的恢复窗口意味着更多的空间,更快的恢复意味着更频繁的备份。

设计备份策略,就是回答三个问题:备在哪里?保留多久?多久备一次?


备在哪里:故障域决定容灾等级

备份仓库的位置是第一个、也是最重要的决定,因为它直接划定了备份能扛住哪个级别的灾难。

本地仓库pgbackrest_method: local)把备份放在主库本地磁盘上。它简单、快速、没有外部依赖, 恢复时走本地 I/O 速度最快 —— 但备份与数据共享同一个故障域:磁盘损毁、主机报废、机器被勒索加密时, 备份大概率与数据一同陪葬。它能对抗的是 逻辑错误(误删、缺陷),而不是 物理灾难

远程仓库pgbackrest_method: minio 或云上 S3)把备份放进独立的故障域。 数据库主机全灭,备份依然健在;配合 AES-256 加密与 MinIO 多节点纠删码, 还能对抗仓库侧的磁盘故障,并降低备份介质泄露造成的明文暴露风险。 代价是恢复速度受网络带宽制约,以及多维护一个组件。

场景推荐仓库理由
开发、测试、演示local零依赖,坏了重建,无须容灾
生产环境minio(专用集群)独立故障域,加密,多节点纠删码
云上部署S3 / OSS 等对象存储免维护,天然异地,成本低廉
高合规要求MinIO 版本控制 + 已配置保留期的对象锁定防篡改、防勒索:锁定版本在保留期内不可被永久删除

一个经常被忽略的角度:备份仓库同时是 安全资产。防勒索的关键不是"有备份", 而是"攻击者拿到数据库主机的最高权限后,依然无法销毁备份" —— 这正是对象存储的版本控制与对象锁定(WORM)的价值所在,详见 备份仓库


保留多久:空间与窗口

恢复窗口的长度由保留策略决定,而保留策略的成本是刚性的:窗口越长,空间越大,没有配置技巧可以绕开。

以一个 100 GB、每日变更 10 GB 的数据库为例(未计压缩):

  • 每日全量,保留两份(本地仓库默认思路):约 200 GB 备份 + 两天 WAL 归档 ≈ 2~3 倍 数据库大小, 换来一至两天的恢复窗口。
  • 每周全量 + 每日增量,按时间保留十四天(MinIO 仓库默认思路):稳态低点约三份全量 + 十二份增量 + 十四天 WAL,下一次全量前增至十八份增量与二十一天 WAL;恢复窗口约 十四至二十一天

实际占用通常显著低于这个粗估:zstd 压缩往往能将备份压缩数倍,块级增量(block: y) 使增量备份只存储文件内部真正变化的数据块。但数量级的规律不变 —— 为备份仓库规划 数倍于数据库 的空间是基本前提。

窗口应该多长?一个实用的标尺是:窗口必须覆盖"错误从发生到被发现"的延迟。 误删表通常几分钟内就会被发现,一天的窗口绰绰有余;而缓慢污染数据的软件缺陷、 要到月底对账才暴露的错误,则需要以周计的窗口。“本地一两天、远程至少两周"正是对这两类需求的回应。


多久备一次:频率与恢复速度

恢复耗时(RTO)由两段组成:还原基础备份 的时间加上 重放 WAL 的时间。 备份大小决定前者,备份 频率 决定后者 —— 距离恢复目标最近的那个基础备份越新,需要重放的 WAL 就越少。

WAL 重放是单进程的,而且重放高峰期写入的 WAL 可能比还原备份本身还慢。 对写入繁忙的库,如果恢复目标恰好落在下一次备份之前,“每周全量"可能需要重放接近一周的 WAL —— 这正是增量备份的价值: 以极小的空间代价(块级增量下通常只有全量的百分之几),把"需要重放的历史"每天清零一次。

经验法则:备份窗口允许的前提下,宁可提高备份频率,不要拉长重放距离


两种预设策略

Pigsty 把上述权衡沉淀为两套开箱即用的预设,多数场景可以直接采用或微调:

标准策略:本地仓库 + 每日全量。配置简单,恢复走本地磁盘速度最快,适合开发测试与容灾要求有限的场景:

pgbackrest_method: local               # 备份到主库本地 /pg/backup(默认值,可省略)
pg_crontab: [ '00 01 * * * /pg/bin/pg-backup full' ]   # 每日凌晨一点全量备份
# 保留最近两个全量备份,恢复窗口约一至两天

生产策略:MinIO 仓库 + 周全量日增量。独立故障域,AES-256 加密,十四至二十一天窗口,适合严肃生产环境:

pgbackrest_method: minio               # 备份到专用 MinIO 集群(或云上 S3)
pg_crontab:                            # 周一全量,其余每日增量
  - '00 01 * * 1 /pg/bin/pg-backup full'
  - '00 01 * * 2,3,4,5,6,7 /pg/bin/pg-backup'
# 按时间至少保留 14 天;周全备时恢复窗口约 14~21 天

空间估算与保留策略的可视化推演,请参阅任务层文档 备份策略


没有演练过的备份,不算备份

最后一个权衡维度不在配置里,而在流程里。备份系统最危险的状态,是"看起来一直在正常运行”: 监控绿灯长明,仓库稳步增长,而没有人知道这些备份 能不能恢复、恢复要多久

把恢复演练纳入例行运维:定期用 克隆恢复 把备份还原成一套新集群 —— 这既是对备份完整性的端到端验证,也是对 RTO 的实测校准,而且不触碰生产集群;演练目标集群仍会被覆盖。 恢复的具体机制与工具,请继续阅读 声明式恢复

5.4 - 声明式恢复

恢复不该是深夜里的十几步手工操作:用 pg_pitr 参数声明想回到的时刻,由 pgsql-pitr.yml 剧本或 pig 命令行工具编排执行。

备份系统的全部价值,都在恢复的那一刻兑现。而恢复几乎总是发生在最糟糕的时刻 —— 生产事故、深夜告警、每一分钟都在损失。传统的 PITR 手工流程在这种时刻是残酷的: 停 HA、停库、写恢复配置、执行还原、盯日志、验证位点、重建元数据、拉起集群……十几个步骤环环相扣,任何一步出错都可能雪上加霜。

Pigsty 的答案与 声明式配置 一脉相承:恢复也是声明式的。 您描述想回到的时刻,编排工具负责停库、还原、重放与重新接管。


声明恢复目标

恢复目标用 pg_pitr 参数描述,交给 pgsql-pitr.yml 剧本执行。 最常用的形式只有一行 —— 把集群恢复到指定时间点:

./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": { "time": "2026-07-11 10:00:00+08", "action": "promote" }}'

六类恢复目标 与恢复行为的方方面面,都是这个参数的字段:

pg_pitr:                      # 恢复目标定义(按需声明,字段均可省略)
  cluster: pg-meta            # 从哪个集群的备份恢复(源 stanza),默认为本集群
  type: time                  # 目标类型:default | time | xid | lsn | name | immediate
  time: '2026-07-11 10:00:00+08'  # 恢复到的时间点(与 xid / lsn / name 互斥)
  exclusive: false            # 停在目标之前(排除目标点),默认包含
  action: promote             # 显式提升;指定目标时未声明 action,实际默认为 pause
  timeline: latest            # 目标时间线,默认 latest
  set: latest                 # 从哪个备份集开始还原,默认自动选择
  repo: { ... }               # 临时指定备份仓库(不使用本机配置时)
  backup: false               # 恢复前是否把原数据目录搬到 /pg/data-backup 留作后悔药
  archive: true               # 保留原有归档配置;探索性恢复可设为 false
  db_include: [ ... ]         # 只恢复指定数据库(选择性恢复)
  data: /pg/data              # 恢复到哪个数据目录

完整的字段说明与用法示例请参阅 恢复操作


剧本如何执行

pgsql-pitr.yml 把手工恢复的十几个步骤编排为六个阶段,并支持用 tags 分段执行:

阶段动作
print汇总恢复计划:源集群、目标类型、还原命令;只打印,不会暂停等待确认
pausepatronictl pause:让 Patroni 进入维护模式,暂停高可用自动干预
stop依次停止从库与主库的 Patroni 及 PostgreSQL 进程
pitr渲染恢复配置,执行 pgbackrest restore(增量还原),启动进程重放 WAL,等待进入一致状态并打印控制信息
etcd清除 etcd 中的旧集群元数据,避免新旧时间线的状态混淆
start重新拉起 Patroni,恢复高可用自动驾驶,从库重新克隆

几处设计值得注意:

  • 增量还原:还原使用 pgBackRest 的 delta 模式,只重写数据目录中与备份不一致的文件。 对大库而言,这往往把"还原全库"缩短为"还原变化的部分",显著压缩 RTO。
  • 验证而非假设:剧本用 pg_controldata 打印检查点 LSN、时间线与 NextXID;最终仍由人检查业务数据是否正确。
  • 后悔药:声明 backup: true 时,恢复前会把原数据目录完整搬到 /pg/data-backup—— 如果恢复目标选错了,原现场还在。再次以 backup: true 运行会先删除已有的 /pg/data-backup,不要把它当成可反复覆盖的快照。
  • 分阶段执行:谨慎起见,可以用 tags 把恢复拆为三步走:-t down(停集群)、-t pitr(执行还原)、-t up(拉起集群), 每步之间人工检查。pitr 阶段返回只表示数据库已进入一致恢复状态;指定了时间、XID、LSN 或恢复点时,还要确认 WAL 已重放到目标。

恢复到达目标后的行为由 action 决定:promote(提升并开启新时间线)、 pause(暂停在目标点,可检查数据后再决定;指定目标时的实际默认值)、shutdown(停机待命)。 若要保留 pause / shutdown 的人工门,应分阶段执行并在确认后再运行 up;一步式执行应显式选择 promote。 剧本不会替您做"数据对不对"的判断 —— 这是工程师保留的最终决定权。


命令行工具:pig

除了 Ansible 剧本,pig 命令行工具提供了单实例粒度的 PITR 编排 —— 适合在数据库节点上直接操作,无需管理节点与剧本环境:

pig pitr -t "2026-07-11 10:00:00+08"    # 恢复到指定时间点
pig pitr --xid 250000 -X                # 恢复到事务 250000 之前(排除该事务)
pig pitr -d                             # 重放到 WAL 归档末尾(灾难恢复)
pig pitr -I --no-restart                # 只还原并准备 immediate 恢复,PostgreSQL 保持停止

pig pitr 执行单节点恢复编排:预检(校验目标、stanza、备份存在性)、 停止 Patroni 与 PostgreSQL、执行还原、按参数决定是否启动 PostgreSQL、给出恢复后指引。对于 Patroni 托管的数据目录, 恢复后 Patroni 会保持停止,验证数据后再用 pig pt start 恢复 HA 管理;它不会清理 etcd、重建副本或自动重入集群。 默认拒绝任何破坏性的强制停库动作,除非显式指定 --force-stop

更底层的 pig pb 系列命令封装了 pgBackRest 本身:pb info 查看备份、 pb backup 触发备份、pb restore 执行裸还原。这里有一道有意设置的硬边界: 当实例仍由 Patroni 托管时,pig pb restore 会直接拒绝执行 —— 因为 Patroni 会立刻把恢复到一半的库重新拉起,酿成事故。托管实例的恢复,请始终使用 pig pitrpgsql-pitr.yml


原地恢复与克隆恢复

同一套恢复机制,有两种截然不同的用法:

维度原地恢复克隆恢复
做法把生产集群整体回滚到过去用备份把 另一套集群 恢复到过去
停机需要(恢复期间服务不可用)不需要(生产集群不受影响)
影响目标点之后的 所有 写入都被抹去不影响源集群;目标集群会被覆盖,可反复尝试不同时间点
适用整库损毁、灾难恢复、可接受回滚误删找回、审计取证、恢复演练

克隆恢复的关键是 pg_pitrcluster 字段 —— 它指定 从谁的备份 恢复。 下面的命令把 pg-meta 的历史状态恢复到 pg-test 集群上,生产库全程无感:

./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": { "cluster": "pg-meta", "time": "2026-07-11 10:00:00+08", "archive": false, "action": "promote" }}'

从克隆集群中把误删的表 pg_dump 出来、导回生产,是处理误删除的标准姿势 —— 全库回滚是最后手段,而不是第一反应。克隆恢复的完整流程与善后事项,请参阅 克隆数据库集群


恢复之后

恢复完成不等于事情结束。有三件事应当纳入收尾清单:

  1. 新时间线,新备份:提升后集群运行在新时间线上。尽快执行一次全量备份(pg-backup full), 让恢复窗口在新时间线上重新建立。
  2. 归档状态:探索性恢复后,按 恢复后处理 恢复归档。
  3. 克隆善后:克隆出的新集群与源集群的备份身份(stanza)不一致,需要重建 stanza 后再启用自身的备份, 详见 克隆数据库集群

工具完成机械步骤,剩下的是判断:恢复到哪一刻、用原地还是克隆、数据对不对。 这些决策的框架,请继续阅读 典型场景

5.5 - 时间点恢复的典型场景

误删数据、发布事故、审计取证、机房灾难 —— 事故发生时如何选择恢复目标与恢复方式,以及为什么要把事故排练成例行演练。

事故发生时,最贵的不是恢复本身,而是 决策时间。 恢复的机械步骤已经被 工具编排 好了,真正需要人来回答的只有三个问题: 恢复到哪一刻?原地恢复还是克隆恢复?如何验证数据是对的?

本文为最常见的几类事故给出决策框架 —— 最好在事故发生之前读完它。


判断框架

场景典型问题推荐方式恢复目标
误删 / 误更新数据(DML)DELETE / UPDATE 忘加 WHERE克隆恢复,导回数据time / xid
误删表 / 库 / Schema(DDL)DROP TABLE / 错误迁移脚本克隆恢复,导回对象time / name
发布事故 / 批量污染缺陷代码批量写坏数据克隆恢复,比对后决策time / xid
审计 / 取证 / 复盘需要查看历史某刻的数据克隆恢复(只读)time / lsn
整库损毁 / 机房灾难硬件全灭、勒索加密原地恢复或异地重建default / time

贯穿所有场景的两条原则:

  • 先止损,再恢复。第一动作永远是阻止错误继续扩散:暂停问题应用、吊销问题账号的写权限。 恢复窗口在流逝,但慌乱中启动错误的恢复造成的二次伤害更大。
  • 克隆恢复是默认选项。它不触碰生产集群、可以反复尝试不同时间点、可以先验证再动手;代价是目标集群会被覆盖。 只有当集群已经整体不可用 —— 也就是"没有什么可失去"的时候,原地恢复才是首选。
flowchart TD
    A["发现数据错误"] --> B["止损:暂停错误来源"]
    B --> C{"生产集群还能服务吗?"}
    C -->|能| D["克隆恢复:另起集群回到错误前<br/>验证后导回数据"]
    C -->|不能| E["原地恢复:整体回滚<br/>或在新硬件上异地重建"]
    D --> F["善后:重建备份,复盘"]
    E --> F

误删数据(DML)

没加 WHEREDELETE、写错条件的 UPDATE、逻辑出错的批处理脚本 —— 这是 PITR 最高频的用武之地。

关键动作是 定位错误时刻:从应用日志、PostgreSQL 日志或监控曲线中找到错误发生的时间 (若启用了 审计日志,定位会更加精确)。 如果能定位到确切的事务号,xid 目标配合 exclusive 可以精确地停在错误事务 之前,一条数据都不多丢:

# 已知误删发生在 10:15 左右:克隆恢复到 10:14
./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": { "cluster": "pg-meta", "time": "2026-07-11 10:14:00+08", "archive": false, "action": "promote" }}'

# 已知误删事务号为 250000:精确停在该事务之前
./pgsql-pitr.yml -l pg-test -e '{"pg_pitr": { "cluster": "pg-meta", "xid": "250000", "exclusive": true, "archive": false, "action": "promote" }}'

数据在克隆集群中验证无误后,用 pg_dump / COPY 把受影响的行导回生产库。

如果集群配置了 延迟集群,且误删仍在延迟窗口之内, 直接从延迟从库读取数据更快 —— 这是 PITR 之外的第二条时间通道。


误删对象(DDL)

DROP TABLEDROP DATABASE、跑错环境的迁移脚本。与 DML 场景同理,但有一个更强的约束: DDL 误删几乎不应该原地恢复 —— 为了找回一张表就把整个库回滚到过去,等于把误删之后所有正常业务写入一并抹掉。

标准流程是克隆恢复:另起集群恢复到误删之前,校验对象完整性,pg_dump 导出误删的表 / 库,导回生产。 如果变更前用 pg_create_restore_point() 打过还原点,name 目标可以让"恢复到变更之前"变得毫无歧义 —— 在高危变更前打点,是成本几乎为零的好习惯。


发布事故与批量污染

某次发布带着缺陷上线,几个小时里持续写入错误数据 —— 这类场景的难点不是恢复,而是 影响范围不清楚

克隆恢复在这里的价值是提供一个 干净的对照组:把克隆集群恢复到发布之前,与生产库做数据比对, 量化污染范围,再决定是修复数据(把正确值从克隆库导回)还是整体回滚(切换到克隆集群)。 因为克隆恢复可以反复执行,您可以多次尝试不同时间点,逐步逼近"最后一个干净时刻"。


审计与取证

“上个月月底这个账户的余额是多少?"—— 有些问题只有历史数据能回答。 克隆恢复到指定时刻、以只读方式查询、用后即焚,是回答这类问题的标准做法: 不影响生产、不修改历史、可审计可复现。指定时间、LSN、XID 或命名恢复点并配合 action: pause, 集群可以停在目标点上供检查,而不推进到新时间线;immediate 只表示尽快恢复到首个一致点,不用于选择历史时刻。


机房级灾难

主从全灭、磁盘阵列损毁、勒索软件加密了所有主机 —— 高可用在这类灾难面前无能为力,PITR 是最后一道防线。 其中最关键的前提是:备份仓库在灾难的故障域之外。使用 远程备份仓库 时, 数据库主机全部丢失也不影响恢复;使用本地仓库时,这道防线并不存在。

恢复流程是在新硬件上重建:准备新节点,恢复配置清单(它本身应在 git 中,见 声明式配置), 将集群指向远程仓库,恢复到归档流末尾:

./pgsql-pitr.yml -l pg-meta -e '{"pg_pitr": {"action": "promote"}}'  # default:重放到归档流末尾并提升

配置清单与远程备份仓库是重建的两块核心拼图,但不是全部:还需要 Pigsty 安装介质或软件仓库、 备份访问凭据与加密口令、PKI/CA、自定义文件,以及 DNS 和其他外部依赖。配置清单可以纳入私有版本控制, 秘密与私钥则应加密保存并与备份分离 —— 这才是独立故障域真正的意义。


把事故排练成肌肉记忆

以上每个场景的第一次实战,都不应该发生在生产事故中。

克隆恢复给了您一个不触碰生产的演练场:可以把可访问的集群备份恢复成一套新集群,验证、计时、销毁;目标集群会被覆盖。 建议把恢复演练作为例行运维的一部分 —— 每季度(或每次重大架构变更后)完整走一遍克隆恢复流程,回答三个问题:

  1. 备份可用吗? 端到端还原成功,数据完整。
  2. RTO 是多少? 实测还原耗时,而不是估算 —— 数据库在增长,去年的答案今年未必成立。
  3. 人熟练吗? 值班工程师能否不翻文档完成恢复。

没有演练过的备份只是一种心理安慰。演练过的备份,才是真正的时间机器。

具体操作步骤请参阅 恢复操作克隆数据库集群

6 - 监控系统

Pigsty 的监控系统是如何架构与实现的,被监控的目标对象又是如何被自动纳入管理的。

Pigsty 监控系统由指标、日志与告警三部分组成,默认随部署开箱可用;其中日志与告警也是 审计与追溯 的重要输入。 它既可以监控由 Pigsty 托管的数据库集群,也可以监控已有 PostgreSQL 集群与外部 RDS 服务。


监控目标

Pigsty 监控覆盖的核心对象包括:

  • PostgreSQL 集群与实例(SQL 性能、连接、复制、事务、检查点、WAL)
  • 基础设施组件(Grafana、VictoriaMetrics、Alertmanager、Nginx 等)
  • 宿主机节点(CPU、内存、磁盘、网络、内核)
  • 关键中间件(ETCD、MINIO、REDIS、FERRET、JUICE、VIBE 等)

技术栈

组件作用
Grafana可视化监控面板、统一入口、告警视图
VictoriaMetrics时序指标采集、存储与查询
VictoriaLogs结构化日志采集、索引与检索
VMAlert + Alertmanager告警规则执行与消息通知
Exporter / Agent业务与系统指标暴露、日志转发

纳管方式

Pigsty 支持三种监控纳管方式:

模式适用场景入口
FULL数据库由 Pigsty 直接部署与托管PGSQL 监控系统
MANAGED现有 PostgreSQL 集群,节点可 SSH 管理监控现有集群
RDS仅能通过连接串访问的云数据库监控 RDS

继续阅读

7 - 安全合规

Pigsty 以安全即代码的方式管理认证、授权、加密、审计与备份恢复,并提供从默认配置到生产加固的清晰路径。

数据库通常是信息系统中最敏感的组件:它保存着最有价值的数据,也因此是攻击与故障后果最严重的地方。 数据库安全并不是某个可以一键开启的功能,而是一系列问题的答案之和:谁能连进来?连进来能做什么?流量会不会被窃听?操作有没有留痕?数据坏了、丢了、被删了,还能不能恢复?

Pigsty 把这些问题的答案沉淀为一套 开箱即用的安全基线,并用 声明式配置 的方式加以管理: HBA 规则角色与权限、证书与加密、备份与审计策略,全部以 参数 的形式在 配置清单 中声明,由幂等剧本渲染落地。

这种 安全即代码(Security as Code)的做法本身就是一项重要的安全实践:安全策略可以被版本控制、评审与回溯,配置清单为多实例环境提供统一基线。 当审计者问“谁能访问这个数据库”时,可以先从一份可读的 YAML 声明出发,再用实际生成的 HBA 与数据库授权验证它是否已经生效。


安全即代码

在传统运维中,安全配置散落在各个角落:某台服务器上的 pg_hba.conf,某位 DBA 手工执行过的 GRANT 语句,某次应急时临时放开的防火墙规则。 时间一长,文档与实际状态容易出现偏差,也很难快速确认各实例正在使用哪一版规则。

Pigsty 的做法不同:安全策略是集群定义的一部分,与集群的其他属性写在一起。

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_users:                     # 谁可以登录:账号、角色与过期时间
      - { name: dbuser_app ,password: '<独立随机口令>' ,roles: [dbrole_readwrite] ,expire_in: 365 }
    pg_databases:                 # 数据库及其隔离策略
      - { name: app ,owner: dbuser_app ,revokeconn: true }
    pg_hba_rules:                 # 谁能从哪里、以何种方式连接
      - { user: dbuser_app ,db: app ,addr: 10.1.0.0/16 ,auth: ssl ,order: 50 ,title: 'app access via ssl' }

用户、权限、HBA 规则以声明的方式描述,剧本负责把它们幂等地应用到集群的每个实例上: 新加入的实例可以沿用同一套策略,git 提交历史也可以记录安全配置的变更。手工执行的 GRANT、运行时参数修改和节点文件变更仍可能造成漂移,因此生产环境还需要定期核对实际状态。


默认安全基线

合理的默认值可以减少遗漏。以下能力在 Pigsty 默认配置下即处于启用状态:

能力默认行为相关参数
密码哈希新设置或更新的 PostgreSQL 口令使用 SCRAM-SHA-256pg_pwd_enc
数据校验和集群初始化时启用页级校验和,捕获静默数据损坏pg_checksum
服务端 TLSPostgreSQL 服务器证书就位并启用 ssl,可以接受 TLS 连接-
本地 CA自动创建自签名 CA,为受管组件签发证书ca_create
etcd 加密认证客户端与对等通信 TLS,RBAC 密码认证etcd_root_password
MinIO HTTPS备份存储流量默认走 HTTPSminio_https
Nginx HTTPSWeb 入口默认同时监听 80、443nginx_sslmode
HBA 规则集分层放行:本地 ident,内网口令,公网管理员强制 SSLpg_default_hba_rules
角色与权限四层角色模型与默认权限模板,提供最小权限基线pg_default_roles
备份恢复pgBackRest 默认启用,本地仓库保留两份全量备份pgbackrest_enabled
防火墙zone 模式:信任内网网段,公网仅放行必要端口node_firewall_mode
受限 sudo数据库系统用户的 sudo 被限制在必要命令集内pg_dbsu_sudo

有所取舍的加固项

默认配置面向运行在受信内网中的部署,一部分安全能力需要显式启用 —— 它们或有性能与兼容性代价,或需要用户提供额外的决策:

  • 默认配置与示例模板包含 文档公开的默认密码,方便快速上手与本地测试。生产部署应先用 ./configure -g 随机化其支持的凭据,再检查 pgBackRest 加密口令、ha/safe 中的 MinIO 用户和自定义值。
  • Patroni REST APIPgBouncer 的 TLS 默认未启用(patroni_ssl_enabledpgbouncer_sslmode),可以使用已经签发的证书显式开启。
  • 密码强度检查passwordcheck)与 审计扩展pgaudit)默认未启用;使用前应确认软件包可用,再完成预加载与策略配置。
  • SELinux 默认处于 permissive 模式;演示配置的防火墙额外放行了 5432 端口,生产环境应当移除。
  • 本地备份仓库默认 不加密;MinIO 备份仓库默认启用 AES-256 加密,但需要修改默认加密口令。

安全加固模板 ha/safe 将 TLS、证书认证、密码检查和备份加密等配置组合在一起, 并配合面向一致性优先业务的 CRIT 参数模板 给出一份可直接修改的示例。模板中的公开凭据、审计扩展与故障模型仍需逐项确认。 完整的升级路径见 安全模型


本章内容

章节回答的问题
安全模型信任的根在哪里?防线有几道?如何从默认基线逐步加固?
身份认证谁能连进来?如何证明身份?HBA 规则如何声明与生效?
访问控制连进来之后能做什么?最小权限如何成为默认行为?
加密通信流量如何加密?证书由谁签发、如何分发与轮换?
数据安全数据如何保证完整、可恢复、保密、可追溯?
合规实践如何把安全能力映射到等保与 SOC 2 的控制要求?

相关话题

概念层之外,以下页面提供操作层面的安全内容:

7.1 - 安全模型

Pigsty 的信任边界与纵深防御体系:管理节点作为高信任控制面,从默认基线逐步完成生产加固。

在讨论具体的安全特性之前,值得先回答两个更基本的问题:信任的根在哪里,以及 防线有几道。 前者决定了你应该重点保护什么,后者决定了当某一道防线失守时,你还剩下什么。


信任边界

Pigsty 是一套基于 Ansible 的声明式部署系统,它的信任模型与其他控制平面系统类似:管理节点 就是控制平面,也是整个部署中最需要保护的节点。

角色掌握的资产与权限
管理节点(Admin Node)配置清单 pigsty.yml(通常包含系统与业务凭据)、CA 私钥、对所有节点的 SSH 管理权限
INFRA 节点监控告警、DNS、Nginx 入口、软件仓库
数据库节点数据库实例、本地 dbsu、受限 sudo
客户端数据库凭据或客户端证书,经服务端口、HBA 与认证进入

这些角色掌握的能力不同,并不是简单的线性等级。其中三份资产尤其关键:

  1. 配置清单 pigsty.yml:包含所有组件的密码与凭证。应当严格控制管理节点与配置仓库(如果使用 git 管理)的访问权限。
  2. CA 私钥 files/pki/ca/ca.key:整个部署的信任锚点,持有它就可以签发任意受信证书。文件权限为 0600,存放于 0700 的目录中,建议离线备份。
  3. 管理用户的 SSH 私钥:管理节点通过 SSH 免密 sudo 管理所有纳管节点,这份私钥等价于所有节点的 root 权限。

Pigsty 的 安全策略 对此有明确表述:需要管理节点访问权限、或已持有 pigsty.yml 与 CA 私钥才能实施的攻击,不被视作安全漏洞 —— 这些是设计上的高信任控制面,必须以相应的等级加以保护。


七道防线

纵深防御不依赖某一项机制独立解决所有问题,而是让不同控制相互补充。 Pigsty 的安全能力可以归纳为七道防线:

#防线机制详见
1网络边界防火墙分区、监听地址收敛、统一入口本页下文
2传输加密本地 CA、组件间 TLS加密通信
3身份认证HBA 规则集、SCRAM 密码、客户端证书身份认证
4访问控制角色体系、默认权限、数据库隔离访问控制
5主机安全SELinux、受限 sudo、专用系统用户本页下文
6数据安全校验和、备份与加密、PITR、防误删数据安全
7审计追溯DDL 与连接日志、审计扩展、集中日志数据安全

其中第 2、3、4、6、7 道防线各有专门章节展开,这里补充说明网络与主机两道防线。

网络边界

Pigsty 在节点置备时默认启用防火墙(node_firewall_mode 默认为 zone 模式),按操作系统使用 firewalldufw 实现: 内网网段(10.0.0.0/8172.16.0.0/12192.168.0.0/16,由 node_firewall_intranet 定义)加入信任区, 公网侧仅放行 node_firewall_public_port 声明的端口,默认为 22(SSH)、80443(Web)。

默认演示配置 pigsty.yml 中额外放行了 5432 端口以便本地体验,生产部署通常应当移除。确需直接接入数据库时,应通过安全组、防火墙与 HBA 将来源限制到明确网段。

数据库默认监听所有地址(pg_listen0.0.0.0),实际访问范围由监听地址、防火墙与 HBA 共同决定。对于要求更严格的场景,可以将监听收敛到特定地址:

pg_listen: '${ip},${vip},${lo}'   # 仅监听主机 IP、集群 VIP 与本地环回地址

默认防火墙不会直接向公网开放 Grafana、VictoriaMetrics 等 Web 基础设施,外部访问通常经由 Nginx 门户 反向代理接入; 数据库流量则通过 HAProxy 提供的 服务 端口接入。入口越少,越容易加固,也越容易审计。

主机安全

主机层的核心原则:每个系统用户只拥有完成本职工作所需的最小权限

  • 数据库超级用户 postgrespg_dbsu)默认 不设密码,只能通过本地 ident 认证登录数据库,无法远程以超级用户身份进入。 它的 sudo 权限由 pg_dbsu_sudo 控制,默认为 limit 模式:仅允许免密执行数据库相关服务的 systemctl 操作与日志查看,而不是完整的 root 权限。
  • 管理用户(node_admin_username,默认 dba)供运维人员与剧本使用,默认拥有免密 sudo(nopass); 安全敏感的环境可通过 node_admin_sudo 改为 all(sudo 需输入密码)或 limit(限制命令集)。
  • SELinux 由 node_selinux_mode 控制,默认为 permissive 模式:记录违规行为但不阻断,为切换到 enforcing 强制模式积累基线。

Pigsty 不接管 SSH 服务端配置:禁用口令登录、限制 root 远程登录等操作系统级加固不在剧本管理范围内,应当纳入您自己的主机安全基线。


加固梯度

安全水位的提升不必一步到位。Pigsty 提供了一条清晰的升级路径,每一档都建立在前一档之上:

第一档:默认基线。开箱即用的安全能力包括 SCRAM 密码、数据校验和、本地 CA 与组件证书、分层 HBA、四层角色模型、默认备份和防火墙分区。 它适合受信内网中的开发、测试与验证环境;生产部署还需要继续检查凭据、网络边界和客户端验证。

第二档:随机凭证。默认密码是公开写在文档里的,任何暴露于网络的部署都必须更换。在生成配置时加上 -g 选项,可以随机化配置向导识别的内置参数和示例凭据:

./configure -g    # --generate:随机化向导识别的默认凭据

该选项不会替换 pgBackRest 的 cipher_passha/safe 中的全部 MinIO 示例凭据,也不会处理用户自定义值。完整范围见 默认凭证清单

第三档:策略加固(ha/safe 模板)。配置模板 conf/ha/safe.yml 将多项安全配置组合为一份可以继续定制的参考:

  • TLS 与证书认证:主要 TCP HBA 规则使用 ssl,公网管理员使用客户端证书;PgBouncer 启用 require,Patroni API 启用 HTTPS。本地 ident 与部分 localhost 口令规则仍然保留。
  • 密码策略:显式预加载 passwordcheck,并为内置用户声明 expire_in;模板中的示例口令仍需在部署前检查和替换。
  • 攻击面收敛:监听地址收敛至 ${ip},${vip},${lo},监控与管理账号从公网访问连接池被显式拒绝。
  • 备份加密:pgBackRest 使用 MinIO 仓库并启用 AES-256-CBC;pgBR.${pg_cluster} 是可预测的示例值,必须替换。
  • 安全扩展:安装 passwordcheckcredcheckpgauditpgsodiumanonymizer 等安全相关扩展;安装不等于预加载、创建或配置。

第四档:内核加固(crit.yml 参数模板)。safe 模板默认为集群指定了面向核心业务的 CRIT 参数模板,它相对通用的 oltp 模板:

  • 强制启用数据校验和,不受 pg_checksum 参数影响;
  • 启用严格同步复制(synchronous_mode_strict),没有可用同步副本时阻塞需要同步确认的写入;
  • 记录连接与断开事件;PostgreSQL 18 还会区分连接接收、认证与授权阶段;
  • watchdog 配置为 automatic,仅在系统存在可用设备时启用。

严格同步模式以不丢失已确认事务为目标,但仍依赖 synchronous_commit、同步副本状态和故障切换条件;RPO 需要通过目标拓扑上的故障演练验证。

也可以不使用完整模板,只挑选需要的加固项,声明在集群或全局参数中:

pg-meta:
  hosts:
    10.10.10.10: { pg_seq: 1 , pg_role: primary }
    10.10.10.11: { pg_seq: 2 , pg_role: replica }
    10.10.10.12: { pg_seq: 3 , pg_role: replica }
  vars:
    pg_cluster: pg-meta
    pg_conf: crit.yml                    # 使用 crit 内核参数模板
    patroni_ssl_enabled: true            # Patroni API 启用 HTTPS
    pgbouncer_sslmode: require           # Pgbouncer 强制 TLS
    pg_listen: '${ip},${vip},${lo}'      # 监听地址收敛
    pg_libs: '$libdir/passwordcheck, pg_stat_statements, auto_explain'  # 密码强度检查

接下来

7.2 - 身份认证

Pigsty 以声明式方式管理 PostgreSQL 与 PgBouncer 的 HBA 规则,配合 SCRAM 密码与客户端证书,回答“谁能连进来、如何证明身份”。

PostgreSQL 使用 pg_hba.conf 进行 基于主机的认证(Host-Based Authentication):谁(用户)、从哪里(来源地址)、访问什么(数据库)、需要以何种方式证明身份(认证方法)。

这套机制足够强大,但在集群环境中手工维护的成本很高:主库与从库可能需要不同规则,配置文件又分布在每个实例的数据目录中。 如果缺少统一声明和刷新流程,各实例的规则很容易发生漂移。

Pigsty 的答案与 声明式配置 一脉相承:HBA 规则是配置清单的一部分,由剧本统一渲染与下发。


HBA 即代码

集群的 HBA 规则由两组参数拼接而成:全局默认规则 pg_default_hba_rules 与集群自定义规则 pg_hba_rulesPgBouncer 连接池 另有独立的两组对应参数(pgb_default_hba_rulespgb_hba_rules)。

每条规则可以用两种形式书写。别名形式 是推荐的方式,一条规则一行,语义一目了然:

pg_hba_rules:
  - { user: dbuser_app ,db: app ,addr: 10.1.0.0/16 ,auth: ssl ,order: 50 ,title: 'app user access via ssl' }

原始形式 则直接给出 pg_hba.conf 的原文,用于表达别名覆盖不了的特殊规则。

除了四要素之外,规则还有两个控制字段:

  • order:渲染顺序。HBA 按“先匹配先生效”的原则工作,顺序即优先级。约定 0-99 保留给用户的高优先级规则,100-999 是默认规则集,未指定 order 的规则排在最后。
  • role:实例角色过滤。commondefault 规则对所有实例生效;primaryreplicaofflinestandbydelayed 规则仅在对应角色的实例上启用; role: offline 的规则还会额外下发给标记了 pg_offline_query 的实例。同一份声明渲染到不同实例,得到的是各自角色对应的规则 —— 主从差异不再需要手工维护。

修改声明后,使用封装好的脚本应用变更,规则会被重新渲染并重载生效:

bin/pgsql-hba pg-meta          # 重新渲染并应用 pg-meta 集群的 HBA 规则

pg_hba_rules 用于追加规则,不会自动收窄范围更宽的默认规则。需要建立更严格的边界时,应同时审查 pg_default_hba_rules,并在变更后检查各实例实际生成的 pg_hba.conf


地址与认证别名

别名形式的价值在于把常见场景抽象为语义化的词汇。addr 字段的别名展开为具体的地址块:

别名展开为含义
localUnix Socket仅本地套接字
localhostUnix Socket、127.0.0.1/32::1/128本机
admin<admin_ip>/32管理节点
infra各 INFRA 节点的 /32 地址基础设施节点
cluster集群各成员的 /32 地址集群内部
intra10.0.0.0/8172.16.0.0/12192.168.0.0/16内网网段,可通过 node_firewall_intranet 定制
world0.0.0.0/0::/0任意地址
CIDR 地址原样保留自定义网段

auth 字段的别名决定认证方法,以及是否强制 TLS 连接:

别名认证方法说明
denyreject显式拒绝
trusttrust无条件放行,慎用
pwdscram-sha-256md5pg_pwd_enc 而定,默认 SCRAM
shascram-sha-256强制 SCRAM
md5md5兼容旧客户端
sslhostssl 与密码认证密码认证,且必须走 TLS
ssl-shahostsslscram-sha-256TLS 与强制 SCRAM
certhostsslcert客户端证书认证
identosident(PgBouncer 中为 peer操作系统用户映射
peerpeer本地操作系统用户

用户字段支持四个占位符,渲染时替换为实际用户名:${dbsu}(超级用户)、${repl}(复制用户)、${monitor}(监控用户)、${admin}(管理用户); +role 前缀表示匹配该角色的所有成员。

这里还要区分两件事:auth: ssl 只要求连接使用 TLS,并不要求客户端验证服务端身份。安全敏感的客户端还应使用 sslmode=verify-full 和可信 CA,详见 加密通信


默认规则解读

Pigsty 的默认 HBA 规则集体现了一个简单的原则:来源越远,要求越严。以下是 PostgreSQL 侧的默认规则(源码原文):

pg_default_hba_rules:             # postgres default host-based authentication rules, order by `order`
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  ,order: 100}
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' ,order: 150}
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost',order: 200}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' ,order: 250}
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' ,order: 300}
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' ,order: 350}
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password',order: 400}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   ,order: 450}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'    ,order: 500}
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket',order: 550}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     ,order: 600}
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet',order: 650}

逐层来看:

  • 本地最受信任:超级用户 postgres 只能通过本地 Unix Socket 以 ident 方式进入 —— 不需要密码,但也无法在远程使用。这就是为什么 dbsu 默认不设密码:不存在可以被窃取的口令。
  • 内网次之:复制与业务账号在内网使用 SCRAM 口令认证;监控和管理用户的远程访问主要面向 INFRA 节点。
  • 公网最严:默认只有管理员可以从任意地址访问,且必须同时提供口令与 TLS 连接。

PgBouncer 侧的默认规则更保守一层:监控与管理账号从公网访问连接池会被显式 deny,业务用户则限定在本机与内网。

需要特别说明,默认 +dbrole_offline 规则没有设置 role,因此会应用到所有实例。要把离线用户限制到 pg_role: offline 或设置了 pg_offline_query: true 的实例,必须在对应 HBA 规则上显式增加 role: offline

这份默认规则集是“可用性优先”的取舍:业务账号在内网使用口令认证即可接入。 ha/safe 模板将主要 TCP 规则改为 ssl,管理员从非内网位置访问必须持有客户端证书(cert);本地 ident 与部分 localhost 口令规则仍然保留。


密码策略

Pigsty 默认使用 PostgreSQL 官方推荐的 scram-sha-256 算法存储密码(pg_pwd_enc),仅在需要兼容老旧客户端时才应降级为 md5

密码处理链路会在执行 ALTER USER ... PASSWORD 前临时关闭语句日志(SET log_statement TO 'none'),避免口令进入 PostgreSQL 日志。 但明文口令仍会出现在配置清单中,渲染后的用户 SQL 也会以 0640 权限写入 /pg/tmp/pg-user-<name>.sql;相关任务没有完整使用 Ansible no_log。因此应限制管理节点、配置仓库和自动化输出的访问,并避免对含凭据任务使用 --diff

密码强度默认不做强制,需要时可以预加载 passwordcheck 扩展,或使用规则更丰富的 credcheck 扩展:

pg_libs: '$libdir/passwordcheck, pg_stat_statements, auto_explain'   # 拒绝弱密码

ha/safe 模板显式设置了上述 pg_libs;单独选择 CRIT 参数模板不会自动加载 passwordcheck

账号有效期通过用户定义中的 expire_in(自创建起天数)或 expire_at(截止日期)声明,配合组织的密码轮换制度使用:

pg_users:
  - { name: dbuser_app ,password: '<独立随机口令>' ,roles: [dbrole_readwrite] ,expire_in: 365 }

证书认证

口令终究可能被钓鱼、复用或撞库。对管理员这样的高权限账号,可以在 HBA 中使用 auth: cert 要求 客户端证书认证: 客户端必须持有由本地 CA 签发、CN 与数据库用户名一致的证书才能建立连接。在 HBA 仅接受 cert 的前提下,单独泄露口令不足以通过认证。

使用内置的 cert.yml 剧本签发客户端证书:

./cert.yml -e cn=dbuser_dba            # 为 dbuser_dba 签发客户端证书,默认有效期 20 年
./cert.yml -e cn=dbuser_dba -e expire=365d   # 或指定较短的有效期

签发的证书位于 files/pki/misc/<cn>.keyfiles/pki/misc/<cn>.crt。客户端私钥应通过受控渠道交付;客户端仍需使用 verify-full 验证数据库服务端,证书体系详见 加密通信


连接池与组件 API

数据库本体之外,还有两类入口需要认证:

PgBouncer 连接池 使用独立的 HBA 规则集与用户列表。默认关闭 pgbouncer_auth_query,此时只有声明了 pgbouncer: true 的用户才会进入 userlist.txt 并通过连接池认证;启用动态认证查询后,应重新评估可登录用户范围。

Patroni REST API 承载高可用控制指令(重启、切换、重载配置),写操作要求 HTTP Basic 认证(patroni_usernamepatroni_password), 且来源受地址白名单限制;启用 patroni_ssl_enabled 后 API 全程走 HTTPS。

Grafana、HAProxy 管理界面、MinIO、etcd 等组件的凭证同样在配置清单中声明,完整清单与修改方式见 合规实践


接下来

7.3 - 访问控制

Pigsty 内置四层角色模型与默认权限模板,将最小权限原则落实为可声明、可复用的集群配置。

认证 回答“你是谁”,授权回答“你能做什么”。

权限失控很少是因为缺少机制 —— PostgreSQL 的 GRANTREVOKE 足够精细。问题在于缺少一套被默认执行的约定: 业务上线时直接把账号设为属主;临时排障授予超级用户后没有及时回收;新表创建后遗漏授权,最终在生产环境触发权限错误。

Pigsty 提供了一套开箱即用的基础访问控制模型作为起点:四层角色、默认权限与数据库隔离。 它减少了逐库手工授权,但仍需要部署方按业务边界分配角色,并定期核对实际权限。

pigsty-acl.jpg


角色体系

Pigsty 默认创建四个 业务角色 —— 它们不可登录,作为权限组使用:

角色属性继承用途
dbrole_readonlyNOLOGIN-全局只读访问
dbrole_readwriteNOLOGINdbrole_readonly全局读写(DML),业务账号的默认选择
dbrole_adminNOLOGINdbrole_readwritepg_monitor对象创建(DDL),管理与发布流程使用
dbrole_offlineNOLOGIN-独立只读角色,可配合 HBA 限制到离线实例

以及四个 系统用户,各自只承担一种职责:

用户属性用途
postgresSUPERUSER数据库超级用户:不设密码,仅限本地 ident 登录
replicatorREPLICATION流复制与备份,附带 pg_monitor 与只读权限
dbuser_dbaSUPERUSER日常管理用户,继承 dbrole_admin
dbuser_monitor-监控用户,仅持有 pg_monitor 与只读权限

业务账号通过 roles 字段挂载到角色组上,权限随继承而来:

pg_users:
  - { name: dbuser_app    ,password: '...' ,roles: [dbrole_readwrite] }  # 常规业务账号
  - { name: dbuser_report ,password: '...' ,roles: [dbrole_readonly]  }  # 报表只读账号
  - { name: dbuser_etl    ,password: '...' ,roles: [dbrole_offline]   }  # 离线 ETL 账号

角色体系本身也是声明的一部分(pg_default_roles),可以定制。 该参数是一份完整列表;调整时应保留所需的系统用户与默认角色,并同步检查 HBA、默认权限和脚本中的角色引用。


默认权限

角色解决了“权限授予谁”,还剩下另一半问题:新创建的对象如何自动获得正确的权限?

PostgreSQL 的原生答案是 ALTER DEFAULT PRIVILEGES。Pigsty 通过 pg_default_privileges 将其声明化:

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

只读角色获得查询与执行权限,读写角色叠加 DML,管理角色再增加对象管理所需的 DDL 辅助权限。

所有权约定

默认权限机制有一个经常被忽略的前提:它只对配置了默认权限的对象创建者生效。Pigsty 会为以下身份配置默认权限:

  • 数据库系统用户 pg_dbsu,默认为 postgres
  • 管理用户 pg_admin_username,默认为 dbuser_dba
  • dbrole_admin
  • 每个在 pg_databases 中声明的数据库属主。

应用 DDL 通常应使用声明的数据库属主;平台级管理与发布操作可以使用 dbuser_dba,或先 SET ROLE dbrole_admin。由其他用户直接创建的对象不会自动进入这套默认权限体系,除非另行为该用户配置 ALTER DEFAULT PRIVILEGES

这不是 Pigsty 的限制,而是 PostgreSQL 默认权限机制本身的工作方式:默认权限跟随对象创建者,而不是数据库或会话中的登录用户名自动传播。


数据库隔离

默认情况下,PostgreSQL 向 PUBLIC 授予数据库 CONNECT 权限。只要 HBA 同时允许连接,可登录用户就可能进入并不属于自己的数据库;多业务共享集群时尤其需要收敛这一默认值。

在数据库定义中声明 revokeconn,即可回收公共连接权限:

pg_databases:
  - { name: app_a ,owner: dbuser_a ,revokeconn: true }
  - { name: app_b ,owner: dbuser_b ,revokeconn: true }

启用后,该数据库上 PUBLICCONNECT 权限被撤销,只显式授予复制、监控、管理用户与数据库属主 —— 属主获得带 GRANT OPTION 的连接权限,可以自行决定向谁开放访问。在没有其他角色继承或额外授权的前提下,app_a 的账号将无法连接 app_b

与之配套,集群初始化时还会回收数据库与 public 模式上 PUBLICCREATE 权限:

REVOKE CREATE ON DATABASE app FROM PUBLIC;
REVOKE CREATE ON SCHEMA public FROM PUBLIC;

普通用户不再能在公共数据库或模式中随意创建对象,从而降低不安全 search_path 与对象覆盖带来的风险。 PostgreSQL 15 起已经收紧 public 模式的默认 CREATE 权限;Pigsty 将这项边界统一应用到所有受支持的大版本上。


离线角色与实例隔离

dbrole_offline 的设计用途,是为 ETL、报表和个人查询提供一组独立的只读权限。但角色本身只控制对象权限,并不会自动限制用户连接到哪类实例。

当前默认 HBA 中,+dbrole_offline 的内网规则没有设置 role,因此会应用到所有实例。要把它限制到 pg_role: offline 的专用实例,或标记了 pg_offline_query: true 的普通从库,需要在完整的 pg_default_hba_rules 列表中修改这一条规则:

pg_default_hba_rules:
  # 复制并保留其他默认规则,仅修改离线角色这一条
  - { user: '+dbrole_offline', db: all, addr: intra, auth: pwd, role: offline, order: 650,
      title: 'allow offline users on offline instances' }

定义 pg_default_hba_rules 会替换整组默认值,不能只保留示例中的一条。只有当 HBA 已按实例角色过滤,且用户没有同时继承其他可登录角色时,这类高消耗查询才会被限制到离线实例。资源隔离还应配合 独立服务入口、连接数和查询资源控制。


数据库之外

最小权限原则同样贯彻到主机层面:

  • 超级用户 postgres 不设密码,只能本地 ident 登录;其 sudo 权限默认限制在数据库相关服务的启停与日志查看(pg_dbsu_sudolimit)。
  • 监控用户 dbuser_monitor 默认持有 pg_monitor、只读角色与专用 monitor 模式权限,不具备业务表写权限。
  • 复制用户 replicator 被显式授予备份恢复所需的目录函数执行权限,而不是笼统的超级用户。

接下来

7.4 - 加密通信

Pigsty 内置自签名 CA,为受管组件签发证书并分发信任,提供统一的 TLS 基础设施。

TLS 可以提供三类保护:传输加密服务端身份验证客户端身份验证。这三项能力需要分别配置:启用服务端 TLS 并不等于客户端已经验证了服务端身份,也不等于服务端要求客户端证书。

TLS 的主要运维成本不在加密算法本身,而在证书的签发、分发、信任与轮换。缺少统一管理时,内网服务往往只启用加密,却跳过证书验证,或者干脆继续使用明文连接。

Pigsty 的做法是把 PKI 也纳入声明式管理:部署时自动创建本地自签名 CA,为受管组件签发证书并分发信任,让 TLS 在部署完成后即可使用。


本地 CA

首次执行部署时,Pigsty 会在 管理节点 上检查并按需创建 CA:

文件说明权限
files/pki/ca/ca.keyCA 私钥:整个部署的信任根,务必妥善保管0600(目录 0700
files/pki/ca/ca.crtCA 根证书:可以自由分发0644
  • CA 的行为由 ca_create 控制:CA 文件已存在则原样复用(幂等),不存在则新建; 设为 false 时若找不到 CA 文件,部署会直接报错中止,防止意外生成新的信任根。
  • CA 证书的 CN 由 ca_cn 指定,默认 pigsty-ca;密钥为 RSA 4096 位。
  • 有效期:CA 根证书 100 年,组件证书默认 20 年(cert_validity7300d)。 面向浏览器的 Nginx 证书是例外,当前默认有效期为 397 天。

较长的默认有效期用于降低私有基础设施的初始维护成本,并不意味着生产环境无需轮换。组织已有证书策略时,应缩短有效期,并建立到期监控和换证流程。


信任分发

签发证书只是一半,另一半是让每个 节点 信任这些证书。节点纳入管理时,Pigsty 将 CA 证书分发到所有节点的 /etc/pki/ca.crt,并链接进操作系统信任链:

  • EL 系(RHEL、Rocky、Alma):链接至 /etc/pki/ca-trust/source/anchors/ 并执行 update-ca-trust
  • Debian、Ubuntu:链接至 /usr/local/share/ca-certificates/ 并执行 update-ca-certificates

此后,使用操作系统信任库的客户端(例如 curl)可以验证 Pigsty CA 签发的证书。 CA 证书还会发布到 Nginx 门户 的站点根目录(ca.crt),供浏览器与外部客户端下载安装。

PostgreSQL 的 libpq 客户端需要单独说明:它默认使用 ~/.postgresql/root.crt,默认 sslmodeprefer,不会直接使用操作系统信任库验证服务端身份。


客户端验证服务端

安全敏感的 PostgreSQL 客户端应使用 sslmode=verify-full,并指定 Pigsty CA:

psql "host=pg-meta dbname=postgres user=dbuser_dba sslmode=verify-full sslrootcert=/etc/pki/ca.crt"

verify-full 会同时验证证书链与连接主机名,因此客户端使用的 DNS 名称或 IP 地址必须出现在服务端证书的 SAN 中。外部客户端需要先安装 ca.crt,或通过 sslrootcert 指定 CA 文件。


证书矩阵

本地 CA 为下列组件签发证书,构成统一的信任链:

组件证书身份(CN)部署路径加密状态
PostgreSQL<集群>-<序号>/pg/cert/server.{crt,key}服务端 SSL 默认启用;是否强制由 HBA 决定
PgBouncer复用 PostgreSQL 证书/pg/cert/TLS 默认关闭(pgbouncer_sslmode
Patroni复用 PostgreSQL 证书/pg/cert/API HTTPS 默认关闭(patroni_ssl_enabled
etcd<实例名>/etc/etcd/server.{crt,key}客户端与对等通信使用 TLS
MinIO<节点名>~minio/.minio/certs/HTTPS 默认开启(minio_https
Nginxpigsty(SAN 含门户域名)/etc/nginx/conf.d/cert/HTTPS 默认开启(nginx_sslmode
INFRA 节点<节点名>/etc/pki/infra.{crt,key}供基础设施组件使用

表中的“加密状态”一列如实反映了默认配置的取舍:

  • 部署时启用:PostgreSQL 服务端可以接受 SSL 连接,etcd 的客户端与对等通信使用 TLS。
  • 默认加密:MinIO(备份流量)与 Nginx(Web 流量)默认启用 HTTPS。
  • 默认关闭,按需启用:Patroni REST API 与 PgBouncer 的 TLS 默认关闭,证书已经就位,可以通过相应参数开启;ha/safe 模板中两者均默认开启。

还有一层需要分清的区别:服务端支持 SSL 不等于强制客户端使用 SSL,更不等于客户端验证了服务端身份。 是否强制加密由 HBA 规则 决定(auth: sslcert);是否验证服务端则由客户端的 sslmode 与信任配置决定。默认规则仅对任意来源的管理员连接强制 TLS,safe 模板将主要 TCP 规则改为 sslcert,但仍保留本地 ident 与部分 localhost 口令规则。


客户端证书

内置剧本 cert.yml 用于签发客户端证书。证书的 CN 对应数据库用户名,供 HBA 的 cert 认证方式使用:

./cert.yml -e cn=dbuser_dba                  # 为 dbuser_dba 签发客户端证书,默认有效期 20 年
./cert.yml -e cn=dbuser_dba -e expire=365d   # 或指定更短的有效期

签发结果位于 files/pki/misc/<cn>.keyfiles/pki/misc/<cn>.crt。客户端私钥应通过受控渠道交付,并设置为仅对应用户可读。客户端证书解决服务端对客户端身份的验证,客户端仍需使用 verify-full 验证数据库服务端。


使用企业 CA

如果组织已有 PKI 体系,可以让 Pigsty 改用您的 CA(或由企业根 CA 签出的中间 CA)签发证书:把证书与私钥放到指定位置即可,剧本检测到已有 CA 后不会重新生成:

files/pki/ca/ca.key    # 您的 CA 私钥(或中间 CA 私钥)
files/pki/ca/ca.crt    # 对应的 CA 证书

同时建议设置 ca_create: false:这样当文件缺失时部署会显式失败,避免意外创建新的自签名 CA,破坏既有的信任链。


密钥保护与轮换

  • CA 私钥只存在于管理节点上。它与 pigsty.yml 一起构成部署中信任等级最高的资产(参见 信任边界),建议离线备份。
  • CA 私钥一旦泄露,需要建立新的信任根并重新签发全部组件与客户端证书。执行前应规划新旧 CA 的信任过渡,避免一次性中断所有连接。
  • 组件证书的签发源保存在管理节点的 files/pki/<component>/,节点上的证书只是部署副本。仅删除节点上的证书会重新复制原证书,不会触发重新签发。轮换时应更新或删除管理节点上的对应证书源,再执行相关剧本,并按组件要求重载或滚动重启。

接下来

7.5 - 数据安全

使用校验和、备份与 PITR、加密和审计日志保护 PostgreSQL 数据的完整性、可恢复性、保密性与可追溯性。

网络边界身份认证权限控制 用于降低事件发生的概率;当硬件损坏、口令泄露或误操作已经发生时,还需要依靠数据层机制控制影响并完成恢复。

数据安全要回答四个问题:数据是 完整 的吗?丢了能 恢复 吗?被拿走了会 泄密 吗?发生了什么能 查清 吗?


完整性

磁盘坏块、内存位翻转、存储固件缺陷,都可能造成 静默数据损坏:数据坏了,但没有任何报错。 Pigsty 默认启用页级数据校验和(pg_checksumtrue), 集群初始化时以 data-checksums 建库,PostgreSQL 会在页面写入时计算校验和,并在读取时检查页面损坏。

页校验和主要发现存储介质、I/O 路径或写入后发生的页面损坏,不能检测所有内存错误、逻辑错误或应用写入的错误数据,也不能替代备份。

CRIT 参数模板 更进一步:校验和强制启用,不受参数影响; 同时启用 严格同步复制synchronous_mode_strict),在没有可用同步副本时阻塞需要同步确认的写入。 该模式以不丢失已确认事务为目标,但仍依赖客户端没有降低 synchronous_commit、同步副本正常参与提交,以及故障切换只选择包含所需 WAL 的节点。RPO 需要通过目标拓扑上的故障演练验证。


可恢复性

副本主要处理节点故障,备份则处理误删除、逻辑错误、集群损坏和更大范围的灾难。 高可用 可以缩短主库故障造成的中断,但如果有人误删了数据,复制也会把误操作同步到其他副本。备份因此无可替代。

Pigsty 默认启用 pgBackRestpgbackrest_enabled): 基础备份加上持续归档的 WAL,构成 时间点恢复(PITR)能力,可以将集群恢复到备份与 WAL 保留窗口内的目标时刻。

备份仓库由 pgbackrest_method 选择:

仓库位置默认保留策略加密
local(默认)本地 /pg/backup 目录最近 2 份全量备份
minioMinIO 或 S3 对象存储14 天AES-256-CBC

对于防误删场景,还有两项辅助机制:

  • 延迟从库:为关键集群声明一个 pg_delay: 1h 的延迟副本。在错误操作尚未回放前,可以暂停复制并提取数据。延迟副本最终仍会追上主库,不能代替备份。
  • 移除保护pg_safeguardetcd_safeguard 开启后,对应的移除剧本会拒绝执行,降低误删集群的风险。

备份的存在不等于恢复的能力。恢复演练应当成为例行工作:原理与决策见 时间点恢复,配置与操作见 PGSQL 备份恢复


保密性

静态数据的保密性分三层展开:

备份加密。MinIO 备份仓库默认启用 AES-256-CBC 加密,但默认加密口令(pgBackRest)是公开的,生产环境必须修改。 ha/safe 模板按集群名称区分加密口令:

pgbackrest_repo:
  minio:
    cipher_type: aes-256-cbc
    cipher_pass: 'pgBR.${pg_cluster}'   # 示例值,部署前必须替换

pgBR.${pg_cluster} 是可预测的示例值,configure -g 也不会替换它。生产环境应使用独立随机口令,并与备份分开保存;口令丢失会导致备份无法恢复。

本地备份仓库默认不加密。加密可以降低备份文件被单独复制或介质被盗时的泄露风险,但如果密钥与备份位于同一主机,保护效果仍会受到限制。

传输加密。备份上传 MinIO 走 HTTPS,PostgreSQL 客户端与流复制可以通过 HBA 强制 SSL。客户端还应验证服务端证书,详见 加密通信

静态加密。PostgreSQL 上游内核目前没有通用的内置透明数据加密(TDE),Pigsty 提供两条现实路径: 使用 Percona PostgreSQL 内核的 pg_tde 扩展实现表级透明加密(参见 pgtde 配置模板); 或使用 pgsodiumpgcryptoanonymizer安全扩展 在列级实现加密与脱敏 —— safe 模板已预装这一类扩展。 此外,全盘加密(LUKS、dm-crypt)在操作系统层解决介质被盗问题,与数据库层方案互补。


审计与追溯

出了问题,要能回答“谁在什么时候做了什么”。Pigsty 的日志审计分层递进:

默认基线:所有 DDL 语句被记录(log_statement: ddl),执行超过 100ms 的查询被记录(log_min_duration_statement: 100), PostgreSQL 18 及以上版本还会记录连接授权事件。

CRIT 模板:记录连接与断开事件(log_connectionslog_disconnections);PostgreSQL 18 还会区分连接接收、认证与授权阶段。

pgaudit 扩展:需要语句级的细粒度审计(对象级读写、按角色审计)时,安装 pgaudit 并加入 pg_libs 预加载。 safe 模板已预装该扩展,加载与审计策略需按需求显式声明。

启用 INFRA 日志组件并完成 Vector 配置后,PostgreSQL 日志会汇入 VictoriaLogs 集中存储(默认保留 15 天,可按合规要求调整)。 日志和指标为安全事件的检索、告警与回溯提供输入,但事件判定、响应和证据保全仍需要配套流程。


接下来

7.6 - 合规实践

合规是配置、流程与证据的组合:上线加固清单、等保与 SOC 2 控制点映射、供应链完整性与漏洞响应机制。

合规不是一个可以购买的产品,而是一种需要持续证明的状态。它由三部分组成:

  • 配置:安全能力是否启用 —— 这部分由 Pigsty 直接提供;
  • 流程:权限审批、变更管理、恢复演练等制度 —— 需要组织自行建立;
  • 证据:能证明前两者持续有效的记录 —— Pigsty 的 配置清单、运行日志和 监控系统 可以提供其中一部分。

本页从上线前的加固清单开始,给出 Pigsty 安全能力与常见合规框架的映射关系。 这些映射用于方案设计和差距分析,不构成等保测评结论、SOC 2 审计意见或法律建议。


默认凭证清单

Pigsty 的默认凭证公开写在文档与源码中,仅供演示与本地开发使用。任何生产部署或暴露于网络的部署,上线前必须修改所有适用的默认值

范围默认值示例configure -g
Grafana 管理员与只读用户pigstyDBUser.Viewer
HAProxy 管理界面pigsty
PostgreSQL 管理、监控、复制用户DBUser.DBADBUser.MonitorDBUser.Replicator
Patroni REST APIPatroni.API
etcd rootEtcd.Root
MinIO rootS3User.MinIO
MinIO 备份与示例业务用户S3User.BackupS3User.MetaS3User.Data
示例数据库用户DBUser.MetaDBUser.SupaVibe.Coding
pgBackRest 加密口令cipher_pass: pgBackRest
ha/safe 中的 MinIO 用户与 pgBR.${pg_cluster}模板示例值
用户自行添加的凭据自定义值

生成配置时可以使用 -g,随机化配置向导识别的内置参数和示例字符串:

./configure -g     # 生成配置清单,并随机化向导识别的默认凭据

配置向导会把生成的密码输出到终端,因此终端记录和自动化日志也应按敏感信息保护。生成完成后还要检查配置文件,单独替换 pgBackRest cipher_passha/safe 中未覆盖的 MinIO 示例值和自定义凭据。


上线加固清单

部署前

  • 明确 网络边界:数据库端口不暴露公网,移除演示配置中防火墙放行的 5432
  • 确定证书策略:使用内置 CA,或接入企业 PKI(参见 使用企业 CA
  • 规划 客户端验证:为数据库客户端配置 sslmode=verify-full 与可信 CA
  • 规划账号体系:业务账号按 四层角色 分级,声明 expire_in 过期时间
  • 规划 备份仓库、保留周期、加密口令和异地副本
  • 评估是否采用 ha/safe 加固模板与 CRIT 参数模板

部署后

  • 确认 configure -g 覆盖的凭据与未覆盖的备份、MinIO、自定义凭据均已修改
  • 审查实际生效的 HBA 规则/pg/data/pg_hba.conf)是否与声明及预期一致
  • 查询实际用户、角色、默认权限 和数据库 CONNECT 授权,并与配置清单比较
  • 执行一次全量备份与 恢复演练,验证备份链路可用
  • 确认日志采集、监控告警与通知通道可用

周期性

  • 权限审计:核对 pg_users 声明与实际授权,清理过期与离职账号
  • 凭证与证书轮换
  • 恢复演练与故障切换演练
  • 跟进 Pigsty 与上游组件的安全更新

合规证据

声明式配置为合规审计提供了稳定的证据入口,但还需要保留运行时状态,证明配置已经应用并持续有效。

证据来源
安全配置基线及其变更历史pigsty.yml 配置清单与 Git 提交记录
访问控制矩阵pg_default_rolespg_userspg_hba_rules 声明
实际生效的认证规则各实例渲染出的 pg_hba.conf,用于与声明比较并发现漂移
实际用户与权限PostgreSQL 系统目录、数据库 ACL、\du+\ddp+
操作与连接日志PostgreSQL 日志(DDL、慢查询、连接),VictoriaLogs 集中留存
备份记录pgBackRest 备份信息与监控面板
安全事件与告警记录监控系统告警历史
证书清单files/pki/ 目录与各组件部署证书

等保三级映射

《GB/T 22239-2019》三级要求中“安全计算环境”部分与 Pigsty 能力的对应关系:

控制要求Pigsty 能力需要补充
身份鉴别唯一性独立账号体系,SCRAM-SHA-256 密码存储账号实名管理制度
口令复杂度与定期更换passwordcheckcredcheck 扩展,expire_in 账号过期启用扩展;轮换制度
登录失败处理可借助 credcheck 等扩展实现按需启用与配置
访问控制与最小权限四层角色模型、默认权限与数据库隔离权限审批流程
安全审计DDL、连接、慢查询日志,pgaudit,集中日志留存CRIT 模板或手工启用连接日志;留存周期按要求调整
通信保密性本地 CA 与 TLS,HBA 强制 sslcert强制 TLS、客户端 verify-full 与证书轮换
数据完整性页级校验和(默认启用),严格同步复制(CRIT)存储保护、故障模型与演练
数据保密性备份 AES 加密,TDE 与列级加密路径按需启用
数据备份恢复pgBackRest、PITR 与远端仓库(MinIO)恢复演练制度
剩余信息保护-介质销毁与擦除流程

等保还包括安全物理环境、安全通信网络、安全管理制度等部分,超出数据库发行版的能力范畴: Pigsty 可以支持“安全计算环境”中与数据库相关的部分技术控制,机房、网络设备与管理制度仍需在整体方案中补足。


SOC 2 映射

SOC 2 信任服务准则(TSC)中与数据库直接相关的部分控制点:

控制点Pigsty 能力需要补充
CC6.1 逻辑访问安全HBA、RBAC、默认权限与数据库隔离权限设计、审批与定期复核
CC6.2 用户注册与授权声明式用户、角色和有效期入职、变更、离职和身份核验流程
CC6.3 访问变更与撤销pg_users、角色调整、REVOKE 与到期时间工单、授权批准和及时回收证据
CC6.6 外部边界威胁防火墙、监听地址、HBA 与管理入口限制网络架构、边界设备和持续验证
CC6.7 信息传输与移动TLS、客户端验证与备份加密数据导出、介质和第三方传输策略
CC7.2 系统监控Victoria 可观测性栈,数千项指标与告警告警响应流程
CC7.3 事件追溯集中日志,审计扩展日志审查流程
A1.2 可用性与恢复高可用PITR演练记录与 RTO、RPO 目标

供应链与漏洞响应

合规审查越来越关注软件供应链,Pigsty 在分发与响应侧提供以下保障:

包完整性:Pigsty 软件仓库(repo.pigsty.iorepo.pigsty.cc)中的 RPM、DEB 包经 GPG 签名, 公钥指纹为 9592 A7BC 7A68 2E73 3337 6E09 E793 5D8D B9BD 8B20B9BD8B20),可在信任前核验。但部署时写入的仓库定义以及 INFRA 节点 上的本地仓库,默认不强制逐包签名验证;生产环境应检查包管理器的仓库信任与验签设置。

漏洞响应:安全问题通过 GitHub 私有漏洞报告或邮件渠道私下披露(参见 SECURITY.md), 项目目标是在 3 个工作日内确认、7 天内给出初步评估。

版本支持:安全修复随最新稳定版发布,保持升级是获得安全修复的方式;需要长期锁定版本的用户,可通过 订阅服务 获得延长支持。


接下来