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

返回本页常规视图.

系统架构

介绍 PostgreSQL 集群的整体架构与实现细节。

1 - 实体关系图

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

先弄清楚“有哪些对象、它们如何互相引用”,再去讨论部署和运维。Pigsty 的 PGSQL 模块围绕几个核心实体构成一张稳定的 E-R 图,理解这张图能帮助你设计清晰的配置和自动化流程。

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

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

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

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

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

pigsty-er.jpg

命名约定(沿用 Pigsty 早期约束)

  • 集群名应为有效的 DNS 域名,不包含任何点号,正则表达式为:[a-zA-Z0-9-]+
  • 服务名应以集群名为前缀,并以特定单词作为后缀:primaryreplicaofflinedelayed,中间用-连接。
  • 实例名以集群名为前缀,以正整数实例号为后缀,用-连接,例如${cluster}-${seq}
  • 节点由其首要内网IP地址标识,因为PGSQL模块中数据库与主机1:1部署,所以主机名通常与实例名相同。

2 - 身份标识符

介绍 Pigsty 中 PostgreSQL 集群的实体身份标识符:命名规范、设计理念,以及使用方法。

Pigsty 使用 PG_ID 参数组为 PGSQL 模块的每个实体赋予确定的身份。


核心身份参数

三项必填参数构成 PGSQL 的最小 ID 集:

参数层级作用约束
pg_cluster集群业务命名空间[a-z][a-z0-9-]*
pg_seq实例集群内实例序号递增分配的自然数,唯一且不可复用
pg_role实例复制角色primary / replica / offline / delayed
  • pg_cluster 决定所有衍生名称:实例、服务、监控标签。
  • pg_seq 与节点 1:1 绑定,表达拓扑顺序和预期优先级。
  • pg_role 驱动 Patroni/HAProxy 的行为:primary 唯一,replica 承载在线只读,offline 只接离线服务,delayed 用于延迟集群。

Pigsty 不会为上述参数提供默认值,必须在 inventory 中显式写明。


实体身份标识

Pigsty 的 PostgreSQL 实体标识符将根据上面的核心身份参数自动生成

实体生成规则示例
实例{{ pg_cluster }}-{{ pg_seq }}pg-test-1
服务{{ pg_cluster }}-{{ pg_role }}pg-test-primary
节点名默认等同实例名,但可以显式覆盖pg-test-1

服务后缀采用内置约定:primaryreplicadefaultofflinedelayed 等。HAProxy/pgbouncer 会读取这些标识自动构建路由。命名保持前缀一致,可直接通过 pg-test-* 查询或筛选。


监控标签体系

在 PGSQL 模块中,所有监控指标使用以下标签体系:

  • cls:集群名:{{ pg_cluster }}
  • ins:实例名:{{ pg_cluster }}-{{ pg_seq }}
  • ip:实例所在节点 IP。

对于 VictoriaMetrics 而言,采集 PostgreSQL 指标的 job 名固定为 pgsql; 用于监控远程 PG 实例的 job 名固定为 pgrds

对于 VictoriaLogs 而言,采集 PostgreSQL CSV 日志的 job 名固定为 postgres; 采集 pgbackrest 日志的 job 名固定为 pgbackrest,其余组件通过 syslog 采集日志。


示例: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, pg_offline_query: true }
  vars:
    pg_cluster: pg-test
集群序号角色节点/IP实例服务入口
pg-test1primary10.10.10.11pg-test-1pg-test-primary
pg-test2replica10.10.10.12pg-test-2pg-test-replica
pg-test3replica+offline10.10.10.13pg-test-3pg-test-replica / pg-test-offline

Prometheus 标签示例:

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

3 - 组件与交互

介绍 Pigsty 中 PostgreSQL 集群中的组件,以及它们之间的交互行为与依赖关系。

总览

以下是 PostgreSQL 模块组件及其相互作用的详细描述,从上至下分别为:

  • 集群 DNS 由 infra 节点上的 DNSMASQ 负责解析
  • 集群 VIP 由 vip-manager 组件管理,它负责将 pg_vip_address 绑定到集群主库节点上。
    • vip-manageretcd 集群获取由 patroni 写入的集群领导者信息
  • 集群服务由节点上的 Haproxy 对外暴露,不同服务通过节点的不同端口(543x)区分。
    • Haproxy 端口 9101:监控指标 & 统计 & 管理页面
    • Haproxy 端口 5433:默认路由至主 pgbouncer:读写服务
    • Haproxy 端口 5434:默认路由至从库 pgbouncer:只读服务
    • Haproxy 端口 5436:默认路由至主 postgres:默认服务
    • Haproxy 端口 5438:默认路由至离线 postgres:离线服务
    • HAProxy 将根据 patroni 提供的健康检查信息路由流量。
  • Pgbouncer 是一个连接池中间件,默认监听6432端口,可以缓冲连接、暴露额外的指标,并提供额外的灵活性。
    • Pgbouncer 是无状态的,并通过本地 Unix 套接字以 1:1 的方式与 Postgres 服务器部署。
    • 生产流量(主/从)将默认通过 pgbouncer(可以通过pg_default_service_dest指定跳过)
    • 默认/离线服务将始终绕过 pgbouncer ,并直接连接到目标 Postgres。
  • PostgreSQL 监听5432端口,提供关系型数据库服务
    • 在多个节点上安装 PGSQL 模块,并使用同一集群名,将自动基于流式复制组成高可用集群
    • PostgreSQL 进程默认由 patroni 管理。
  • Patroni 默认监听端口 8008,监管着 PostgreSQL 服务器进程
    • Patroni 将 Postgres 服务器作为子进程启动
    • Patroni 使用 etcd 作为 DCS:存储配置、故障检测和领导者选举。
    • Patroni 通过健康检查提供 Postgres 信息(比如主/从),HAProxy 通过健康检查使用该信息分发服务流量
    • Patroni 指标将被 infra 节点上的 Prometheus 抓取
  • PG Exporter 在 9630 端口对外暴露 postgres 架空指标
    • PostgreSQL 指标将被 infra 节点上的 Prometheus 抓取
  • Pgbouncer Exporter 在端口 9631 暴露 pgbouncer 指标
    • Pgbouncer 指标将被 infra 节点上的 Prometheus 抓取
  • pgBackRest 默认在使用本地备份仓库 (pgbackrest_method = local
    • 如果使用 local(默认)作为备份仓库,pgBackRest 将在主库节点的pg_fs_bkup 下创建本地仓库
    • 如果使用 minio 作为备份仓库,pgBackRest 将在专用的 MinIO 集群上创建备份仓库:pgbackrest_repo.minio
  • Postgres 相关日志(postgres, pgbouncer, patroni, pgbackrest)由 promtail 负责收集
    • Promtail 监听 9080 端口,也对 infra 节点上的 Prometheus 暴露自身的监控指标
    • Promtail 将日志发送至 infra 节点上的 Loki

集群 DNS

集群 DNS 服务由 infra 节点的 DNSMASQ 维护,为每个 pg_cluster 提供稳定的 FQDN(<cluster>.<pg_dns_suffix>)。DNS 记录会指向主库或 VIP,供业务侧、自动化流程与跨集群的数据服务访问,不需要直接关心节点的实时 IP。DNS 依赖部署期写入的库存信息,运行期只在 VIP 或主节点漂移时更新,其上游是 vip-manager 与 etcd 中的主节点状态。

DNS 的下游是客户端与第三方服务入口,它也为 HAProxy 等中间层提供统一的目标地址。组件可选;当集群运行在独立网络或业务端直接使用 IP 时可以跳过,但绝大多数生产环境建议启用,以避免硬编码节点地址。

关键参数

主库虚拟 IP(vip-manager)

vip-manager 在每个 PG 节点上运行,通过监视 etcd 中由 Patroni 写入的领导者键,把 pg_vip_address 绑定到当前主节点上,实现透明的 L2 漂移。它依赖 DCS 的健康状态,并要求目标网络接口可被当前节点控制,从而在故障转移时立即释放并重绑 VIP,保障旧主机不会继续响应。

VIP 的下游包含 DNS、自建客户端、遗留系统等需要固定端点的访问者。该组件可选:只在 pg_vip_enabledtrue 且业务需要静态地址时启用。启用后必须保证所有参与节点都具备相同的 VLAN 接入,否则 VIP 无法正确漂移。

关键参数

服务入口与流量调度(HAProxy)

HAProxy 安装在 PG 节点(或专用服务节点),统一对外暴露数据库服务端口组:5433/5434(读写/只读,通过 Pgbouncer),5436/5438(直连主库/离线库),以及 9101 管理接口。每个后端池依靠 patroni REST API 提供的角色与健康信息做路由判断,并把流量转发到对应实例或连接池。

该组件是整个集群的入口,下游直接面向应用、ETL 与管理工具。可将 pg_service_provider 指向专用 HA 节点以承载更高流量,也可在实例本地进行发布。HAProxy 对 VIP 无依赖,但通常与 DNS 和 VIP 联动,打造统一访问口。服务定义由 pg_default_servicespg_services 组合而成,可精细化配置端口、负载均衡策略与目标。

关键参数

连接池(Pgbouncer)

Pgbouncer 在每个实例上以无状态方式运行,优先通过本地 Unix Socket 连接 PostgreSQL,用于吸收瞬时连接、稳定会话与提供额外指标。Pigsty 默认让生产流量(5433/5434)经由 Pgbouncer,只有默认/离线服务绕过它直连 PostgreSQL。Pgbouncer 不依赖 VIP,可与 HAProxy、Patroni 独立伸缩,在 Pgbouncer 停止时 PostgreSQL 仍可提供直连服务。

Pgbouncer 的下游是大量短连接客户端,以及统一入口 HAProxy。它允许基于 auth_query 的动态用户加载,并可按需配置 SSL。组件可选,通过 pgbouncer_enabled 关闭时,默认服务将直接指向 PostgreSQL,需要相应调整连接数与会话管理策略。

关键参数

数据库实例(PostgreSQL)

PostgreSQL 进程是整个模块的核心,默认监听 5432 并由 Patroni 托管。以同一 pg_cluster 在多节点安装 PGSQL 模块,将自动构建基于物理流复制的主从拓扑;primary/replica/offline 角色由 pg_role 控制,必要时可通过 pg_instances 在同一节点运行多实例。实例依赖本地数据盘、操作系统内核调优与 NODE 模块提供的系统服务。

该组件的下游是业务读写流量、pgBackRest、pg_exporter 等服务;上游是 Patroni、Ansible 引导脚本,以及 etcd 中的元数据。可根据 pg_conf 模板切换 OLTP/OLAP 配置,并通过 pg_upstream 定义级联复制。若使用 citus/gpsql,需进一步设置 pg_shardpg_grouppg_hba_rulespg_default_hba_rules 决定访问控制策略。

关键参数

  • pg_mode:实例运行模式(标准 PG、Citus、MSSQL 兼容等)。
  • pg_seq:实例序号,用于锁定复制拓扑与服务权重。
  • pg_role:定义实例角色(primary/replica/offline)。
  • pg_instances:在单节点部署多实例的映射。
  • pg_upstream:级联备库的复制源。
  • pg_conf:加载的配置模板,决定资源与连接上限。
  • pg_hba_rules / pg_default_hba_rules:访问控制列表。

高可用控制器(Patroni + etcd)

Patroni 监听 8008,接管 PostgreSQL 的启动、配置与健康状态,将领导者、成员信息写入 etcd(命名空间由 pg_namespace 定义)。它负责自动故障转移、保持复制因子、协调参数,以及提供 REST API 供 HAProxy、监控与管理员查询。Patroni 可启用看门狗强制隔离旧主机,以避免脑裂。

Patroni 的上游是 etcd 集群与系统服务(systemd、Keepalive),下游包括 vip-manager、HAProxy、Pgbackrest 与监控组件。可以通过 patroni_mode 切换为 pause/remove 模式,以便维护或删除集群。禁用 Patroni 仅在管理外部 PG 实例时使用。

关键参数

备份子系统(pgBackRest)

pgBackRest 在主库上创建本地或远程仓库,用于全量/增量备份与 WAL 归档。它与 PostgreSQL 配合执行控制命令,支持本地磁盘(默认)、MinIO 等多种目标,能够覆盖 PITR、备份链条验证与远程拉起。上游是主库的数据与归档流,下游是对象存储或本地备份盘,以及 pgbackrest_exporter 提供的可观测性。

组件可择时运行,通常在初始化完成后立即发起一次全量备份;也支持关闭(实验环境或外部备份系统)。启用 minio 仓库时需要可达的对象存储服务与凭据。恢复过程与 Patroni 集成,可通过 pgbackrest 命令将副本引导为新的主库或备库。

关键参数

PostgreSQL 指标(pg_exporter)

pg_exporter 运行在 PG 节点上,使用本地 socket 登录,导出覆盖会话、缓冲命中、复制延迟、事务率等指标供 infra 节点上的 Prometheus 抓取。它与 PostgreSQL 紧耦合,重启 PostgreSQL 时会自动重连,对外监听 9630(默认)。Exporter 不依赖 VIP,与 HA 拓扑解耦。

关键参数

连接池指标(pgbouncer_exporter)

pgbouncer_exporter 启动在节点上,读取 Pgbouncer 的统计视图,提供连接池利用率、等待队列与命中率指标。它依赖 Pgbouncer 的 admin 用户,并通过独立端口暴露给 Prometheus。若禁用 Pgbouncer,本组件应同时关闭。

关键参数

备份指标(pgbackrest_exporter)

pgbackrest_exporter 解析该节点的 pgBackRest 状态,生成最近备份时间、大小、类型等指标。Prometheus 通过 9854(默认)采集这些指标,结合告警策略即可快速发现备份过期或失败。组件依赖 pgBackRest 元数据目录,关闭备份系统时也应禁用它。

关键参数

日志采集(Promtail)

Promtail 常驻在节点上,跟踪 PostgreSQL、Pgbouncer、Patroni 与 pgBackRest 的日志目录,通过 Loki Pipeline 统一存档,并在 9080 提供自监控指标。它基于 NODE 模块提供的 systemd 服务,与 PG 模块解耦,但对排障与合规审计至关重要。Promtail 的上游是本地日志文件,下游是 infra 节点的 Loki/Prometheus 组合。

关键参数(位于 NODE 模块的 PROMTAIL 组件)

pigsty-arch.jpg

4 - 高可用集群

深入介绍 Pigsty 中 PostgreSQL 高可用集群的架构设计、组件交互、故障场景与恢复机制。

Pigsty 的 PostgreSQL 集群带有开箱即用的高可用方案,由 PatroniEtcdHAProxy 强力驱动。

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

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

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

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


架构概览

Pigsty 高可用架构由四个核心组件构成,它们协同工作,实现故障自动检测、领导者选举与流量切换:

flowchart TB
    subgraph Client["🖥️ 客户端接入层"]
        C[("Client")]
        ACCESS["DNS / VIP / HAProxy / L4 LVS"]
    end

    subgraph Node1["📦 Node 1"]
        HAP1["HAProxy :9101<br/>Primary :5433 | Replica :5434"]
        subgraph Stack1["Patroni :8008"]
            PG1[("PostgreSQL<br/>[Primary] :5432")]
            PGB1["PgBouncer :6432"]
        end
    end

    subgraph Node2["📦 Node 2"]
        HAP2["HAProxy :9101<br/>Primary :5433 | Replica :5434"]
        subgraph Stack2["Patroni :8008"]
            PG2[("PostgreSQL<br/>[Replica] :5432")]
            PGB2["PgBouncer :6432"]
        end
    end

    subgraph Node3["📦 Node 3"]
        HAP3["HAProxy :9101<br/>Primary :5433 | Replica :5434"]
        subgraph Stack3["Patroni :8008"]
            PG3[("PostgreSQL<br/>[Replica] :5432")]
            PGB3["PgBouncer :6432"]
        end
    end

    subgraph ETCD["🔐 Etcd Cluster (Raft Consensus)"]
        E1[("Etcd-1<br/>:2379")]
        E2[("Etcd-2<br/>:2379")]
        E3[("Etcd-3<br/>:2379")]
    end

    C --> ACCESS
    ACCESS --> HAP1 & HAP2 & HAP3

    HAP1 -.->|"HTTP Health Check"| Stack1
    HAP2 -.->|"HTTP Health Check"| Stack2
    HAP3 -.->|"HTTP Health Check"| Stack3

    HAP1 --> PGB1
    HAP2 --> PGB2
    HAP3 --> PGB3

    PG1 ==>|"Streaming Replication"| PG2
    PG1 ==>|"Streaming Replication"| PG3

    Stack1 <-->|"Leader Lease"| ETCD
    Stack2 <-->|"Leader Lease"| ETCD
    Stack3 <-->|"Leader Lease"| ETCD

    E1 <--> E2 <--> E3
    E1 <--> E3

    style PG1 fill:#4CAF50,color:#fff
    style PG2 fill:#2196F3,color:#fff
    style PG3 fill:#2196F3,color:#fff
    style ETCD fill:#FF9800,color:#fff

组件详解

PostgreSQL

PostgreSQL 是核心数据库服务,使用标准流复制(Streaming Replication)搭建物理从库:

  • 主库(Primary):接受读写请求,生成 WAL 日志
  • 从库(Replica):通过流复制实时接收 WAL,提供只读查询
  • 复制槽(Replication Slot):确保 WAL 不被过早清理
  • 同步提交:可选的同步复制模式,确保 RPO = 0

关键配置(由 Patroni 动态管理):

wal_level: logical                    # 启用逻辑复制级别
max_wal_senders: 50                   # 最大 WAL 发送进程数
max_replication_slots: 50             # 最大复制槽数量
hot_standby: on                       # 从库可读
wal_log_hints: on                     # 支持 pg_rewind
track_commit_timestamp: on            # 追踪事务时间戳
synchronous_standby_names: ''         # 同步从库列表(动态管理)

Patroni

Patroni 是高可用的核心引擎,负责管理 PostgreSQL 生命周期与集群状态:

核心职责

  • 管理 PostgreSQL 进程的启停与配置
  • 维护领导者租约(Leader Lease)
  • 执行自动故障切换(Failover)与主动切换(Switchover)
  • 提供 REST API 用于健康检查与集群管理
  • 处理从库的自动重建与 pg_rewind

关键时序参数(控制 RTO):

参数默认值说明
ttl30s领导者租约有效期,即故障检测时间窗口
loop_wait10sPatroni 主循环间隔
retry_timeout10sDCS 与 PostgreSQL 操作重试超时
primary_start_timeout10s主库启动超时时间
primary_stop_timeout30s主库优雅停止超时(同步模式下生效)

这些参数由 pg_rto 统一计算派生,默认 30s 的 RTO 对应:

ttl: 30                               # 领导者租约 TTL
loop_wait: 10                         # 主循环间隔 = RTO/3
retry_timeout: 10                     # 重试超时 = RTO/3
primary_start_timeout: 10             # 主库启动超时 = RTO/3

约束条件ttl >= loop_wait + retry_timeout * 2

健康检查端点(供 HAProxy 使用):

端点用途返回 200 条件
/primary主库服务当前节点是 Leader
/replica从库服务当前节点是 Replica
/read-only只读服务节点可读(主库或从库)
/health健康检查PostgreSQL 运行正常
/leader领导者检查持有领导者锁
/async异步从库异步复制从库
/sync同步从库同步复制从库

Etcd

Etcd 作为分布式配置存储(DCS),提供集群共识能力:

核心职责

  • 存储集群配置与状态信息
  • 提供领导者选举的原子操作
  • 通过租约机制实现故障检测
  • 存储 PostgreSQL 动态配置

存储结构(以 /pg 命名空间为例):

/pg/
├── <cluster_name>/
│   ├── leader          # 当前领导者标识
│   ├── config          # 集群配置(DCS 配置)
│   ├── history         # 故障切换历史
│   ├── initialize      # 集群初始化标记
│   ├── members/        # 成员信息目录
│   │   ├── pg-test-1   # 实例 1 元数据
│   │   ├── pg-test-2   # 实例 2 元数据
│   │   └── pg-test-3   # 实例 3 元数据
│   └── sync            # 同步从库状态

关键配置

election_timeout: 1000ms              # 选举超时(影响 Etcd 自身 HA)
heartbeat_interval: 100ms             # 心跳间隔
quota_backend_bytes: 16GB             # 存储配额
auto_compaction_mode: periodic        # 自动压缩
auto_compaction_retention: 24h        # 保留 24 小时历史

Etcd 集群要求

  • 必须奇数节点:3、5、7 个节点,确保多数派仲裁
  • 推荐独立部署于管理节点,与 PostgreSQL 节点分离
  • 网络延迟应保持在 10ms 以内

HAProxy

HAProxy 负责服务发现与流量分发:

核心职责

  • 通过 HTTP 健康检查发现主从角色
  • 将流量路由到正确的后端节点
  • 提供负载均衡与连接池功能
  • 实现服务的自动故障转移

默认服务定义

服务名端口目标健康检查用途
primary5433pgbouncer/primary读写服务,路由到主库
replica5434pgbouncer/read-only只读服务,优先路由到从库
default5436postgres/primary直连主库(绕过连接池)
offline5438postgres/replica离线从库(ETL/备份)

健康检查配置

listen pg-test-primary
    bind *:5433
    mode tcp
    option httpchk
    http-check send meth OPTIONS uri /primary
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3
                   on-marked-down shutdown-sessions slowstart 30s
                   maxconn 3000 maxqueue 128 weight 100
    server pg-test-1 10.10.10.11:6432 check port 8008
    server pg-test-2 10.10.10.12:6432 check port 8008 backup
    server pg-test-3 10.10.10.13:6432 check port 8008 backup

健康检查时序参数(影响 RTO 敏感度):

参数默认值说明
inter3s正常检查间隔
fastinter1s状态变化后的快速检查间隔
downinter5s节点宕机后的检查间隔
rise3节点恢复需要连续成功次数
fall3节点宕机需要连续失败次数

流量切换时序(主库故障):

  • 故障检测:fall × inter = 3 × 3s = 9s
  • 快速探测:一旦发现异常,切换到 fastinter(1s)
  • 服务恢复:新主库提升后,rise × fastinter = 3 × 1s = 3s

VIP Manager(可选)

vip-manager 提供可选的二层 VIP 支持:

工作原理

  1. 监听 Etcd 中的领导者键(/pg/<cluster>/leader
  2. 当本节点成为领导者时,绑定 VIP 到指定网卡
  3. 发送免费 ARP 通告网络中的设备更新 MAC 映射
  4. 当失去领导者地位时,解绑 VIP

配置示例

interval: 1000                        # 检查间隔(毫秒)
trigger-key: "/pg/pg-test/leader"     # 监听的 Etcd 键
trigger-value: "pg-test-1"            # 匹配的领导者值
ip: 10.10.10.100                      # VIP 地址
netmask: 24                           # 子网掩码
interface: eth0                       # 绑定网卡
dcs-type: etcd                        # DCS 类型
retry-num: 2                          # 重试次数
retry-after: 250                      # 重试间隔(毫秒)

使用限制

  • 要求所有节点在同一二层网络
  • 云环境通常不支持,需使用云厂商 VIP 或 DNS 方案
  • 切换时间约 1-2 秒

控制流与数据流

正常运行状态

控制流:Patroni 与 Etcd 之间的心跳与租约管理

flowchart LR
    subgraph Control["⚙️ 控制流 (Control Flow)"]
        direction LR
        P1["Patroni<br/>(Primary)"]
        P2["Patroni<br/>(Replica)"]
        ETCD[("Etcd<br/>Cluster")]

        P1 -->|"续租/心跳"| ETCD
        P2 -->|"续租/心跳"| ETCD
        ETCD -->|"租约/配置"| P1
        ETCD -->|"租约/配置"| P2
    end

    style ETCD fill:#FF9800,color:#fff

数据流:客户端请求与 WAL 复制

flowchart LR
    subgraph Data["📊 数据流 (Data Flow)"]
        direction LR
        CLIENT["Client"]
        HAP["HAProxy"]
        PGB["PgBouncer"]
        PG_P[("PostgreSQL<br/>[Primary]")]
        PG_R[("PostgreSQL<br/>[Replica]")]
        PATRONI["Patroni :8008"]

        CLIENT -->|"SQL Request"| HAP
        HAP -->|"路由"| PGB
        PGB --> PG_P
        HAP -.->|"健康检查<br/>/primary /replica"| PATRONI
        PG_P ==>|"WAL Stream"| PG_R
    end

    style PG_P fill:#4CAF50,color:#fff
    style PG_R fill:#2196F3,color:#fff

故障切换流程

当主库发生故障时,系统经历以下阶段:

sequenceDiagram
    autonumber
    participant Primary as 🟢 Primary
    participant Patroni_P as Patroni (Primary)
    participant Etcd as 🟠 Etcd Cluster
    participant Patroni_R as Patroni (Replica)
    participant Replica as 🔵 Replica
    participant HAProxy as HAProxy

    Note over Primary: T=0s 主库故障发生

    rect rgb(255, 235, 235)
        Note right of Primary: 故障检测阶段 (0-10s)
        Primary-x Patroni_P: 进程崩溃
        Patroni_P--x Etcd: 停止续租
        HAProxy--x Patroni_P: 健康检查失败
        Etcd->>Etcd: 租约倒计时开始
    end

    rect rgb(255, 248, 225)
        Note right of Etcd: 选举阶段 (10-20s)
        Etcd->>Etcd: 租约过期,释放领导者锁
        Patroni_R->>Etcd: 检查资格 (LSN, 复制延迟)
        Etcd->>Patroni_R: 授予领导者锁
    end

    rect rgb(232, 245, 233)
        Note right of Replica: 提升阶段 (20-30s)
        Patroni_R->>Replica: 执行 PROMOTE
        Replica-->>Replica: 提升为新主库
        Patroni_R->>Etcd: 更新状态
        HAProxy->>Patroni_R: 健康检查 /primary
        Patroni_R-->>HAProxy: 200 OK
    end

    Note over HAProxy: T≈30s 服务恢复
    HAProxy->>Replica: 路由写入流量到新主库

关键时序公式

RTO ≈ TTL + Election_Time + Promote_Time + HAProxy_Detection

其中:
- TTL = pg_rto (默认 30s)
- Election_Time ≈ 1-2s
- Promote_Time ≈ 1-5s
- HAProxy_Detection = fall × inter + rise × fastinter ≈ 12s

实际 RTO 通常在 15-40s 之间,取决于:
- 网络延迟
- 从库 WAL 回放进度
- PostgreSQL 恢复速度

高可用部署模式

三节点标准模式

最推荐的生产部署模式,提供完整的自动故障转移能力:

flowchart TB
    subgraph Cluster["🏢 三节点高可用架构"]
        direction TB

        subgraph Node1["Node 1"]
            E1[("Etcd")]
            H1["HAProxy"]
            P1["Patroni + PostgreSQL<br/>🟢 Primary"]
        end

        subgraph Node2["Node 2"]
            E2[("Etcd")]
            H2["HAProxy"]
            P2["Patroni + PostgreSQL<br/>🔵 Replica"]
        end

        subgraph Node3["Node 3"]
            E3[("Etcd")]
            H3["HAProxy"]
            P3["Patroni + PostgreSQL<br/>🔵 Replica"]
        end
    end

    E1 <-->|"Raft"| E2
    E2 <-->|"Raft"| E3
    E1 <-->|"Raft"| E3

    P1 ==>|"Replication"| P2
    P1 ==>|"Replication"| P3

    style P1 fill:#4CAF50,color:#fff
    style P2 fill:#2196F3,color:#fff
    style P3 fill:#2196F3,color:#fff
    style E1 fill:#FF9800,color:#fff
    style E2 fill:#FF9800,color:#fff
    style E3 fill:#FF9800,color:#fff

故障容忍

  • ✅ 任意 1 个节点故障:自动切换,服务继续
  • ⚠️ 2 个节点故障:需要人工介入

配置示例

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

五节点增强模式

更高可用性要求的部署,可容忍 2 个节点故障:

flowchart LR
    subgraph Cluster["🏛️ 五节点高可用架构"]
        direction TB

        subgraph Row1[""]
            direction LR
            N1["Node 1<br/>Etcd + 🟢 Primary"]
            N2["Node 2<br/>Etcd + 🔵 Replica"]
            N3["Node 3<br/>Etcd + 🔵 Replica"]
            N4["Node 4<br/>Etcd + 🔵 Replica"]
            N5["Node 5<br/>Etcd + 🔵 Replica"]
        end
    end

    N1 ==> N2 & N3 & N4 & N5

    N1 <-.->|"Etcd Raft"| N2
    N2 <-.->|"Etcd Raft"| N3
    N3 <-.->|"Etcd Raft"| N4
    N4 <-.->|"Etcd Raft"| N5

    style N1 fill:#4CAF50,color:#fff
    style N2 fill:#2196F3,color:#fff
    style N3 fill:#2196F3,color:#fff
    style N4 fill:#2196F3,color:#fff
    style N5 fill:#2196F3,color:#fff

Etcd 仲裁:3/5 多数派 | PostgreSQL:1 主 4 从

故障容忍

  • ✅ 任意 2 个节点故障:自动切换
  • ⚠️ 3 个节点故障:需要人工介入

适用场景

  • 金融核心系统
  • 跨机房部署(2+2+1 分布)
  • 需要专用离线从库的场景

两节点半高可用模式

资源受限时的折中方案,提供有限的自动切换能力:

flowchart TB
    subgraph Cluster["⚠️ 两节点半高可用架构"]
        direction LR

        subgraph Node1["Node 1 (Infra)"]
            E1[("Etcd")]
            H1["HAProxy"]
            P1["Patroni + PostgreSQL<br/>🟢 Primary"]
        end

        subgraph Node2["Node 2"]
            E2[("Etcd")]
            H2["HAProxy"]
            P2["Patroni + PostgreSQL<br/>🔵 Replica"]
        end

        subgraph Arbiter["❓ 需要仲裁者"]
            E3[("Etcd<br/>(外部)")]
        end
    end

    E1 <-->|"无法形成多数派"| E2
    E1 <-.-> E3
    E2 <-.-> E3

    P1 ==>|"Replication"| P2

    style P1 fill:#4CAF50,color:#fff
    style P2 fill:#2196F3,color:#fff
    style E1 fill:#FF9800,color:#fff
    style E2 fill:#FF9800,color:#fff
    style E3 fill:#9E9E9E,color:#fff,stroke-dasharray: 5 5

问题:Etcd 只有 2 节点,无法形成多数派

解决方案

  1. 在外部添加第 3 个 Etcd 节点(纯仲裁)
  2. 使用 failsafe_mode 防止脑裂
  3. 接受非对称故障切换

非对称故障切换

  • 从库故障:✅ 自动处理,主库继续服务
  • 主库故障:⚠️ 需要人工介入(无法自动选举)

配置建议

# 启用 failsafe 模式防止误切换
patroni_watchdog_mode: off            # 禁用 watchdog
pg_rto: 60                            # 增大 RTO 减少误报

同城双中心模式

同城容灾部署,机房级故障容忍:

flowchart TB
    subgraph DualDC["🌐 同城双中心架构"]
        direction TB

        subgraph DCA["📍 数据中心 A"]
            direction LR
            N1["Node 1<br/>Etcd + 🟢 Primary"]
            N2["Node 2<br/>Etcd + 🔵 Replica"]
        end

        subgraph DCB["📍 数据中心 B"]
            direction LR
            N3["Node 3<br/>Etcd + 🔵 Replica"]
            N4["Node 4<br/>Etcd + 🔵 Replica"]
        end

        subgraph Arbiter["🏠 第三方机房"]
            N5["Node 5<br/>Etcd (仲裁)"]
        end
    end

    N1 ==>|"Replication"| N2 & N3 & N4

    N1 & N2 <-->|"< 5ms"| N3 & N4
    N1 & N2 & N3 & N4 <-.->|"Etcd Raft"| N5

    style N1 fill:#4CAF50,color:#fff
    style N2 fill:#2196F3,color:#fff
    style N3 fill:#2196F3,color:#fff
    style N4 fill:#2196F3,color:#fff
    style N5 fill:#FF9800,color:#fff

网络要求

  • 机房间延迟 < 5ms(同步复制)或 < 20ms(异步复制)
  • 带宽充足,确保 WAL 传输
  • 仲裁节点可以是轻量级 VM

故障场景

故障影响恢复方式
DC-A 单节点故障无影响自动
DC-B 单节点故障无影响自动
DC-A 整体故障切换到 DC-B自动(需仲裁节点)
DC-B 整体故障无影响自动
仲裁节点故障降级为 4 节点可容忍 1 节点故障

异地多活模式

跨地域部署,需要考虑延迟与带宽:

flowchart LR
    subgraph GeoDR["🌍 异地容灾架构"]
        direction LR

        subgraph Beijing["🏙️ 主数据中心 (北京)"]
            direction TB
            BJ_E[("Etcd<br/>3节点")]
            BJ1["🟢 Primary"]
            BJ2["🔵 Replica"]
        end

        subgraph Shanghai["🏙️ 灾备数据中心 (上海)"]
            direction TB
            SH_E[("Etcd<br/>独立集群")]
            SH1["🔵 Replica"]
            SH2["🔵 Replica"]
        end
    end

    BJ1 ==>|"Async Replication<br/>延迟: 20-50ms"| SH1
    BJ1 --> BJ2
    SH1 --> SH2

    style BJ1 fill:#4CAF50,color:#fff
    style BJ2 fill:#2196F3,color:#fff
    style SH1 fill:#9C27B0,color:#fff
    style SH2 fill:#9C27B0,color:#fff
    style BJ_E fill:#FF9800,color:#fff
    style SH_E fill:#607D8B,color:#fff

部署策略

  1. 主中心:完整 HA 集群(3+ 节点)
  2. 灾备中心:级联从库(Standby Cluster)
  3. 异步复制:容忍网络延迟
  4. 独立 Etcd:避免跨地域仲裁

级联从库配置

# 灾备集群配置
pg-standby:
  hosts:
    10.20.10.11: { pg_seq: 1, pg_role: primary }  # 级联领导者
    10.20.10.12: { pg_seq: 2, pg_role: replica }
  vars:
    pg_cluster: pg-standby
    pg_upstream: 10.10.10.11          # 指向主集群
    pg_delay: 1h                       # 可选:延迟复制

故障场景分析

单节点故障

主库进程崩溃

场景:PostgreSQL 主库进程被 kill -9 或发生崩溃

flowchart LR
    subgraph Detection["🔍 故障检测"]
        D1["Patroni 检测进程消失"]
        D2["尝试重启 PostgreSQL"]
        D3["重启失败,停止续租"]
        D1 --> D2 --> D3
    end

    subgraph Failover["🔄 故障切换"]
        F1["Etcd 租约过期 (~10s)"]
        F2["触发选举,最新从库胜出"]
        F3["新主库提升"]
        F4["HAProxy 检测到新主库"]
        F1 --> F2 --> F3 --> F4
    end

    subgraph Impact["📊 影响"]
        I1["写服务中断: 15-30s"]
        I2["读服务: 短暂闪断"]
        I3["数据丢失: < 1MB 或 0"]
    end

    Detection --> Failover --> Impact

    style D1 fill:#ffcdd2
    style F3 fill:#c8e6c9
    style I1 fill:#fff9c4

Patroni 进程故障

场景:Patroni 进程被杀或崩溃

flowchart TB
    FAULT["Patroni 进程故障"]

    subgraph Detection["故障检测"]
        D1["Patroni 停止续租"]
        D2["PostgreSQL 继续运行<br/>(orphan 状态)"]
        D3["Etcd 租约倒计时"]
    end

    subgraph FailsafeOn["failsafe_mode: true"]
        FS1["检查是否能访问其他 Patroni"]
        FS2["✅ 可以 → 继续作为主库"]
        FS3["❌ 不能 → 自我降级"]
    end

    subgraph FailsafeOff["failsafe_mode: false"]
        FF1["租约过期后触发切换"]
        FF2["原主库降级"]
    end

    FAULT --> Detection
    Detection --> FailsafeOn
    Detection --> FailsafeOff

    style FAULT fill:#f44336,color:#fff
    style FS2 fill:#4CAF50,color:#fff
    style FS3 fill:#ff9800,color:#fff

从库故障

场景:任意从库节点故障

影响

  • 只读流量重新分配到其他从库
  • 如果无其他从库,主库承担只读流量
  • ✅ 写服务完全不受影响

恢复

  • 节点恢复后 Patroni 自动启动
  • 自动从主库重新同步
  • 恢复为从库角色

多节点故障

三节点坏两个(2/3 故障)

场景:3 节点集群,2 个节点同时故障

flowchart TB
    subgraph Analysis["情况分析"]
        A1["Etcd 失去多数派 (1/3 < 2/3)"]
        A2["无法进行领导者选举"]
        A3["自动切换机制失效"]
    end

    subgraph Survivor["存活节点情况"]
        S1{"存活节点是?"}
        S2["🟢 主库<br/>failsafe_mode 下继续运行"]
        S3["🔵 从库<br/>无法自动提升"]
    end

    A1 --> A2 --> A3 --> S1
    S1 -->|"Primary"| S2
    S1 -->|"Replica"| S3

    style A1 fill:#ffcdd2
    style S2 fill:#c8e6c9
    style S3 fill:#fff9c4

紧急恢复流程

# 1. 确认存活节点状态
patronictl -c /etc/patroni/patroni.yml list

# 2. 如果存活节点是从库,手动提升
pg_ctl promote -D /pg/data

# 3. 或者使用 pg-promote 脚本
/pg/bin/pg-promote

# 4. 修改 HAProxy 配置,直接指向存活节点
# 注释掉健康检查,硬编码路由

# 5. 恢复 Etcd 集群后,重新初始化

两节点坏一个(1/2 故障)

场景:2 节点集群,主库故障

问题

  • Etcd 只有 2 节点,无多数派
  • 无法完成选举
  • 从库无法自动提升

解决方案

  1. 方案 1:添加外部 Etcd 仲裁节点
  2. 方案 2:人工介入提升从库
  3. 方案 3:使用 Witness 节点

手动提升步骤

  1. 确认主库确实不可恢复
  2. 停止从库 Patroni:systemctl stop patroni
  3. 手动提升:pg_ctl promote -D /pg/data
  4. 直接启动 PostgreSQL:systemctl start postgres
  5. 更新应用连接串或 HAProxy 配置

Etcd 集群故障

Etcd 单节点故障

场景:3 节点 Etcd 集群,1 节点故障

影响

  • ✅ Etcd 仍有多数派(2/3)
  • ✅ 服务正常运行
  • ✅ PostgreSQL HA 不受影响

恢复

  • 修复故障节点
  • 使用 etcd-add 重新加入
  • 或替换为新节点

Etcd 多数派丢失

场景:3 节点 Etcd 集群,2 节点故障

flowchart TB
    subgraph Impact["❌ 影响"]
        I1["Etcd 无法写入"]
        I2["Patroni 无法续租"]
        I3["failsafe_mode 激活"]
        I4["无法进行故障切换"]
    end

    subgraph PG["PostgreSQL 表现"]
        P1["🟢 主库: 继续运行"]
        P2["🔵 从库: 继续复制"]
        P3["✅ 新写入可以继续"]
    end

    subgraph Limit["⚠️ 限制"]
        L1["无法 switchover"]
        L2["无法 failover"]
        L3["配置变更无法生效"]
    end

    Impact --> PG --> Limit

    style I1 fill:#ffcdd2
    style P1 fill:#c8e6c9
    style L1 fill:#fff9c4

恢复优先级

  1. 恢复 Etcd 多数派
  2. 验证 PostgreSQL 状态
  3. 检查 Patroni 是否正常续租

网络分区

主库网络隔离

场景:主库与 Etcd/其他节点网络不通

flowchart LR
    subgraph Isolated["🔒 隔离侧 (主库)"]
        P1["Primary"]
        CHECK{"failsafe_mode<br/>检查"}
        CONT["继续运行"]
        DEMOTE["自我降级"]

        P1 --> CHECK
        CHECK -->|"能访问其他 Patroni"| CONT
        CHECK -->|"不能访问"| DEMOTE
    end

    subgraph Majority["✅ 多数派侧"]
        E[("Etcd")]
        P2["Replica"]
        ELECT["触发选举"]
        NEWPRI["新主库产生"]

        E --> ELECT --> P2 --> NEWPRI
    end

    Isolated -.->|"网络分区"| Majority

    style P1 fill:#ff9800,color:#fff
    style DEMOTE fill:#f44336,color:#fff
    style NEWPRI fill:#4CAF50,color:#fff

脑裂防护

  • Patroni failsafe_mode
  • 旧主库自我检测
  • fencing(可选)
  • Watchdog(可选)

Watchdog 机制

用于极端情况下的防护

watchdog:
  mode: automatic                     # off|automatic|required
  device: /dev/watchdog
  safety_margin: 5                    # 安全边际(秒)

工作原理

  • Patroni 定期向 watchdog 设备写入
  • 如果 Patroni 无响应,内核触发重启
  • 确保旧主库不会继续服务
  • 防止严重的脑裂场景

RTO / RPO 深度分析

RTO 时序分解

恢复时间目标(RTO) 由多个阶段组成:

gantt
    title RTO 时间分解 (默认配置 pg_rto=30s)
    dateFormat ss
    axisFormat %S秒

    section 故障检测
    Patroni 检测/停止续租    :a1, 00, 10s

    section 选举阶段
    Etcd 租约过期           :a2, after a1, 2s
    候选者竞选 (比较 LSN)    :a3, after a2, 3s

    section 提升阶段
    执行 promote            :a4, after a3, 3s
    更新 Etcd 状态          :a5, after a4, 2s

    section 流量切换
    HAProxy 检测新主库      :a6, after a5, 5s
    HAProxy 确认 (rise)     :a7, after a6, 3s
    服务恢复                :milestone, after a7, 0s

影响 RTO 的关键参数

参数影响调优建议
pg_rtoTTL/loop_wait/retry_timeout 的基准网络稳定可减小到 15-20s
ttl故障检测时间窗口= pg_rto
loop_waitPatroni 检查间隔= pg_rto / 3
interHAProxy 健康检查间隔可减小到 1-2s
fall故障判定次数可减小到 2
rise恢复判定次数可减小到 2

激进配置(RTO ≈ 15s)

pg_rto: 15                            # 更短的 TTL

# HAProxy 配置
default-server inter 1s fastinter 500ms fall 2 rise 2

警告:过短的 RTO 会增加误报切换的风险!


RPO 时序分解

恢复点目标(RPO) 取决于复制模式:

异步复制模式(默认)

sequenceDiagram
    participant P as 🟢 Primary
    participant W as WAL
    participant R as 🔵 Replica

    Note over P: T=0 Commit

    P->>W: WAL 写入本地
    P-->>P: 返回成功给客户端

    Note over P,R: T+Δ (复制延迟)

    P->>R: WAL 发送
    R->>R: WAL 接收 & 回放

    Note over P: T+X 故障发生
    Note over P: ❌ 未发送的 WAL 丢失

    Note over R: RPO = Δ ≈ 几十KB ~ 1MB

复制延迟监控

-- 查看复制延迟
SELECT client_addr,
       state,
       sent_lsn,
       write_lsn,
       flush_lsn,
       replay_lsn,
       pg_wal_lsn_diff(sent_lsn, replay_lsn) AS lag_bytes
FROM pg_stat_replication;

同步复制模式(RPO = 0)

sequenceDiagram
    participant P as 🟢 Primary
    participant W as WAL
    participant R as 🔵 Sync Replica

    Note over P: T=0 Commit

    P->>W: WAL 写入本地
    P->>R: WAL 发送
    R->>R: WAL 接收
    R-->>P: 确认接收 ✓
    P-->>P: 返回成功给客户端

    Note over P: 故障发生
    Note over R: ✅ 所有已提交数据已在从库
    Note over P,R: RPO = 0 (零数据丢失)

启用同步复制

# 使用 crit.yml 模板
pg_conf: crit.yml

# 或设置 RPO = 0
pg_rpo: 0

# Patroni 将自动配置:
# synchronous_mode: true
# synchronous_standby_names: '*'

RTO / RPO 权衡矩阵

配置模式pg_rtopg_rpo实际 RTO实际 RPO适用场景
默认 (OLTP)30s1MB20-40s< 1MB常规业务系统
快速切换15s1MB10-20s< 1MB低延迟要求
零丢失 (CRIT)30s020-40s0金融核心系统
保守模式60s1MB40-80s< 1MB不稳定网络

配置示例

# 快速切换模式
pg_rto: 15
pg_rpo: 1048576
pg_conf: oltp.yml

# 零丢失模式
pg_rto: 30
pg_rpo: 0
pg_conf: crit.yml

# 保守模式(不稳定网络)
pg_rto: 60
pg_rpo: 1048576
pg_conf: oltp.yml

利弊权衡

可用性优先 vs 一致性优先

维度可用性优先 (默认)一致性优先 (crit)
同步复制关闭开启
故障切换快速,可能丢数据谨慎,零数据丢失
写延迟高(多一次网络往返)
吞吐量较低
从库故障影响可能阻塞写入
RPO< 1MB= 0

RTO 权衡

较小 RTO较大 RTO
✅ 故障恢复快✅ 误报风险低
✅ 业务中断短✅ 网络抖动容忍度高
❌ 误报切换风险高❌ 故障恢复慢
❌ 网络要求严格❌ 业务中断长

RPO 权衡

较大 RPORPO = 0
✅ 高性能✅ 零数据丢失
✅ 高可用(单从库故障无影响)✅ 金融合规
❌ 故障可能丢数据❌ 写延迟增加
❌ 同步从库故障影响写入

最佳实践

生产环境检查清单

基础设施

  • 至少 3 个节点(PostgreSQL)
  • 至少 3 个节点(Etcd,可与 PG 共用)
  • 节点分布在不同故障域(机架/可用区)
  • 网络延迟 < 10ms(同城)或 < 50ms(异地)
  • 万兆网络(推荐)

参数配置

  • pg_rto 根据网络状况调整(15-60s)
  • pg_rpo 根据业务需求设置(0 或 1MB)
  • pg_conf 选择合适的模板(oltp/crit)
  • patroni_watchdog_mode 评估是否需要

监控告警

  • Patroni 状态监控(领导者/复制延迟)
  • Etcd 集群健康监控
  • 复制延迟告警(lag > 1MB)
  • failsafe_mode 激活告警

灾备演练

  • 定期执行故障切换演练
  • 验证 RTO/RPO 是否符合预期
  • 测试备份恢复流程
  • 验证监控告警有效性

常见问题排查

故障切换失败

# 检查 Patroni 状态
patronictl -c /etc/patroni/patroni.yml list

# 检查 Etcd 集群健康
etcdctl endpoint health

# 检查复制延迟
psql -c "SELECT * FROM pg_stat_replication"

# 查看 Patroni 日志
journalctl -u patroni -f

脑裂场景处理

# 1. 确认哪个是"真正"的主库
psql -c "SELECT pg_is_in_recovery()"

# 2. 停止"错误"的主库
systemctl stop patroni

# 3. 使用 pg_rewind 同步
pg_rewind --target-pgdata=/pg/data --source-server="host=<true_primary>"

# 4. 重启 Patroni
systemctl start patroni

相关参数

pg_rto

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

以秒为单位的恢复时间目标(RTO)。默认为 30 秒。

此参数用于派生 Patroni 的关键时序参数:

  • ttl = pg_rto
  • loop_wait = pg_rto / 3
  • retry_timeout = pg_rto / 3
  • primary_start_timeout = pg_rto / 3

减小此值可以加快故障恢复,但会增加误报切换的风险。

pg_rpo

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

以字节为单位的恢复点目标(RPO),默认为 1048576(1MB)。

  • 设为 0 启用同步复制,确保零数据丢失
  • 设为较大值允许更多复制延迟,提高可用性
  • 此值也用于 maximum_lag_on_failover 参数

pg_conf

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

Patroni 配置模板,默认为 oltp.yml。可选值:

模板用途同步复制适用场景
oltp.ymlOLTP 负载常规业务系统
olap.ymlOLAP 负载分析型应用
crit.yml关键系统金融核心系统
tiny.yml微型实例开发测试环境

patroni_watchdog_mode

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

Watchdog 模式,默认为 off。可选值:

  • off:禁用 watchdog
  • automatic:如果可用则使用
  • required:必须使用,否则拒绝启动

Watchdog 用于在极端情况下(如 Patroni 挂起)确保节点自我重启,防止脑裂。

pg_vip_enabled

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

是否启用 L2 VIP,默认为 false

启用后需要配置:

  • pg_vip_address:VIP 地址(CIDR 格式)
  • pg_vip_interface:绑定网卡

注意:云环境通常不支持 L2 VIP。


参考资料

5 - 时间点恢复

介绍 Pigsty 中 PostgreSQL 时间点恢复的实现架构,原理,利弊权衡与实现细节。

您可以将集群恢复回滚至过去任意时刻,避免软件缺陷与人为失误导致的数据损失。

Pigsty 的 PostgreSQL 集群带有自动配置的时间点恢复(PITR)方案,基于备份组件 pgBackRest 与可选的对象存储仓库 MinIO 提供。

高可用方案 可以解决硬件故障,但却对软件缺陷与人为失误导致的数据删除/覆盖写入/删库等问题却无能为力。 对于这种情况,Pigsty 提供了开箱即用的 时间点恢复(Point in Time Recovery, PITR)能力,无需额外配置即默认启用。

Pigsty 为您提供了基础备份与 WAL 归档的默认配置,您可以使用本地目录与磁盘,亦或专用的 MinIO 集群或 S3 对象存储服务来存储备份并实现异地容灾。 当您使用本地磁盘时,默认保留恢复至过去一天内的任意时间点的能力。当您使用 MinIO 或 S3 时,默认保留恢复至过去一周内的任意时间点的能力。 只要存储空间管够,您尽可保留任意长地可恢复时间段,丰俭由人。


时间点恢复(PITR)解决什么问题?

  • 容灾能⼒增强:RPO 从 ∞ 降⾄ ⼗⼏MB, RTO 从 ∞ 降⾄ ⼏⼩时/⼏刻钟。
  • 确保数据安全:C/I/A 中的 数据完整性:避免误删导致的数据⼀致性问题。
  • 确保数据安全:C/I/A 中的 数据可⽤性:提供对“永久不可⽤”这种灾难情况的兜底
单实例配置策略事件RTORPO
什么也不做宕机 永久丢失 全部丢失
基础备份宕机 取决于备份大小与带宽(几小时) 丢失上一次备份后的数据(几个小时到几天)
基础备份 + WAL归档宕机 取决于备份大小与带宽(几小时) 丢失最后尚未归档的数据(几十MB)

时间点恢复有什么代价?

  • 降低数据安全中的 C:机密性,产生额外泄漏点,需要额外对备份进⾏保护。
  • 额外的资源消耗:本地存储或⽹络流量 / 带宽开销,通常并不是⼀个问题。
  • 复杂度代价升⾼:⽤户需要付出备份管理成本。

时间点恢复的局限性

如果只有 PITR 用于故障恢复,则 RTO 与 RPO 指标相比 高可用方案 更为逊色,通常应两者组合使用。

  • RTO:如果只有单机 + PITR,恢复时长取决于备份大小与网络/磁盘带宽,从十几分钟到几小时,几天不等。
  • RPO:如果只有单机 + PITR,宕机时可能丢失少量数据,一个或几个 WAL 日志段文件可能尚未归档,损失 16 MB 到⼏⼗ MB 不等的数据。

除了 PITR 之外,您还可以在 Pigsty 中使用 延迟集群 来解决人为失误或软件缺陷导致的数据误删误改问题。


原理

时间点恢复允许您将集群恢复回滚至过去的“任意时刻”,避免软件缺陷与人为失误导致的数据损失。要做到这一点,首先需要做好两样准备工作:基础备份WAL归档。 拥有 基础备份,允许用户将数据库恢复至备份时的状态,而同时拥有从某个基础备份开始的 WAL归档,允许用户将数据库恢复至基础备份时刻之后的任意时间点。

fig-10-02.png

详细原理,请参阅:基础备份与时间点恢复;具体操作,请参考 PGSQL管理:备份恢复

基础备份

Pigsty 使用 pgbackrest 管理 PostgreSQL 备份。pgBackRest 将在所有集群实例上初始化空仓库,但只会在集群主库上实际使用仓库。

pgBackRest 支持三种备份模式:全量备份增量备份,差异备份,其中前两者最为常用。 全量备份将对数据库集群取一个当前时刻的全量物理快照,增量备份会记录当前数据库集群与上一次全量备份之间的差异。

Pigsty 为备份提供了封装命令:/pg/bin/pg-backup [full|incr]。您可以通过 Crontab 或任何其他任务调度系统,按需定期制作基础备份。

WAL归档

Pigsty 默认在集群主库上启⽤了 WAL 归档,并使⽤ pgbackrest 命令行工具持续推送 WAL 段⽂件至备份仓库。

pgBackRest 会⾃动管理所需的 WAL ⽂件,并根据备份的保留策略及时清理过期的备份,与其对应的 WAL 归档⽂件。

如果您不需要 PITR 功能,可以通过 配置集群archive_mode: off 来关闭 WAL 归档,移除 node_crontab 来停止定期备份任务。


实现

默认情况下,Pigsty提供了两种预置备份策略:默认使用本地文件系统备份仓库,在这种情况下每天进行一次全量备份,确保用户任何时候都能回滚至一天内的任意时间点。备选策略使用专用的 MinIO 集群或S3存储备份,每周一全备,每天一增备,默认保留两周的备份与WAL归档。

Pigsty 使用 pgBackRest 管理备份,接收 WAL 归档,执行 PITR。备份仓库可以进行灵活配置(pgbackrest_repo):默认使用主库本地文件系统(local),但也可以使用其他磁盘路径,或使用自带的可选 MinIO 服务(minio)与云上 S3 服务。

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

Pigsty 参数 pgbackrest_repo 中的目标仓库会被转换为 /etc/pgbackrest/pgbackrest.conf 配置文件中的仓库定义。 例如,如果您定义了一个美西区的 S3 仓库用于存储冷备份,可以使用下面的参考配置。

s3:    # ------> /etc/pgbackrest/pgbackrest.conf
  repo1-type: s3                                   # ----> repo1-type=s3
  repo1-s3-region: us-west-1                       # ----> repo1-s3-region=us-west-1
  repo1-s3-endpoint: s3-us-west-1.amazonaws.com    # ----> repo1-s3-endpoint=s3-us-west-1.amazonaws.com
  repo1-s3-key: '<your_access_key>'                # ----> repo1-s3-key=<your_access_key>
  repo1-s3-key-secret: '<your_secret_key>'         # ----> repo1-s3-key-secret=<your_secret_key>
  repo1-s3-bucket: pgsql                           # ----> repo1-s3-bucket=pgsql
  repo1-s3-uri-style: host                         # ----> repo1-s3-uri-style=host
  repo1-path: /pgbackrest                          # ----> repo1-path=/pgbackrest
  repo1-bundle: y                                  # ----> repo1-bundle=y
  repo1-cipher-type: aes-256-cbc                   # ----> repo1-cipher-type=aes-256-cbc
  repo1-cipher-pass: pgBackRest                    # ----> repo1-cipher-pass=pgBackRest
  repo1-retention-full-type: time                  # ----> repo1-retention-full-type=time
  repo1-retention-full: 90                         # ----> repo1-retention-full=90

恢复

您可以直接使用以下封装命令可以用于 PostgreSQL 数据库集群的 时间点恢复

Pigsty 默认使用增量差分并行恢复,允许您以最快速度恢复到指定时间点。

pg-pitr                                 # 恢复到WAL存档流的结束位置(例如在整个数据中心故障的情况下使用)
pg-pitr -i                              # 恢复到最近备份完成的时间(不常用)
pg-pitr --time="2022-12-30 14:44:44+08" # 恢复到指定的时间点(在删除数据库或表的情况下使用)
pg-pitr --name="my-restore-point"       # 恢复到使用 pg_create_restore_point 创建的命名恢复点
pg-pitr --lsn="0/7C82CB8" -X            # 在LSN之前立即恢复
pg-pitr --xid="1234567" -X -P           # 在指定的事务ID之前立即恢复,然后将集群直接提升为主库
pg-pitr --backup=latest                 # 恢复到最新的备份集
pg-pitr --backup=20221108-105325        # 恢复到特定备份集,备份集可以使用 pgbackrest info 列出

pg-pitr                                 # pgbackrest --stanza=pg-meta restore
pg-pitr -i                              # pgbackrest --stanza=pg-meta --type=immediate restore
pg-pitr -t "2022-12-30 14:44:44+08"     # pgbackrest --stanza=pg-meta --type=time --target="2022-12-30 14:44:44+08" restore
pg-pitr -n "my-restore-point"           # pgbackrest --stanza=pg-meta --type=name --target=my-restore-point restore
pg-pitr -b 20221108-105325F             # pgbackrest --stanza=pg-meta --type=name --set=20221230-120101F restore
pg-pitr -l "0/7C82CB8" -X               # pgbackrest --stanza=pg-meta --type=lsn --target="0/7C82CB8" --target-exclusive restore
pg-pitr -x 1234567 -X -P                # pgbackrest --stanza=pg-meta --type=xid --target="0/7C82CB8" --target-exclusive --target-action=promote restore

在执行 PITR 时,您可以使用 Pigsty 监控系统观察集群 LSN 位点状态,判断是否成功恢复到指定的时间点,事务点,LSN位点,或其他点位。

pitr




6 - 安全与合规

Pigsty 中 PostgreSQL 集群的安全特性与合规能力详解

Pigsty v4.0 提供了 企业级 的 PostgreSQL 安全配置,涵盖身份鉴别、访问控制、通信加密、审计日志、数据完整性、备份恢复等多个维度。

本文档以 中国等保三级(GB/T 22239-2019)和 SOC 2 Type II 安全合规要求为参照,逐项对比验证 Pigsty 的安全能力。

每个安全维度包含两部分说明:

  • 默认配置:使用 conf/meta.yml 及默认参数时的安全合规状态 (个人使用)
  • 可用配置:通过调整 Pigsty 参数可达到的增强安全状态 (企业级配置可达)

合规对照总结

等保三级核心要求对照

要求项默认满足配置可达说明
身份唯一性角色系统保证用户唯一标识
口令复杂度⚠️可启用 passwordcheck / credcheck 强制执行密码复杂度
口令定期更换⚠️通过 expire_in/expire_at 设置用户有效期并定时刷新
登录失败处理⚠️日志中记录失败的登陆请求,可配合 fail2ban 自动封禁
双因素认证⚠️密码 + 客户端 SSL 证书认证
访问控制HBA规则 + RBAC + SELinux
最小权限分层角色体系
权限分离DBA / Monitor / 应用读/写/ETL/个人用户分离
通信加密默认启用并使用 SSL,可强制 SSL
数据完整性数据校验和默认启用
存储加密⚠️备份加密 + Percona TDE 内核支持
审计日志日志记录 DDL 与敏感操作,可记录所有操作。
日志保护文件权限隔离,VictoriaLogs 集中收集防篡改
备份恢复pgBackRest 自动备份
网络隔离防火墙 + HBA

SOC 2 Type II 控制点对照

控制点默认满足配置可达说明
CC6.1 逻辑访问控制HBA + RBAC + SELinux
CC6.2 用户注册授权Ansible声明式管理
CC6.3 最小权限分层角色
CC6.6 传输加密SSL/TLS 全局启用
CC6.7 静态加密⚠️可使用 Percona PGTDE 内核,以及 pgsodium/valut 等扩展
CC6.8 恶意软件防护⚠️最小安装 + 审计
CC7.1 入侵检测⚠️设置日志 Auth Fail 监控告警规则
CC7.2 系统监控VictoriaMetrics + Grafana
CC7.3 事件响应Alertmanager
CC9.1 业务连续性HA + 自动故障转移
A1.2 数据恢复PITR备份恢复

图例:✅ 默认满足 ⚠️ 需要额外配置


身份鉴别

等保要求:应对登录的用户进行身份标识和鉴别,身份标识具有唯一性;应采用口令、密码技术、生物技术等两种或两种以上组合的鉴别技术。

SOC 2:CC6.1 - 逻辑和物理访问控制;用户身份验证机制。

用户身份标识

PostgreSQL 通过角色(Role)系统实现用户身份标识,每个用户具有唯一的角色名。

配置项默认值说明
pg_default_roles4个默认角色 + 4个系统用户预定义角色体系
pg_users[]业务用户定义列表

默认配置:Pigsty 预置了分层的角色体系:

pg_default_roles:
  - { name: dbrole_readonly  ,login: false ,comment: '全局只读角色' }
  - { name: dbrole_offline   ,login: false ,comment: '受限只读角色(离线查询)' }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: '全局读写角色' }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor,dbrole_readwrite] ,comment: '对象管理角色' }
  - { name: postgres         ,superuser: true  ,comment: '系统超级用户' }
  - { name: replicator       ,replication: true,roles: [pg_monitor,dbrole_readonly] ,comment: '复制用户' }
  - { name: dbuser_dba       ,superuser: true  ,roles: [dbrole_admin] ,pgbouncer: true ,comment: '管理员用户' }
  - { name: dbuser_monitor   ,roles: [pg_monitor,dbrole_readonly] ,pgbouncer: true ,comment: '监控用户' }

可用配置:用户可通过 pg_users 定义业务用户,支持设置账户有效期、连接限制等:

pg_users:
  - name: dbuser_app
    password: 'SecurePass123!'
    roles: [dbrole_readwrite]
    expire_in: 365           # 365天后过期
    connlimit: 100           # 最大100个连接
    comment: '应用程序用户'

密码策略

配置项默认值说明
pg_pwd_encscram-sha-256密码加密算法
pg_dbsu_password''(空)数据库超级用户密码

默认配置

  • 密码加密采用 SCRAM-SHA-256 算法,这是目前 PostgreSQL 支持的最安全的密码哈希算法
  • 密码在设置时自动使用 SET log_statement TO 'none' 防止明文泄露到日志
  • 数据库超级用户 postgres 默认无密码,仅允许通过本地 Unix Socket 使用 ident 认证

可用配置

  • 启用 passwordcheck 扩展强制密码复杂度:

    pg_libs: 'passwordcheck, pg_stat_statements, auto_explain'
    
  • 使用 credcheck 扩展实现更丰富的密码策略(长度、复杂度、历史记录等)

  • 设置用户账户有效期:

    pg_users:
      - { name: temp_user, password: 'xxx', expire_in: 30 }  # 30天后过期
      - { name: temp_user, password: 'xxx', expire_at: '2025-12-31' }  # 指定日期过期
    

认证机制

配置项默认值说明
pg_default_hba_rules12条规则默认HBA认证规则
pg_hba_rules[]业务HBA规则

默认配置:Pigsty 实现了基于来源地址的分层认证策略:

pg_default_hba_rules:
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu本地ident认证'}
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu本地复制'}
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: '复制用户本地密码认证'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: '复制用户内网密码认证'}
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: '复制用户内网访问postgres'}
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: '监控用户本地密码认证'}
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: '监控用户从基础设施节点访问'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: '管理员SSL+密码认证'}
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: '管理员全局SSL+密码认证'}
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: '只读角色本地密码认证'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: '只读角色内网密码认证'}
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: '离线角色内网密码认证'}

支持的认证方法别名:

别名实际方法说明
denyreject拒绝连接
pwdscram-sha-256密码认证(默认加密)
sslscram-sha-256 + hostsslSSL + 密码认证
certcert客户端证书认证
os/ident/peerident/peer操作系统用户映射
trusttrust无条件信任(不推荐)

可用配置

  • 启用客户端证书认证实现双因素认证:

    pg_hba_rules:
      - {user: 'secure_user', db: all, addr: world, auth: cert, title: '证书认证用户'}
    
  • 限制特定用户只能从指定 IP 访问:

    pg_hba_rules:
      - {user: 'app_user', db: 'appdb', addr: '192.168.1.100/32', auth: ssl}
    

访问控制

等保要求:应授予管理用户所需的最小权限,实现管理用户的权限分离;应由授权主体配置访问控制策略。

SOC 2:CC6.3 - 基于角色的访问控制和最小权限原则。

权限分离

默认配置:Pigsty 实现了清晰的职责分离模型:

角色权限用途
postgresSUPERUSER系统超级用户,仅限本地OS认证
dbuser_dbaSUPERUSER + dbrole_admin数据库管理员
replicatorREPLICATION + pg_monitor复制和监控
dbuser_monitorpg_monitor + dbrole_readonly只读监控
dbrole_adminCREATE + dbrole_readwrite对象管理(DDL)
dbrole_readwriteINSERT/UPDATE/DELETE + dbrole_readonly数据读写
dbrole_readonlySELECT只读访问
dbrole_offlineSELECT(受限)离线/ETL查询

可用配置

  • 细粒度权限控制通过 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 INSERT     ON TABLES    TO dbrole_readwrite
      - GRANT UPDATE     ON TABLES    TO dbrole_readwrite
      - GRANT DELETE     ON TABLES    TO dbrole_readwrite
      - GRANT TRUNCATE   ON TABLES    TO dbrole_admin
      - GRANT CREATE     ON SCHEMAS   TO dbrole_admin
    

操作系统层面权限

配置项默认值说明
pg_dbsupostgres数据库超级用户OS账号
pg_dbsu_sudolimitsudo权限级别
node_admin_sudonopass管理员sudo权限

默认配置

  • 数据库超级用户 postgres 的 sudo 权限为 limit,仅允许执行特定的服务管理命令:
    • 启动/停止/重启 PostgreSQL 相关服务
    • 加载 softdog 内核模块(用于 watchdog)
%postgres ALL=NOPASSWD: /bin/systemctl stop postgres
%postgres ALL=NOPASSWD: /bin/systemctl start postgres
%postgres ALL=NOPASSWD: /bin/systemctl reload patroni
# ... 等受限命令

可用配置

  • pg_dbsu_sudo: none - 完全禁用 sudo 权限(最严格)
  • pg_dbsu_sudo: all - 需要密码的完整 sudo(平衡方案)
  • pg_dbsu_sudo: nopass - 无密码完整 sudo(不推荐)

行级安全策略(RLS)

PostgreSQL 原生支持行级安全策略(Row Level Security),可通过 pg_users 设置用户属性:

pg_users:
  - name: secure_user
    bypassrls: false  # 不允许绕过RLS
    roles: [dbrole_readwrite]

配合数据库内的 RLS 策略,可实现细粒度的数据访问控制。


通信安全

等保要求:应采用密码技术保证通信过程中数据的完整性和保密性。

SOC 2:CC6.6 - 数据传输安全;CC6.7 - 加密控制。

SSL/TLS 加密

配置项默认值说明
ssl (postgresql.conf)on服务端 SSL 开关
patroni_ssl_enabledfalsePatroni API SSL
pgbouncer_sslmodedisablePgBouncer 客户端 SSL
nginx_sslmodeenableNginx HTTPS

默认配置

  • PostgreSQL 服务端 默认启用 SSL,支持加密连接
  • 管理员用户(${admin})强制使用 hostssl 连接
  • 自动生成并分发 SSL 证书到所有数据库节点
# patroni.yml 中的 SSL 配置
ssl: 'on'
ssl_cert_file: '/pg/cert/server.crt'
ssl_key_file: '/pg/cert/server.key'
ssl_ca_file: '/pg/cert/ca.crt'

可用配置

  • 启用 Patroni REST API SSL 加密:

    patroni_ssl_enabled: true
    
  • 启用 PgBouncer 客户端 SSL:

    pgbouncer_sslmode: require  # 或 verify-ca, verify-full
    
  • 强制所有连接使用 SSL:

    pg_hba_rules:
      - {user: all, db: all, addr: world, auth: ssl, title: '强制SSL'}
    

PKI 证书管理

配置项默认值说明
cert_validity7300d证书有效期(20年)
CA 证书有效期100年自签名 CA 有效期

默认配置

Pigsty 使用自建 PKI 体系,自动管理证书生命周期:

files/pki/
├── ca/           # CA 根证书
│   ├── ca.crt    # CA 公钥证书
│   └── ca.key    # CA 私钥
├── csr/          # 证书签名请求
├── pgsql/        # PostgreSQL 集群证书
├── etcd/         # ETCD 集群证书
├── infra/        # 基础设施节点证书
└── minio/        # MinIO 证书
  • 每个 PostgreSQL 集群共享一个私钥,每个实例有独立的证书
  • 证书包含正确的 SAN(Subject Alternative Name)配置
  • CA 证书自动分发到 /etc/pki/ca.crt/pg/cert/ca.crt

可用配置

  • 使用外部 CA 签发的证书:将证书放入 files/pki/ 目录,设置 ca_create: false
  • 调整证书有效期:cert_validity: 365d(1年)

ETCD 通信安全

ETCD 作为 Patroni 的 DCS(分布式配置存储),默认使用 mTLS(双向 TLS)认证:

etcd3:
  hosts: '10.10.10.10:2379'
  protocol: https
  cacert: /pg/cert/ca.crt
  cert:   /pg/cert/server.crt
  key:    /pg/cert/server.key
  username: 'pg-meta'        # 集群专用账号
  password: 'pg-meta'        # 默认与集群名相同

数据加密

等保要求:应采用密码技术保证重要数据在存储过程中的保密性。

SOC 2:CC6.1 - 数据加密存储。

备份加密

配置项默认值说明
cipher_typeaes-256-cbc备份加密算法(MinIO仓库)
cipher_passpgBackRest加密密码(需修改)

默认配置

  • 本地备份(pgbackrest_method: local)默认不加密
  • 远程对象存储备份支持 AES-256-CBC 加密

可用配置

启用备份加密(推荐用于远程存储):

pgbackrest_method: minio
pgbackrest_repo:
  minio:
    type: s3
    s3_endpoint: sss.pigsty
    s3_bucket: pgsql
    s3_key: pgbackrest
    s3_key_secret: S3User.Backup
    cipher_type: aes-256-cbc
    cipher_pass: 'YourSecureBackupPassword!'  # 务必修改!
    retention_full_type: time
    retention_full: 14

透明数据加密(TDE)

PostgreSQL 社区版本不支持原生 TDE,但可通过以下方式实现存储加密:

  • 文件系统级加密:使用 LUKS/dm-crypt 加密存储卷
  • pgsodium 扩展:支持列级加密
# 启用 pgsodium 列级加密
pg_libs: 'pgsodium, pg_stat_statements, auto_explain'

# 自定义加密密钥(64位十六进制)
pgsodium_key: 'a1b2c3d4e5f6...'  # 或使用外部密钥管理脚本

数据完整性校验

配置项默认值说明
pg_checksumtrue数据校验和

默认配置

  • 数据校验和默认启用,可检测存储层数据损坏
  • crit.yml 模板强制启用数据校验和
  • 支持 pg_rewind 进行故障恢复
pg_checksum: true  # 强烈建议保持启用

安全审计

等保要求:应启用安全审计功能,审计覆盖到每个用户,对重要的用户行为和重要安全事件进行审计。

SOC 2:CC7.2 - 系统监控和日志记录;CC7.3 - 安全事件检测。

数据库审计日志

配置项默认值说明
logging_collectoron启用日志收集器
log_destinationcsvlogCSV格式日志
log_statementddl记录DDL语句
log_min_duration_statement100ms慢查询阈值
log_connectionsauthorization (PG18) / on连接审计
log_disconnectionson (crit模板)断开连接审计
log_checkpointson检查点日志
log_lock_waitson锁等待日志
log_replication_commandson复制命令日志

默认配置

# oltp.yml 模板的审计配置
log_destination: csvlog
logging_collector: 'on'
log_directory: /pg/log/postgres
log_filename: 'postgresql-%a.log'    # 按星期轮转
log_file_mode: '0640'                # 限制日志文件权限
log_rotation_age: '1d'
log_truncate_on_rotation: 'on'
log_checkpoints: 'on'
log_lock_waits: 'on'
log_replication_commands: 'on'
log_statement: ddl                   # 记录所有DDL
log_min_duration_statement: 100      # 记录慢查询 >100ms

可用配置(crit.yml 关键业务模板)

# crit.yml 提供更全面的审计
log_connections: 'receipt,authentication,authorization'  # PG18完整连接审计
log_disconnections: 'on'             # 记录断开连接
log_lock_failures: 'on'              # 记录锁失败(PG18)
track_activity_query_size: 32768     # 完整查询记录

启用 pgaudit 扩展实现细粒度审计:

pg_libs: 'pgaudit, pg_stat_statements, auto_explain'
pg_parameters:
  pgaudit.log: 'all'
  pgaudit.log_catalog: 'on'
  pgaudit.log_relation: 'on'

性能与执行审计

扩展默认启用说明
pg_stat_statementsSQL统计信息
auto_explain慢查询执行计划
pg_wait_sampling配置可用等待事件采样

默认配置

pg_libs: 'pg_stat_statements, auto_explain'

# auto_explain 配置
auto_explain.log_min_duration: 1s    # 记录>1s的查询计划
auto_explain.log_analyze: 'on'
auto_explain.log_verbose: 'on'
auto_explain.log_timing: 'on'

# pg_stat_statements 配置
pg_stat_statements.max: 10000
pg_stat_statements.track: all

日志集中管理

默认配置

  • PostgreSQL 日志:/pg/log/postgres/
  • Patroni 日志:/pg/log/patroni/
  • PgBouncer 日志:/pg/log/pgbouncer/
  • pgBackRest 日志:/pg/log/pgbackrest/

可用配置

通过 Vector 将日志发送到 VictoriaLogs 集中存储:

# 日志自动收集到 VictoriaLogs
vlogs_enabled: true
vlogs_port: 9428
vlogs_options: >-
  -retentionPeriod=15d
  -retention.maxDiskSpaceUsageBytes=50GiB

网络安全

等保要求:应在网络边界部署访问控制设备,对进出网络的数据流实现访问控制。

SOC 2:CC6.1 - 边界保护和网络安全。

防火墙配置

配置项默认值说明
node_firewall_modezone防火墙模式
node_firewall_intranetRFC1918网段内网CIDR
node_firewall_public_port[22,80,443,5432]公网开放端口

默认配置

node_firewall_mode: zone             # 启用区域防火墙
node_firewall_intranet:              # 定义内网地址
  - 10.0.0.0/8
  - 192.168.0.0/16
  - 172.16.0.0/12
node_firewall_public_port:           # 公网开放端口
  - 22    # SSH
  - 80    # HTTP
  - 443   # HTTPS
  - 5432  # PostgreSQL(谨慎开放)

防火墙规则:

  • 内网地址自动加入 trusted 区域
  • 仅指定端口对外开放
  • 支持 firewalld(RHEL系)和 ufw(Debian系)

可用配置

  • node_firewall_mode: off - 禁用防火墙(不推荐)
  • node_firewall_mode: none - 不修改现有配置
  • 移除5432端口,仅允许内网访问数据库

服务访问控制

配置项默认值说明
pg_listen0.0.0.0PostgreSQL监听地址
patroni_allowlistinfra + clusterPatroni API白名单

默认配置

Patroni REST API 仅允许来自以下地址的访问:

# 自动计算的白名单
pg_allow_list = [admin_ip] + pg_cluster_members + groups["infra"]

可用配置

限制 PostgreSQL 只监听特定网卡:

pg_listen: '${ip}'  # 仅监听主机IP,不监听0.0.0.0

SELinux

配置项默认值说明
node_selinux_modepermissiveSELinux模式

默认配置:SELinux 设为 permissive 模式(记录但不阻止)

可用配置

node_selinux_mode: enforcing  # 强制模式(需要额外配置策略)

可用性与恢复

等保要求:应提供数据备份与恢复功能;应提供自动故障恢复功能。

SOC 2:CC9.1 - 业务连续性;A1.2 - 数据备份和恢复。

高可用架构

配置项默认值说明
patroni_enabledtrue启用Patroni HA
pg_rto30恢复时间目标(秒)
pg_rpo1048576恢复点目标(1MB)

默认配置

  • Patroni 自动故障检测与切换(RTO < 30秒)
  • 异步复制,最大数据丢失 1MB(RPO)
  • failsafe_mode: true 防止脑裂

可用配置

启用同步复制实现 RPO = 0:

pg_rpo: 0                    # 零数据丢失
pg_conf: crit.yml            # 使用关键业务模板
# crit.yml 自动启用 synchronous_mode: true

启用硬件看门狗:

patroni_watchdog_mode: automatic  # 或 required

备份恢复

配置项默认值说明
pgbackrest_enabledtrue启用pgBackRest
pgbackrest_methodlocal备份存储方式
retention_full2保留完整备份数量

默认配置

pgbackrest_enabled: true
pgbackrest_method: local
pgbackrest_repo:
  local:
    path: /pg/backup
    retention_full_type: count
    retention_full: 2            # 保留2个完整备份

可用配置

异地备份到对象存储:

pgbackrest_method: minio
pgbackrest_repo:
  minio:
    type: s3
    s3_endpoint: sss.pigsty
    s3_bucket: pgsql
    cipher_type: aes-256-cbc     # 加密备份
    retention_full_type: time
    retention_full: 14           # 保留14天
    block: y                     # 块级增量备份
    bundle: y                    # 小文件合并

定时备份策略:

node_crontab:
  - '00 01 * * * postgres /pg/bin/pg-backup full'   # 每日1点全量备份
  - '00 */4 * * * postgres /pg/bin/pg-backup diff'  # 每4小时差异备份

入侵防范

等保要求:应遵循最小安装的原则,仅安装需要的组件和应用程序;应能够检测到对重要节点进行入侵的行为,并在发生严重入侵事件时提供报警。

SOC 2:CC6.8 - 恶意软件防护;CC7.1 - 入侵检测。

最小化安装

默认配置

  • 仅安装必要的 PostgreSQL 组件和扩展
  • 通过 pg_packagespg_extensions 精确控制安装内容
  • 生产系统不安装开发工具和调试符号
pg_packages: [ pgsql-main, pgsql-common ]  # 最小化安装
pg_extensions: []                          # 按需添加扩展

安全扩展

Pigsty 提供以下 安全相关扩展,可按需安装启用:

扩展/包版本描述
passwordcheck_cracklib3.1.0使用 cracklib 加固 PG 用户密码
supautils3.0.2用于在云环境中确保数据库集群的安全
pgsodium3.1.9表数据加密存储 TDE
supabase_vault / pg_vault0.3.1在 Vault 中存储加密凭证的扩展 (supabase)
pg_session_jwt0.4.0使用JWT进行会话认证
anon2.5.1数据匿名化处理工具
pgsmcrypto0.1.1为PostgreSQL提供商密算法支持:SM2,SM3,SM4
pg_enigma0.5.0PostgreSQL 加密数据类型
pgaudit18.0提供审计功能
pgauditlogtofile1.7.6pgAudit 子扩展,将审计日志写入单独的文件中
pg_auditor0.2审计数据变更并提供闪回能力
logerrors2.1.5用于收集日志文件中消息统计信息的函数
pg_auth_mon3.0监控每个用户的连接尝试
pg_jobmon1.4.1记录和监控函数
credcheck4.2明文凭证检查器
pgcryptokey0.85PG密钥管理
login_hook1.7在用户登陆时执行login_hook.login()函数
set_user4.2.0增加了日志记录的 SET ROLE
pg_snakeoil1.4PostgreSQL动态链接库反病毒功能
pgextwlist1.19PostgreSQL扩展白名单功能
sslutils1.4使用SQL管理SSL证书
noset0.3.0阻止非超级用户使用SET/RESET设置变量
pg_tde1.0Percona加密存储引擎
sepgsql-基于SELinux标签的强制访问控制
auth_delay-在返回认证失败前暂停一会,避免爆破
pgcrypto1.3实用加解密函数
passwordcheck-用于强制拒绝修改弱密码的扩展

安装所有安全扩展包:

pg_extensions: [ pg18-sec ]  # 安装安全类扩展组

告警与监控

默认配置

  • VictoriaMetrics + Alertmanager 提供监控告警
  • 预置 PostgreSQL 告警规则
  • Grafana 可视化仪表板

关键安全相关告警:

  • 认证失败次数过多
  • 复制延迟过大
  • 备份失败
  • 磁盘空间不足
  • 连接数耗尽