This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

模块:PGSQL

如何使用 Pigsty 部署并管理世界上最先进的开源关系型数据库 —— PostgreSQL,按需定制,开箱即用!

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

而 Pigsty 帮它进入全盛状态:开箱即用、可靠、可观测、可维护、可伸缩! 配置 | 管理 | 剧本 | 监控 | 参数


概览

了解关于 PostgreSQL 的重要主题与概念。


配置

描述 你想要的 PostgreSQL 集群

  • 身份参数:定义PostgreSQL集群的身份参数
  • 读写主库:创建由单一主库构成的单实例“集群“
  • 只读从库:创建一主一从的两节点基础高可用集群
  • 离线从库:创建专用于OLAP/ETL/交互式查询的特殊只读实例
  • 同步备库:启用同步提交,以确保没有数据丢失
  • 法定人数:使用法定人数同步提交以获得更高的一致性级别
  • 备份集群:克隆现有集群,并保持同步(异地灾备集群)
  • 延迟集群:克隆现有集群,并延迟重放,用于紧急数据恢复
  • Citus集群:定义并创建 Citus 水平分布式数据库集群
  • 大版本切换:使用不同的PostgreSQL大版本部署集群

管理

管理 您所创建的 PostgreSQL 集群。


剧本

使用幂等的剧本,将您的描述变为现实。

  • pgsql.yml :初始化PostgreSQL集群或添加新的从库。
  • pgsql-rm.yml :移除PostgreSQL集群,或移除某个实例
  • pgsql-user.yml :在现有的PostgreSQL集群中添加新的业务用户
  • pgsql-db.yml :在现有的PostgreSQL集群中添加新的业务数据库
  • pgsql-monitor.yml :将远程postgres实例纳入监控中
  • pgsql-migration.yml :为现有的PostgreSQL集群生成迁移手册和脚本
样例:安装 PGSQL 模块

asciicast

样例:移除 PGSQL 模块

asciicast


监控

在 Grafana 仪表盘 中查阅 PostgreSQL 的详情状态。

在 Pigsty 中共有 26 个与 PostgreSQL 相关的监控面板:

总览 集群 实例 数据库
PGSQL Overview PGSQL Cluster PGSQL Instance PGSQL Database
PGSQL Alert PGRDS Cluster PGRDS Instance PGCAT Database
PGSQL Shard PGSQL Activity PGCAT Instance PGSQL Tables
PGSQL Replication PGSQL Persist PGSQL Table
PGSQL Service PGSQL Proxy PGCAT Table
PGSQL Databases PGSQL Pgbouncer PGSQL Query
PGSQL Patroni PGSQL Session PGCAT Query
PGSQL PITR PGSQL Xacts PGCAT Locks
PGSQL Exporter PGCAT Schema

参数

PGSQL 模块的配置参数列表

  • PG_ID : 计算和校验 PostgreSQL 实例身份
  • PG_BUSINESS : PostgreSQL业务对象定义
  • PG_INSTALL : 安装 PostgreSQL 内核,支持软件包与扩展插件
  • PG_BOOTSTRAP : 使用 Patroni 初始化高可用 PostgreSQL 集群
  • PG_PROVISION : 创建 PostgreSQL 用户、数据库和其他数据库内对象
  • PG_BACKUP : 使用 pgbackrest 设置备份仓库
  • PG_SERVICE : 暴露 PostgreSQL 服务,绑定 VIP (可选),以及注册DNS
  • PG_EXPORTER : 为 PostgreSQL 实例添加监控,并注册至基础设施中。
完整参数列表
参数 参数组 类型 级别 说明 中文说明
pg_mode PG_ID enum C pgsql cluster mode: pgsql,citus,gpsql pgsql 集群模式: pgsql,citus,gpsql
pg_cluster PG_ID string C pgsql cluster name, REQUIRED identity parameter pgsql 集群名称, 必选身份参数
pg_seq PG_ID int I pgsql instance seq number, REQUIRED identity parameter pgsql 实例号, 必选身份参数
pg_role PG_ID enum I pgsql role, REQUIRED, could be primary,replica,offline pgsql 实例角色, 必选身份参数, 可为 primary,replica,offline
pg_instances PG_ID dict I define multiple pg instances on node in {port:ins_vars} format 在一个节点上定义多个 pg 实例,使用 {port:ins_vars} 格式
pg_upstream PG_ID ip I repl upstream ip addr for standby cluster or cascade replica 级联从库或备份集群或的复制上游节点IP地址
pg_shard PG_ID string C pgsql shard name, optional identity for sharding clusters pgsql 分片名,对 citus 与 gpsql 等水平分片集群为必选身份参数
pg_group PG_ID int C pgsql shard index number, optional identity for sharding clusters pgsql 分片号,正整数,对 citus 与 gpsql 等水平分片集群为必选身份参数
gp_role PG_ID enum C greenplum role of this cluster, could be master or segment 这个集群的 greenplum 角色,可以是 master 或 segment
pg_exporters PG_ID dict C additional pg_exporters to monitor remote postgres instances 在该节点上设置额外的 pg_exporters 用于监控远程 postgres 实例
pg_offline_query PG_ID bool I set to true to enable offline query on this instance 设置为 true 将此只读实例标记为特殊的离线从库,承载 Offline 服务,允许离线查询
pg_users PG_BUSINESS user[] C postgres business users postgres 业务用户
pg_databases PG_BUSINESS database[] C postgres business databases postgres 业务数据库
pg_services PG_BUSINESS service[] C postgres business services postgres 业务服务
pg_hba_rules PG_BUSINESS hba[] C business hba rules for postgres postgres 的业务 hba 规则
pgb_hba_rules PG_BUSINESS hba[] C business hba rules for pgbouncer pgbouncer 的业务 hba 规则
pg_replication_username PG_BUSINESS username G postgres replication username, replicator by default postgres 复制用户名,默认为 replicator
pg_replication_password PG_BUSINESS password G postgres replication password, DBUser.Replicator by default postgres 复制密码,默认为 DBUser.Replicator
pg_admin_username PG_BUSINESS username G postgres admin username, dbuser_dba by default postgres 管理员用户名,默认为 dbuser_dba
pg_admin_password PG_BUSINESS password G postgres admin password in plain text, DBUser.DBA by default postgres 管理员明文密码,默认为 DBUser.DBA
pg_monitor_username PG_BUSINESS username G postgres monitor username, dbuser_monitor by default postgres 监控用户名,默认为 dbuser_monitor
pg_monitor_password PG_BUSINESS password G postgres monitor password, DBUser.Monitor by default postgres 监控密码,默认为 DBUser.Monitor
pg_dbsu_password PG_BUSINESS password G/C dbsu password, empty string means no dbsu password by default dbsu 密码,默认为空字符串意味着不设置 dbsu 密码,最好不要设置。
pg_dbsu PG_INSTALL username C os dbsu name, postgres by default, better not change it 操作系统 dbsu 名称,默认为 postgres,最好不要更改
pg_dbsu_uid PG_INSTALL int C os dbsu uid and gid, 26 for default postgres users and groups 操作系统 dbsu uid 和 gid,对于默认的 postgres 用户和组为 26
pg_dbsu_sudo PG_INSTALL enum C dbsu sudo privilege, none,limit,all,nopass. limit by default dbsu sudo 权限, none,limit,all,nopass,默认为 limit,有限sudo权限
pg_dbsu_home PG_INSTALL path C postgresql home directory, /var/lib/pgsql by default postgresql 主目录,默认为 /var/lib/pgsql
pg_dbsu_ssh_exchange PG_INSTALL bool C exchange postgres dbsu ssh key among same pgsql cluster 在 pgsql 集群之间交换 postgres dbsu ssh 密钥
pg_version PG_INSTALL enum C postgres major version to be installed, 15 by default 要安装的 postgres 主版本,默认为 15
pg_bin_dir PG_INSTALL path C postgres binary dir, /usr/pgsql/bin by default postgres 二进制目录,默认为 /usr/pgsql/bin
pg_log_dir PG_INSTALL path C postgres log dir, /pg/log/postgres by default postgres 日志目录,默认为 /pg/log/postgres
pg_packages PG_INSTALL string[] C pg packages to be installed, ${pg_version} will be replaced 要安装的 pg 包,${pg_version} 将被替换为实际主版本号
pg_extensions PG_INSTALL string[] C pg extensions to be installed, ${pg_version} will be replaced 要安装的 pg 扩展,${pg_version} 将被替换为实际主版本号
pg_safeguard PG_BOOTSTRAP bool G/C/A prevent purging running postgres instance? false by default 防误删保险,禁止清除正在运行的 postgres 实例?默认为 false
pg_clean PG_BOOTSTRAP bool G/C/A purging existing postgres during pgsql init? true by default 在 pgsql 初始化期间清除现有的 postgres?默认为 true
pg_data PG_BOOTSTRAP path C postgres data directory, /pg/data by default postgres 数据目录,默认为 /pg/data
pg_fs_main PG_BOOTSTRAP path C mountpoint/path for postgres main data, /data by default postgres 主数据的挂载点/路径,默认为 /data
pg_fs_bkup PG_BOOTSTRAP path C mountpoint/path for pg backup data, /data/backup by default pg 备份数据的挂载点/路径,默认为 /data/backup
pg_storage_type PG_BOOTSTRAP enum C storage type for pg main data, SSD,HDD, SSD by default pg 主数据的存储类型,SSD、HDD,默认为 SSD,影响自动优化的参数。
pg_dummy_filesize PG_BOOTSTRAP size C size of /pg/dummy, hold 64MB disk space for emergency use /pg/dummy 的大小,默认保留 64MB 磁盘空间用于紧急抢修
pg_listen PG_BOOTSTRAP ip(s) C/I postgres/pgbouncer listen addresses, comma separated list postgres/pgbouncer 的监听地址,用逗号分隔的IP列表,默认为 0.0.0.0
pg_port PG_BOOTSTRAP port C postgres listen port, 5432 by default postgres 监听端口,默认为 5432
pg_localhost PG_BOOTSTRAP path C postgres unix socket dir for localhost connection postgres 的 Unix 套接字目录,用于本地连接
pg_namespace PG_BOOTSTRAP path C top level key namespace in etcd, used by patroni & vip 在 etcd 中的顶级键命名空间,被 patroni & vip 用于高可用管理
patroni_enabled PG_BOOTSTRAP bool C if disabled, no postgres cluster will be created during init 如果禁用,初始化期间不会创建 postgres 集群
patroni_mode PG_BOOTSTRAP enum C patroni working mode: default,pause,remove patroni 工作模式:default,pause,remove
patroni_port PG_BOOTSTRAP port C patroni listen port, 8008 by default patroni 监听端口,默认为 8008
patroni_log_dir PG_BOOTSTRAP path C patroni log dir, /pg/log/patroni by default patroni 日志目录,默认为 /pg/log/patroni
patroni_ssl_enabled PG_BOOTSTRAP bool G secure patroni RestAPI communications with SSL? 使用 SSL 保护 patroni RestAPI 通信?
patroni_watchdog_mode PG_BOOTSTRAP enum C patroni watchdog mode: automatic,required,off. off by default patroni 看门狗模式:automatic,required,off,默认为 off
patroni_username PG_BOOTSTRAP username C patroni restapi username, postgres by default patroni restapi 用户名,默认为 postgres
patroni_password PG_BOOTSTRAP password C patroni restapi password, Patroni.API by default patroni restapi 密码,默认为 Patroni.API
pg_primary_db PG_BOOTSTRAP string C 指定集群中首要使用的数据库名,Citus等模式会用到,默认为 postgres
pg_parameters PG_BOOTSTRAP dict C 覆盖 postgresql.auto.conf 中的 PostgreSQL 参数
pg_conf PG_BOOTSTRAP enum C config template: oltp,olap,crit,tiny. oltp.yml by default 配置模板:oltp,olap,crit,tiny,默认为 oltp.yml
pg_max_conn PG_BOOTSTRAP int C postgres max connections, auto will use recommended value postgres 最大连接数,auto 将使用推荐值
pg_shared_buffer_ratio PG_BOOTSTRAP float C postgres shared buffer memory ratio, 0.25 by default, 0.1~0.4 postgres 共享缓冲区内存比率,默认为 0.25,范围 0.1~0.4
pg_rto PG_BOOTSTRAP int C recovery time objective in seconds, 30s by default 恢复时间目标(秒),默认为 30s
pg_rpo PG_BOOTSTRAP int C recovery point objective in bytes, 1MiB at most by default 恢复点目标(字节),默认为 1MiB
pg_libs PG_BOOTSTRAP string C preloaded libraries, timescaledb,pg_stat_statements,auto_explain by default 预加载的库,默认为 timescaledb,pg_stat_statements,auto_explain
pg_delay PG_BOOTSTRAP interval I replication apply delay for standby cluster leader 备份集群主库的WAL重放应用延迟,用于制备延迟从库
pg_checksum PG_BOOTSTRAP bool C enable data checksum for postgres cluster? 为 postgres 集群启用数据校验和?
pg_pwd_enc PG_BOOTSTRAP enum C passwords encryption algorithm: md5,scram-sha-256 密码加密算法:md5,scram-sha-256
pg_encoding PG_BOOTSTRAP enum C database cluster encoding, UTF8 by default 数据库集群编码,默认为 UTF8
pg_locale PG_BOOTSTRAP enum C database cluster local, C by default 数据库集群本地化设置,默认为 C
pg_lc_collate PG_BOOTSTRAP enum C database cluster collate, C by default 数据库集群排序,默认为 C
pg_lc_ctype PG_BOOTSTRAP enum C database character type, en_US.UTF8 by default 数据库字符类型,默认为 en_US.UTF8
pgbouncer_enabled PG_BOOTSTRAP bool C if disabled, pgbouncer will not be launched on pgsql host 如果禁用,则不会配置 pgbouncer 连接池
pgbouncer_port PG_BOOTSTRAP port C pgbouncer listen port, 6432 by default pgbouncer 监听端口,默认为 6432
pgbouncer_log_dir PG_BOOTSTRAP path C pgbouncer log dir, /pg/log/pgbouncer by default pgbouncer 日志目录,默认为 /pg/log/pgbouncer
pgbouncer_auth_query PG_BOOTSTRAP bool C query postgres to retrieve unlisted business users? 使用 AuthQuery 来从 postgres 获取未列出的业务用户?
pgbouncer_poolmode PG_BOOTSTRAP enum C pooling mode: transaction,session,statement, transaction by default 池化模式:transaction,session,statement,默认为 transaction
pgbouncer_sslmode PG_BOOTSTRAP enum C pgbouncer client ssl mode, disable by default pgbouncer 客户端 SSL 模式,默认为禁用
pg_provision PG_PROVISION bool C provision postgres cluster after bootstrap 在引导后置备 postgres 集群内部的业务对象?
pg_init PG_PROVISION string G/C provision init script for cluster template, pg-init by default 为集群模板提供初始化脚本,默认为 pg-init
pg_default_roles PG_PROVISION role[] G/C default roles and users in postgres cluster postgres 集群中的默认预定义角色和系统用户
pg_default_privileges PG_PROVISION string[] G/C default privileges when created by admin user 由管理员用户创建数据库内对象时的默认权限
pg_default_schemas PG_PROVISION string[] G/C default schemas to be created 要创建的默认模式列表
pg_default_extensions PG_PROVISION extension[] G/C default extensions to be created 要创建的默认扩展列表
pg_reload PG_PROVISION bool A reload postgres after hba changes 更改HBA后,是否立即重载 postgres 配置
pg_default_hba_rules PG_PROVISION hba[] G/C postgres default host-based authentication rules postgres 基于主机的认证规则,全局PG默认HBA
pgb_default_hba_rules PG_PROVISION hba[] G/C pgbouncer default host-based authentication rules pgbouncer 默认的基于主机的认证规则,全局PGB默认HBA
pgbackrest_enabled PG_BACKUP bool C enable pgbackrest on pgsql host? 在 pgsql 主机上启用 pgbackrest?
pgbackrest_clean PG_BACKUP bool C remove pg backup data during init? 在初始化时删除以前的 pg 备份数据?
pgbackrest_log_dir PG_BACKUP path C pgbackrest log dir, /pg/log/pgbackrest by default pgbackrest 日志目录,默认为 /pg/log/pgbackrest
pgbackrest_method PG_BACKUP enum C pgbackrest repo method: local,minio,etc… pgbackrest 使用的仓库:local,minio,等…
pgbackrest_repo PG_BACKUP dict G/C pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository pgbackrest 仓库定义:https://pgbackrest.org/configuration.html#section-repository
pg_weight PG_SERVICE int I relative load balance weight in service, 100 by default, 0-255 在服务中的相对负载均衡权重,默认为 100,范围 0-255
pg_service_provider PG_SERVICE enum G/C dedicate haproxy node group name, or empty string for local nodes by default 专用的 haproxy 节点组名称,或默认空字符,使用本地节点上的 haproxy
pg_default_service_dest PG_SERVICE enum G/C default service destination if svc.dest=‘default’ 如果 svc.dest=‘default’,默认服务指向哪里?postgres 或 pgbouncer,默认指向 pgbouncer
pg_default_services PG_SERVICE service[] G/C postgres default service definitions postgres 默认服务定义列表,全局共用。
pg_vip_enabled PG_SERVICE bool C enable a l2 vip for pgsql primary? false by default 是否为 pgsql 主节点启用 L2 VIP?默认不启用
pg_vip_address PG_SERVICE cidr4 C vip address in <ipv4>/<mask> format, require if vip is enabled vip 地址的格式为 /,启用 vip 时为必选参数
pg_vip_interface PG_SERVICE string C/I vip network interface to listen, eth0 by default 监听的 vip 网络接口,默认为 eth0
pg_dns_suffix PG_SERVICE string C pgsql dns suffix, ’’ by default pgsql dns 后缀,默认为空
pg_dns_target PG_SERVICE enum C auto, primary, vip, none, or ad hoc ip PG DNS 解析到哪里?auto、primary、vip、none 或者特定的 IP 地址
pg_exporter_enabled PG_EXPORTER bool C enable pg_exporter on pgsql hosts? 在 pgsql 主机上启用 pg_exporter 吗?
pg_exporter_config PG_EXPORTER string C pg_exporter configuration file name pg_exporter 配置文件/模板名称
pg_exporter_cache_ttls PG_EXPORTER string C pg_exporter collector ttl stage in seconds, ‘1,10,60,300’ by default pg_exporter 收集器阶梯TTL配置,默认为4个由逗号分隔的秒数:‘1,10,60,300’
pg_exporter_port PG_EXPORTER port C pg_exporter listen port, 9630 by default pg_exporter 监听端口,默认为 9630
pg_exporter_params PG_EXPORTER string C extra url parameters for pg_exporter dsn pg_exporter dsn 中传入的额外 URL 参数
pg_exporter_url PG_EXPORTER pgurl C overwrite auto-generate pg dsn if specified 如果指定,则覆盖自动生成的 postgres DSN 连接串
pg_exporter_auto_discovery PG_EXPORTER bool C enable auto database discovery? enabled by default 监控是否启用自动数据库发现?默认启用
pg_exporter_exclude_database PG_EXPORTER string C csv of database that WILL NOT be monitored during auto-discovery 启用自动发现时,排除在外的数据库名称列表,用逗号分隔
pg_exporter_include_database PG_EXPORTER string C csv of database that WILL BE monitored during auto-discovery 启用自动发现时,只监控这个列表中的数据库,名称用逗号分隔
pg_exporter_connect_timeout PG_EXPORTER int C pg_exporter connect timeout in ms, 200 by default pg_exporter 连接超时,单位毫秒,默认为 200
pg_exporter_options PG_EXPORTER arg C overwrite extra options for pg_exporter pg_exporter 的额外命令行参数选项
pgbouncer_exporter_enabled PG_EXPORTER bool C enable pgbouncer_exporter on pgsql hosts? 在 pgsql 主机上启用 pgbouncer_exporter 吗?
pgbouncer_exporter_port PG_EXPORTER port C pgbouncer_exporter listen port, 9631 by default pgbouncer_exporter 监听端口,默认为 9631
pgbouncer_exporter_url PG_EXPORTER pgurl C overwrite auto-generate pgbouncer dsn if specified 如果指定,则覆盖自动生成的 pgbouncer dsn 连接串
pgbouncer_exporter_options PG_EXPORTER arg C overwrite extra options for pgbouncer_exporter pgbouncer_exporter 的额外命令行参数选项

教程

一些使用/管理 Pigsty中 PostgreSQL 数据库的教程。

  • 克隆一套现有的 PostgreSQL 集群
  • 创建一套现有 PostgreSQL 集群的在线备份集群。
  • 创建一套现有 PostgreSQL 集群的延迟备份集群
  • 监控一个已有的 postgres 实例?
  • 使用逻辑复制从外部 PostgreSQL 迁移至 Pigsty 托管的 PostgreSQL 实例?
  • 使用 MinIO 作为集中的 pgBackRest 备份仓库。
  • 使用专门的 etcd 集群作为 PostgreSQL / Patroni 的 DCS ?
  • 使用专用的 haproxy 负载均衡器集群对外暴露暴露 PostgreSQL 服务。
  • 使用 pg-meta CMDB 替代 pigsty.yml 作为配置清单源。
  • 使用 PostgreSQL 作为 Grafana 的后端存储数据库?
  • 使用 PostgreSQL 作为 Prometheus 后端存储数据库?

1 - 核心概念

介绍 PostgreSQL 集群的中涉及到的重要概念

PGSQL 模块总览:关键概念与架构细节

PGSQL模块在生产环境中以集群的形式组织,这些集群是由一组由主-备关联的数据库实例组成的逻辑实体。 每个数据库集群都是一个自治的业务服务单元,由至少一个 数据库(主库)实例 组成。


实体概念图

让我们从ER图开始。在Pigsty的PGSQL模块中,有四种核心实体:

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

pigsty-er.jpg

命名约定

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

身份参数

Pigsty使用身份参数来识别实体:PG_ID

除了节点IP地址,pg_clusterpg_rolepg_seq三个参数是定义postgres集群所必需的最小参数集。 以沙箱环境测试集群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

集群的三个成员如下所示:

集群 序号 角色 主机 / IP 实例 服务 节点名
pg-test 1 primary 10.10.10.11 pg-test-1 pg-test-primary pg-test-1
pg-test 2 replica 10.10.10.12 pg-test-2 pg-test-replica pg-test-2
pg-test 3 replica 10.10.10.13 pg-test-3 pg-test-replica pg-test-3

这里包含了:

  • 一个集群:该集群命名为pg-test
  • 两种角色:primaryreplica
  • 三个实例:集群由三个实例组成:pg-test-1pg-test-2pg-test-3
  • 三个节点:集群部署在三个节点上:10.10.10.1110.10.10.1210.10.10.13
  • 四个服务:

在监控系统(Prometheus/Grafana/Loki)中,相应的指标将会使用这些身份参数进行标记:

pg_up{cls="pg-meta", ins="pg-meta-1", ip="10.10.10.10", job="pgsql"}
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"}

组件概览

以下是 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

pigsty-arch.jpg


高可用

主库故障恢复时间目标 (RTO) ≈ 30s,数据恢复点目标 (RPO) < 1MB,从库故障 RTO ≈ 0 (重置当前连接)

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

pigsty-ha.png

当主库故障时,将触发新一轮领导者竞选,集群中最为健康的从库将胜出,并被提升为新的主库。读写流量将立即路由至新的主库。主库故障影响是:默认情况下写入查询将被阻塞 15 ~ 40s,直到选出新的领导者来。

当从库故障时,只读流量将路由至其他从库,如果所有从库都故障,只读流量才会最终由主库承载。从库故障的影响非常小:查询闪断:该从库上正在运行查询将由于连接重置而中止。

故障检测由 patronietcd 完成,集群领导者将持有一个租约,如果它因为故障而没有及时续租(10s),租约将会被释放,新一轮集群选举会被触发。

您可以使用 pg_rto 参数调整集群的 TTL,默认 RTO 配置为 30s,增大它将导致更长的故障转移等待时间,而减少它将增加误报故障转移率(例如,网络抖动)。

Pigsty 默认使用可用性优先模式,这意味着当主库故障时,它将尽快进行故障转移,尚未复制到从库的数据可能会丢失(常规万兆网络下,复制延迟在通常在几KB到100KB)。

最大潜在数据丢失由 pg_rpo 控制,默认为 1MB,减小这个值将会减少故障恢复时的可能数据损失,但也会增加故障时因为从库不够健康(落后太久)而拒绝自动切换的概率。

RTO 与 RPO 是高可用集群设计时需要仔细权衡的两个参数,您应当根据您的硬件水平,网络质量,业务需求来合理调整它们。

2 - 系统架构

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

PGSQL 模块总览:关键概念与架构细节


组件概览

以下是 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

pigsty-arch.jpg


高可用

主库故障恢复时间目标 (RTO) ≈ 30s,数据恢复点目标 (RPO) < 1MB,从库故障 RTO ≈ 0 (重置当前连接)

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

pigsty-ha.png

当主库故障时,将触发新一轮领导者竞选,集群中最为健康的从库将胜出,并被提升为新的主库。读写流量将立即路由至新的主库。主库故障影响是:默认情况下写入查询将被阻塞 15 ~ 40s,直到选出新的领导者来。

当从库故障时,只读流量将路由至其他从库,如果所有从库都故障,只读流量才会最终由主库承载。从库故障的影响非常小:查询闪断:该从库上正在运行查询将由于连接重置而中止。

故障检测由 patronietcd 完成,集群领导者将持有一个租约,如果它因为故障而没有及时续租(10s),租约将会被释放,新一轮集群选举会被触发。

您可以使用 pg_rto 参数调整集群的 TTL,默认 RTO 配置为 30s,增大它将导致更长的故障转移等待时间,而减少它将增加误报故障转移率(例如,网络抖动)。

Pigsty 默认使用可用性优先模式,这意味着当主库故障时,它将尽快进行故障转移,尚未复制到从库的数据可能会丢失(常规万兆网络下,复制延迟在通常在几KB到100KB)。

最大潜在数据丢失由 pg_rpo 控制,默认为 1MB,减小这个值将会减少故障恢复时的可能数据损失,但也会增加故障时因为从库不够健康(落后太久)而拒绝自动切换的概率。

RTO 与 RPO 是高可用集群设计时需要仔细权衡的两个参数,您应当根据您的硬件水平,网络质量,业务需求来合理调整它们。


时间点恢复

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

Pigsty 的 PostgreSQL 集群带有自动配置的时间点恢复(PITR)方案,基于 pgBackRest 与可选的 MinIO

高可用可以解决硬件故障,软件缺陷与人为失误导致的数据删除/覆盖写入却无能为力:因为变更操作会立即同步至从库应用。时间点恢复(Point in Time Recovery, PITR)可以解决这个问题。此外当您只有单个实例时,PITR也可以代替高可用,为最坏的情况兜底。

如果想将集群恢复至某个备份,用户需要提前定期做好基础备份,如果想将集群恢复至任意时间点,用户还需要从备份时刻迄今的 WAL归档。这两项工作 Pigsty 为您自动进行了兜底配置。 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 天的完整备份

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

3 - 用户/角色

用户/角色指的是使用 SQL 命令 CREATE USER/ROLE 创建的,数据库集簇内的逻辑对象。

在这里的上下文中,用户指的是使用 SQL 命令 CREATE USER/ROLE 创建的,数据库集簇内的逻辑对象。

在PostgreSQL中,用户直接隶属于数据库集簇而非某个具体的数据库。因此在创建业务数据库和业务用户时,应当遵循"先用户,后数据库"的原则。


定义用户

Pigsty通过两个配置参数定义数据库集群中的角色与用户:

  • pg_default_roles:定义全局统一使用的角色和用户
  • pg_users:在数据库集群层面定义业务用户和角色

前者用于定义了整套环境中共用的角色与用户,后者定义单个集群中特有的业务角色与用户。二者形式相同,均为用户定义对象的数组。

你可以定义多个用户/角色,它们会按照先全局,后集群,最后按数组内排序的顺序依次创建,所以后面的用户可以属于前面定义的角色。

下面是 Pigsty 演示环境中默认集群 pg-meta 中的业务用户定义:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_users:
      - {name: dbuser_meta     ,password: DBUser.Meta     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: pigsty admin user }
      - {name: dbuser_view     ,password: DBUser.Viewer   ,pgbouncer: true ,roles: [dbrole_readonly] ,comment: read-only viewer for meta database }
      - {name: dbuser_grafana  ,password: DBUser.Grafana  ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for grafana database    }
      - {name: dbuser_bytebase ,password: DBUser.Bytebase ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for bytebase database   }
      - {name: dbuser_kong     ,password: DBUser.Kong     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for kong api gateway    }
      - {name: dbuser_gitea    ,password: DBUser.Gitea    ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for gitea service       }
      - {name: dbuser_wiki     ,password: DBUser.Wiki     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for wiki.js service     }
      - {name: dbuser_noco     ,password: DBUser.Noco     ,pgbouncer: true ,roles: [dbrole_admin]    ,comment: admin user for nocodb service      }

每个用户/角色定义都是一个 object,可能包括以下字段,以 dbuser_meta 用户为例:

- name: dbuser_meta               # 必需,`name` 是用户定义的唯一必选字段
  password: DBUser.Meta           # 可选,密码,可以是 scram-sha-256 哈希字符串或明文
  login: true                     # 可选,默认情况下可以登录
  superuser: false                # 可选,默认为 false,是超级用户吗?
  createdb: false                 # 可选,默认为 false,可以创建数据库吗?
  createrole: false               # 可选,默认为 false,可以创建角色吗?
  inherit: true                   # 可选,默认情况下,此角色可以使用继承的权限吗?
  replication: false              # 可选,默认为 false,此角色可以进行复制吗?
  bypassrls: false                # 可选,默认为 false,此角色可以绕过行级安全吗?
  pgbouncer: true                 # 可选,默认为 false,将此用户添加到 pgbouncer 用户列表吗?(使用连接池的生产用户应该显式定义为 true)
  connlimit: -1                   # 可选,用户连接限制,默认 -1 禁用限制
  expire_in: 3650                 # 可选,此角色过期时间:从创建时 + n天计算(优先级比 expire_at 更高)
  expire_at: '2030-12-31'         # 可选,此角色过期的时间点,使用 YYYY-MM-DD 格式的字符串指定一个特定日期(优先级没 expire_in 高)
  comment: pigsty admin user      # 可选,此用户/角色的说明与备注字符串
  roles: [dbrole_admin]           # 可选,默认角色为:dbrole_{admin,readonly,readwrite,offline}
  parameters: {}                  # 可选,使用 `ALTER ROLE SET` 针对这个角色,配置角色级的数据库参数
  pool_mode: transaction          # 可选,默认为 transaction 的 pgbouncer 池模式,用户级别
  pool_connlimit: -1              # 可选,用户级别的最大数据库连接数,默认 -1 禁用限制
  search_path: public             # 可选,根据 postgresql 文档的键值配置参数(例如:使用 pigsty 作为默认 search_path)
  • 唯一必需的字段是 name,它应该是 PostgreSQL 集群中的一个有效且唯一的用户名。
  • 角色不需要 password,但对于可登录的业务用户,通常是需要指定一个密码的。
  • password 可以是明文或 scram-sha-256 / md5 哈希字符串,请最好不要使用明文密码。
  • 用户/角色按数组顺序逐一创建,因此,请确保角色/分组的定义在成员之前。
  • loginsuperusercreatedbcreateroleinheritreplicationbypassrls 是布尔标志。
  • pgbouncer 默认是禁用的:要将业务用户添加到 pgbouncer 用户列表,您应当显式将其设置为 true

ACL系统

Pigsty 具有一套内置的,开箱即用的访问控制 / ACL 系统,您只需将以下四个默认角色分配给业务用户即可轻松使用:

  • dbrole_readwrite:全局读写访问的角色(主属业务使用的生产账号应当具有数据库读写权限)
  • dbrole_readonly:全局只读访问的角色(如果别的业务想要只读访问,可以使用此角色)
  • dbrole_admin:拥有DDL权限的角色 (业务管理员,需要在应用中建表的场景)
  • dbrole_offline:受限的只读访问角色(只能访问 offline 实例,通常是个人用户)

如果您希望重新设计您自己的 ACL 系统,可以考虑定制以下参数和模板:


创建用户

pg_default_rolespg_users定义的用户和角色,将在集群初始化的 PROVISION 阶段中自动逐一创建。 如果您希望在现有的集群上创建用户,可以使用 bin/pgsql-user 工具。 将新用户/角色定义添加到 all.children.<cls>.pg_users,并使用以下方法创建该数据库:

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

不同于数据库,创建用户的剧本总是幂等的。当目标用户已经存在时,Pigsty会修改目标用户的属性使其符合配置。所以在现有集群上重复运行它通常不会有问题。


修改用户

修改 PostgreSQL 用户的属性的方式与 创建用户 相同。

首先,调整您的用户定义,修改需要调整的属性,然后执行以下命令应用:

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

请注意,修改用户不会删除用户,而是通过 ALTER USER 命令修改用户属性;也不会回收用户的权限与分组,并使用 GRANT 命令授予新的角色。


Pgbouncer用户

默认情况下启用 Pgbouncer,并作为连接池中间件,其用户默认被管理。

Pigsty 默认将 pg_users 中显式带有 pgbouncer: true 标志的所有用户添加到 pgbouncer 用户列表中。

Pgbouncer 连接池中的用户在 /etc/pgbouncer/userlist.txt 中列出:

"postgres" ""
"dbuser_wiki" "SCRAM-SHA-256$4096:+77dyhrPeFDT/TptHs7/7Q==$KeatuohpKIYzHPCt/tqBu85vI11o9mar/by0hHYM2W8=:X9gig4JtjoS8Y/o1vQsIX/gY1Fns8ynTXkbWOjUfbRQ="
"dbuser_view" "SCRAM-SHA-256$4096:DFoZHU/DXsHL8MJ8regdEw==$gx9sUGgpVpdSM4o6A2R9PKAUkAsRPLhLoBDLBUYtKS0=:MujSgKe6rxcIUMv4GnyXJmV0YNbf39uFRZv724+X1FE="
"dbuser_monitor" "SCRAM-SHA-256$4096:fwU97ZMO/KR0ScHO5+UuBg==$CrNsmGrx1DkIGrtrD1Wjexb/aygzqQdirTO1oBZROPY=:L8+dJ+fqlMQh7y4PmVR/gbAOvYWOr+KINjeMZ8LlFww="
"dbuser_meta" "SCRAM-SHA-256$4096:leB2RQPcw1OIiRnPnOMUEg==$eyC+NIMKeoTxshJu314+BmbMFpCcspzI3UFZ1RYfNyU=:fJgXcykVPvOfro2MWNkl5q38oz21nSl1dTtM65uYR1Q="
"dbuser_kong" "SCRAM-SHA-256$4096:bK8sLXIieMwFDz67/0dqXQ==$P/tCRgyKx9MC9LH3ErnKsnlOqgNd/nn2RyvThyiK6e4=:CDM8QZNHBdPf97ztusgnE7olaKDNHBN0WeAbP/nzu5A="
"dbuser_grafana" "SCRAM-SHA-256$4096:HjLdGaGmeIAGdWyn2gDt/Q==$jgoyOB8ugoce+Wqjr0EwFf8NaIEMtiTuQTg1iEJs9BM=:ed4HUFqLyB4YpRr+y25FBT7KnlFDnan6JPVT9imxzA4="
"dbuser_gitea" "SCRAM-SHA-256$4096:l1DBGCc4dtircZ8O8Fbzkw==$tpmGwgLuWPDog8IEKdsaDGtiPAxD16z09slvu+rHE74=:pYuFOSDuWSofpD9OZhG7oWvyAR0PQjJBffgHZLpLHds="
"dbuser_dba" "SCRAM-SHA-256$4096:zH8niABU7xmtblVUo2QFew==$Zj7/pq+ICZx7fDcXikiN7GLqkKFA+X5NsvAX6CMshF0=:pqevR2WpizjRecPIQjMZOm+Ap+x0kgPL2Iv5zHZs0+g="
"dbuser_bytebase" "SCRAM-SHA-256$4096:OMoTM9Zf8QcCCMD0svK5gg==$kMchqbf4iLK1U67pVOfGrERa/fY818AwqfBPhsTShNQ=:6HqWteN+AadrUnrgC0byr5A72noqnPugItQjOLFw0Wk="

而用户级别的连接池参数则是使用另一个单独的文件: /etc/pgbouncer/useropts.txt 进行维护,比如:

dbuser_dba                  = pool_mode=session max_user_connections=16
dbuser_monitor              = pool_mode=session max_user_connections=8

当您创建数据库时,Pgbouncer 的数据库列表定义文件将会被刷新,并通过在线重载配置的方式生效,不会影响现有的连接。

Pgbouncer 使用和 PostgreSQL 同样的 dbsu 运行,默认为 postgres 操作系统用户,您可以使用 pgb 别名,使用 dbsu 访问 pgbouncer 管理功能。

Pigsty 还提供了一个实用函数 pgb-route ,可以将 pgbouncer 数据库流量快速切换至集群中的其他节点,用于零停机迁移:

连接池用户配置文件 userlist.txtuseropts.txt 会在您创建用户时自动刷新,并通过在线重载配置的方式生效,正常不会影响现有的连接。

请注意,pgbouncer_auth_query 参数允许你使用动态查询来完成连接池用户认证,当您懒得管理连接池中的用户时,这是一种折中的方案。

4 - 数据库

数据库指的是使用 SQL 命令 CREATE DATABASE 创建的,数据库集簇内的逻辑对象。

在这里的上下文中,数据库指的是使用 SQL 命令 CREATE DATABASE 创建的,数据库集簇内的逻辑对象。

一组 PostgreSQL 服务器可以同时服务于多个 数据库 (Database)。在 Pigsty 中,你可以在集群配置中定义好所需的数据库。

Pigsty会对默认模板数据库template1进行修改与定制,创建默认模式,安装默认扩展,配置默认权限,新创建的数据库默认会从template1继承这些设置。

默认情况下,所有业务数据库都会被1:1添加到 Pgbouncer 连接池中;pg_exporter 默认会通过 自动发现 机制查找所有业务数据库并进行库内对象监控。


定义数据库

业务数据库定义在数据库集群参数 pg_databases 中,这是一个数据库定义构成的对象数组。 数组内的数据库按照定义顺序依次创建,因此后面定义的数据库可以使用先前定义的数据库作为模板

下面是 Pigsty 演示环境中默认集群 pg-meta 中的数据库定义:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_databases:
      - { name: meta ,baseline: cmdb.sql ,comment: pigsty meta database ,schemas: [pigsty] ,extensions: [{name: postgis, schema: public}, {name: timescaledb}]}
      - { name: grafana  ,owner: dbuser_grafana  ,revokeconn: true ,comment: grafana primary database }
      - { name: bytebase ,owner: dbuser_bytebase ,revokeconn: true ,comment: bytebase primary database }
      - { name: kong     ,owner: dbuser_kong     ,revokeconn: true ,comment: kong the api gateway database }
      - { name: gitea    ,owner: dbuser_gitea    ,revokeconn: true ,comment: gitea meta database }
      - { name: wiki     ,owner: dbuser_wiki     ,revokeconn: true ,comment: wiki meta database }
      - { name: noco     ,owner: dbuser_noco     ,revokeconn: true ,comment: nocodb database }

每个数据库定义都是一个 object,可能包括以下字段,以 meta 数据库为例:

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

唯一必选的字段是 name,它应该是当前 PostgreSQL 集群中有效且唯一的数据库名称,其他参数都有合理的默认值。

  • name:数据库名称,必选项
  • baseline:SQL文件路径(Ansible搜索路径,通常位于files),用于初始化数据库内容。
  • owner:数据库属主,默认为postgres
  • template:数据库创建时使用的模板,默认为template1
  • encoding:数据库默认字符编码,默认为UTF8,默认与实例保持一致。建议不要配置与修改。
  • locale:数据库默认的本地化规则,默认为C,建议不要配置,与实例保持一致。
  • lc_collate:数据库默认的本地化字符串排序规则,默认与实例设置相同,建议不要修改,必须与模板数据库一致。强烈建议不要配置,或配置为C
  • lc_ctype:数据库默认的LOCALE,默认与实例设置相同,建议不要修改或设置,必须与模板数据库一致。建议配置为C或en_US.UTF8
  • allowconn:是否允许连接至数据库,默认为true,不建议修改。
  • revokeconn:是否回收连接至数据库的权限?默认为false。如果为true,则数据库上的PUBLIC CONNECT权限会被回收。只有默认用户(dbsu|monitor|admin|replicator|owner)可以连接。此外,admin|owner 会拥有GRANT OPTION,可以赋予其他用户连接权限。
  • tablespace:数据库关联的表空间,默认为pg_default
  • connlimit:数据库连接数限制,默认为-1,即没有限制。
  • extensions:对象数组 ,每一个对象定义了一个数据库中的扩展,以及其安装的模式
  • parameters:KV对象,每一个KV定义了一个需要针对数据库通过ALTER DATABASE修改的参数。
  • pgbouncer:布尔选项,是否将该数据库加入到Pgbouncer中。所有数据库都会加入至Pgbouncer列表,除非显式指定pgbouncer: false
  • comment:数据库备注信息。
  • pool_auth_user:启用 pgbouncer_auth_query 时,连接到此 pgbouncer 数据库的所有连接都将使用这里指定的用户执行认证查询。你需要使用一个具有访问 pg_shadow 表权限的用户。
  • pool_mode:数据库级别的 pgbouncer 池化模式,默认为 transaction,即事物池化。如果留空,会使用 pgbouncer_poolmode 参数作为默认值。
  • pool_size:数据库级别的 pgbouncer 默认池子大小,默认为 64
  • pool_size_reserve:数据库级别的 pgbouncer 池子保留空间,默认为 32,当默认池子不够用时,最多再申请这么多条突发连接。
  • pool_size_min: 数据库级别的 pgbouncer 池的最小大小,默认为 0
  • pool_max_db_conn: 数据库级别的 pgbouncer 连接池最大数据库连接数,默认为 100

新创建的数据库默认会从 template1 数据库 Fork 出来,这个模版数据库会在 PG_PROVISION 阶段进行定制修改: 配置好扩展,模式以及默认权限,因此新创建的数据库也会继承这些配置,除非您显式使用一个其他的数据库作为模板。

关于数据库的访问权限,请参考 ACL:数据库权限 一节。


创建数据库

pg_databases定义的数据库将在集群初始化时自动创建。 如果您希望在现有集群上创建数据库,可以使用 bin/pgsql-db 包装脚本。 将新的数据库定义添加到 all.children.<cls>.pg_databases 中,并使用以下命令创建该数据库:

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

下面是新建数据库时的一些注意事项:

创建数据库的剧本默认为幂等剧本,不过当您当使用 baseline 脚本时就不一定了:这种情况下,通常不建议在现有数据库上重复执行此操作,除非您确定所提供的 baseline SQL也是幂等的。

我们不建议您手工创建新的数据库,特别当您使用默认的 pgbouncer 连接池时:除非您愿意手工负责维护 Pgbouncer 中的数据库列表并与 PostgreSQL 保持一致。 使用 pgsql-db 工具或 pgsql-db.yml 剧本创建新数据库时,会将此数据库一并添加到 Pgbouncer 数据库 列表中。

如果您的数据库定义有一个非常规 owner(默认为 dbsu postgres),那么请确保在创建该数据库前,属主用户已经存在。 最佳实践永远是在创建数据库之前创建 用户


Pgbouncer数据库

Pigsty 会默认为 PostgreSQL 实例 1:1 配置启用一个 Pgbouncer 连接池,使用 /var/run/postgresql Unix Socket 通信。

连接池可以优化短连接性能,降低并发征用,以避免过高的连接数冲垮数据库,并在数据库迁移时提供额外的灵活处理空间。

Pigsty 默认将 pg_databases 中的所有数据库都添加到 pgbouncer 的数据库列表中。 您可以通过在数据库定义中显式设置 pgbouncer: false 来禁用特定数据库的 pgbouncer 连接池支持。

Pgbouncer数据库列表在 /etc/pgbouncer/database.txt 中定义,数据库定义中关于连接池的参数会体现在这里:

meta                        = host=/var/run/postgresql mode=session
grafana                     = host=/var/run/postgresql mode=transaction
bytebase                    = host=/var/run/postgresql auth_user=dbuser_meta
kong                        = host=/var/run/postgresql pool_size=32 reserve_pool=64
gitea                       = host=/var/run/postgresql min_pool_size=10
wiki                        = host=/var/run/postgresql
noco                        = host=/var/run/postgresql
mongo                       = host=/var/run/postgresql

当您创建数据库时,Pgbouncer 的数据库列表定义文件将会被刷新,并通过在线重载配置的方式生效,正常不会影响现有的连接。

Pgbouncer 使用和 PostgreSQL 同样的 dbsu 运行,默认为 postgres 操作系统用户,您可以使用 pgb 别名,使用 dbsu 访问 pgbouncer 管理功能。

Pigsty 还提供了一个实用函数 pgb-route ,可以将 pgbouncer 数据库流量快速切换至集群中的其他节点,用于零停机迁移:

# route pgbouncer traffic to another cluster member
function pgb-route(){
  local ip=${1-'\/var\/run\/postgresql'}
  sed -ie "s/host=[^[:space:]]\+/host=${ip}/g" /etc/pgbouncer/pgbouncer.ini
  cat /etc/pgbouncer/pgbouncer.ini
}

5 - 服务/接入

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

分离读写操作,正确路由流量,稳定可靠地交付 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默认为每个 PostgreSQL 数据库集群提供四种不同的服务,以下是默认服务及其定义:

服务 端口 描述
primary 5433 生产读写,连接到主库连接池(6432)
replica 5434 生产只读,连接到备库连接池(6432)
default 5436 管理,ETL写入,直接访问主库(5432)
offline 5438 OLAP、ETL、个人用户、交互式查询

以默认的 pg-meta 集群为例,它提供四种默认服务:

psql postgres://dbuser_meta:DBUser.Meta@pg-meta:5433/meta   # pg-meta-primary : 通过主要的 pgbouncer(6432) 进行生产读写
psql postgres://dbuser_meta:DBUser.Meta@pg-meta:5434/meta   # pg-meta-replica : 通过备份的 pgbouncer(6432) 进行生产只读
psql postgres://dbuser_dba:DBUser.DBA@pg-meta:5436/meta     # pg-meta-default : 通过主要的 postgres(5432) 直接连接
psql postgres://dbuser_stats:DBUser.Stats@pg-meta:5438/meta # pg-meta-offline : 通过离线的 postgres(5432) 直接连接

从示例集群架构图上可以看出这四种服务的工作方式:

pigsty-ha.png

注意在这里pg-meta 域名指向了集群的 L2 VIP,进而指向集群主库上的 haproxy 负载均衡器,它负责将流量路由到不同的实例上,详见服务接入


服务实现

在 Pigsty 中,服务使用节点上的 haproxy 来实现,通过主机节点上的不同端口进行区分。

Pigsty 所纳管的每个节点上都默认启用了 Haproxy 以对外暴露服务,而数据库节点也不例外。 集群中的节点尽管从数据库的视角来看有主从之分,但从服务的视角来看,每个节点都是相同的: 这意味着即使您访问的是从库节点,只要使用正确的服务端口,就依然可以使用到主库读写的服务。 这样的设计可以屏蔽复杂度:所以您只要可以访问 PostgreSQL 集群上的任意一个实例,就可以完整的访问到所有服务。

这样的设计类似于 Kubernetes 中的 NodePort 服务,同样在 Pigsty 中,每一个服务都包括以下两个核心要素:

  1. 通过 NodePort 暴露的访问端点(端口号,从哪访问?)
  2. 通过 Selectors 选择的目标实例(实例列表,谁来承载?)

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

所有的服务都通过配置文件进行声明,例如,PostgreSQL 默认服务就是由 pg_default_services 参数所定义的:

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

您也可以在 pg_services 中定义额外的服务,参数 pg_default_servicespg_services 都是由 服务定义 对象组成的数组。


定义服务

Pigsty 允许您定义自己的服务:

  • pg_default_services:所有 PostgreSQL 集群统一对外暴露的服务,默认有四个。
  • pg_services:额外的 PostgreSQL 服务,可以视需求在全局或集群级别定义。
  • haproxy_servies:直接定制 HAProxy 服务内容,可以用于其他组件的接入

对于 PostgreSQL 集群来说,通常只需要关注前两者即可。 每一条服务定义都会在所有相关 HAProxy 实例的配置目录下生成一个新的配置文件:/etc/haproxy/<svcname>.cfg 下面是一个自定义的服务样例 standby:当您想要对外提供没有复制延迟的只读服务时,就可以在 pg_services 新增这条记录:

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

而上面的服务定义,在样例的三节点 pg-test 上将会被转换为 haproxy 配置文件 /etc/haproxy/pg-test-standby.conf

#---------------------------------------------------------------------
# service: pg-test-standby @ 10.10.10.11:5435
#---------------------------------------------------------------------
# service instances 10.10.10.11, 10.10.10.13, 10.10.10.12
# service backups   10.10.10.11
listen pg-test-standby
    bind *:5435            # <--- 绑定了所有IP地址上的 5435 端口
    mode tcp               # <--- 负载均衡器工作在 TCP 协议上
    maxconn 5000           # <--- 最大连接数为 5000,可按需调大
    balance roundrobin     # <--- 负载均衡算法为 rr 轮询,还可以使用 leastconn 
    option httpchk         # <--- 启用 HTTP 健康检查
    option http-keep-alive # <--- 保持HTTP连接
    http-check send meth OPTIONS uri /sync   # <---- 这里使用 /sync ,Patroni 健康检查 API ,只有同步备库和主库才会返回 200 健康状态码。 
    http-check expect status 200             # <---- 健康检查返回代码 200 代表正常
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers: # pg-test 集群全部三个实例都被 selector: "[]" 给圈中了,因为没有任何的筛选条件,所以都会作为 pg-test-replica 服务的后端服务器。但是因为还有 /sync 健康检查,所以只有主库和同步备库才能真正承载请求。
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100 backup  # <----- 唯独主库满足条件 pg_role == `primary`, 被 backup selector 选中。
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100         #        因此作为服务的兜底实例:平时不承载请求,其他从库全部宕机后,才会承载只读请求,从而最大避免了读写服务受到只读服务的影响
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100         #        

在这里,pg-test 集群全部三个实例都被 selector: "[]" 给圈中了,渲染进入 pg-test-replica 服务的后端服务器列表中。但是因为还有 /sync 健康检查,Patroni Rest API只有在主库和同步备库上才会返回代表健康的 HTTP 200 状态码,因此只有主库和同步备库才能真正承载请求。 此外,主库因为满足条件 pg_role == primary, 被 backup selector 选中,被标记为了备份服务器,只有当没有其他实例(也就是同步备库)可以满足需求时,才会顶上。


Primary服务

Primary服务可能是生产环境中最关键的服务,它在 5433 端口提供对数据库集群的读写能力,服务定义如下:

- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }
  • 选择器参数 selector: "[]" 意味着所有集群成员都将被包括在Primary服务中
  • 但只有主库能够通过健康检查(check: /primary),实际承载Primary服务的流量。
  • 目的地参数 dest: default 意味着Primary服务的目的地受到 pg_default_service_dest 参数的影响
  • dest 默认值 default 会被替换为 pg_default_service_dest 的值,默认为 pgbouncer
  • 默认情况下 Primary 服务的目的地默认是主库上的连接池,也就是由 pgbouncer_port 指定的端口,默认为 6432

如果 pg_default_service_dest 的值为 postgres,那么 primary 服务的目的地就会绕过连接池,直接使用 PostgreSQL 数据库的端口(pg_port,默认值 5432),对于一些不希望使用连接池的场景,这个参数非常实用。

示例:pg-test-primary 的 haproxy 配置
listen pg-test-primary
    bind *:5433         # <--- primary 服务默认使用 5433 端口
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /primary # <--- primary 服务默认使用 Patroni RestAPI /primary 健康检查
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

Patroni 的高可用机制确保任何时候最多只会有一个实例的 /primary 健康检查为真,因此Primary服务将始终将流量路由到主实例。

使用 Primary 服务而不是直连数据库的一个好处是,如果集群因为某种情况出现了双主(比如在没有watchdog的情况下kill -9杀死主库 Patroni),Haproxy在这种情况下仍然可以避免脑裂,因为它只会在 Patroni 存活且返回主库状态时才会分发流量。


Replica服务

Replica服务在生产环境中的重要性仅次于Primary服务,它在 5434 端口提供对数据库集群的只读能力,服务定义如下:

- { name: replica ,port: 5434 ,dest: default  ,check: /read-only ,selector: "[]" , backup: "[? pg_role == `primary` || pg_role == `offline` ]" }
  • 选择器参数 selector: "[]" 意味着所有集群成员都将被包括在Replica服务中
  • 所有实例都能够通过健康检查(check: /read-only),承载Replica服务的流量。
  • 备份选择器:[? pg_role == 'primary' || pg_role == 'offline' ] 将主库和离线从库标注为备份服务器。
  • 只有当所有普通从库都宕机后,Replica服务才会由主库或离线从库来承载。
  • 目的地参数 dest: default 意味着Replica服务的目的地也受到 pg_default_service_dest 参数的影响
  • dest 默认值 default 会被替换为 pg_default_service_dest 的值,默认为 pgbouncer,这一点和 Primary服务 相同
  • 默认情况下 Replica 服务的目的地默认是从库上的连接池,也就是由 pgbouncer_port 指定的端口,默认为 6432
示例:pg-test-replica 的 haproxy 配置
listen pg-test-replica
    bind *:5434
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /read-only
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:6432 check port 8008 weight 100 backup
    server pg-test-3 10.10.10.13:6432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:6432 check port 8008 weight 100

Replica服务非常灵活:如果有存活的专用 Replica 实例,那么它会优先使用这些实例来承载只读请求,只有当从库实例全部宕机后,才会由主库来兜底只读请求。对于常见的一主一从双节点集群就是:只要从库活着就用从库,从库挂了再用主库。

此外,除非专用只读实例全部宕机,Replica 服务也不会使用专用 Offline 实例,这样就避免了在线快查询与离线慢查询混在一起,相互影响。


Default服务

Default服务在 5436 端口上提供服务,它是Primary服务的变体。

Default服务总是绕过连接池直接连到主库上的 PostgreSQL,这对于管理连接、ETL写入、CDC数据变更捕获等都很有用。

- { name: primary ,port: 5433 ,dest: default  ,check: /primary   ,selector: "[]" }

如果 pg_default_service_dest 被修改为 postgres,那么可以说 Default 服务除了端口和名称内容之外,与 Primary 服务是完全等价的。在这种情况下,您可以考虑将 Default 从默认服务中剔除。

示例:pg-test-default 的 haproxy 配置
listen pg-test-default
    bind *:5436         # <--- 除了监听端口/目标端口和服务名,其他配置和 primary 服务一模一样
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /primary
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-1 10.10.10.11:5432 check port 8008 weight 100
    server pg-test-3 10.10.10.13:5432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:5432 check port 8008 weight 100

Offline服务

Default服务在 5438 端口上提供服务,它也绕开连接池直接访问 PostgreSQL 数据库,通常用于慢查询/分析查询/ETL读取/个人用户交互式查询,其服务定义如下:

- { name: offline ,port: 5438 ,dest: postgres ,check: /replica   ,selector: "[? pg_role == `offline` || pg_offline_query ]" , backup: "[? pg_role == `replica` && !pg_offline_query]"}

Offline服务将流量直接路由到专用的离线从库上,或者带有 pg_offline_query 标记的普通只读实例

  • 选择器参数从集群中筛选出了两种实例:pg_role = offline 的离线从库,或是带有 pg_offline_query = true 标记的普通只读实例
  • 专用离线从库和打标记的普通从库主要的区别在于:前者默认不承载 Replica服务 的请求,避免快慢请求混在一起,而后者默认会承载。
  • 备份选择器参数从集群中筛选出了一种实例:不带 offline 标记的普通从库,这意味着如果离线实例或者带Offline标记的普通从库挂了之后,其他普通的从库可以用来承载Offline服务。
  • 健康检查 /replica 只会针对从库返回 200, 主库会返回错误,因此 Offline服务 永远不会将流量分发到主库实例上去,哪怕集群中只剩这一台主库。
  • 同时,主库实例既不会被选择器圈中,也不会被备份选择器圈中,因此它永远不会承载Offline服务。因此 Offline 服务总是可以避免用户访问主库,从而避免对主库的影响。
示例:pg-test-offline 的 haproxy 配置
listen pg-test-offline
    bind *:5438
    mode tcp
    maxconn 5000
    balance roundrobin
    option httpchk
    option http-keep-alive
    http-check send meth OPTIONS uri /replica
    http-check expect status 200
    default-server inter 3s fastinter 1s downinter 5s rise 3 fall 3 on-marked-down shutdown-sessions slowstart 30s maxconn 3000 maxqueue 128 weight 100
    # servers
    server pg-test-3 10.10.10.13:5432 check port 8008 weight 100
    server pg-test-2 10.10.10.12:5432 check port 8008 weight 100 backup

Offline服务提供受限的只读服务,通常用于两类查询:交互式查询(个人用户),慢查询长事务(分析/ETL)。

Offline 服务需要额外的维护照顾:当集群发生主从切换或故障自动切换时,集群的实例角色会发生变化,而 Haproxy 的配置却不会自动发生变化。对于有多个从库的集群来说,这通常并不是一个问题。 然而对于一主一从,从库跑Offline查询的精简小集群而言,主从切换意味着从库变成了主库(健康检查失效),原来的主库变成了从库(不在 Offline 后端列表中),于是没有实例可以承载 Offline 服务了,因此需要手动重载服务以使变更生效。

如果您的业务模型较为简单,您可以考虑剔除 Default 服务与 Offline 服务,使用 Primary 服务与 Replica 服务直连数据库。


重载服务

当集群成员发生变化,如添加/删除副本、主备切换或调整相对权重时, 你需要 重载服务 以使更改生效。

bin/pgsql-svc <cls> [ip...]         # 为 lb 集群或 lb 实例重载服务
# ./pgsql.yml -t pg_service         # 重载服务的实际 ansible 任务

接入服务

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

端口 服务 类型 描述
5432 postgres 数据库 直接访问 postgres 服务器
6432 pgbouncer 中间件 访问 postgres 前先通过连接池中间件
5433 primary 服务 访问主 pgbouncer (或 postgres)
5434 replica 服务 访问备份 pgbouncer (或 postgres)
5436 default 服务 访问主 postgres
5438 offline 服务 访问离线 postgres

组合

# 通过集群域名访问
postgres://test@pg-test:5432/test # DNS -> L2 VIP -> 主直接连接
postgres://test@pg-test:6432/test # DNS -> L2 VIP -> 主连接池 -> 主
postgres://test@pg-test:5433/test # DNS -> L2 VIP -> HAProxy -> 主连接池 -> 主
postgres://test@pg-test:5434/test # DNS -> L2 VIP -> HAProxy -> 备份连接池 -> 备份
postgres://dbuser_dba@pg-test:5436/test # DNS -> L2 VIP -> HAProxy -> 主直接连接 (用于管理员)
postgres://dbuser_stats@pg-test:5438/test # DNS -> L2 VIP -> HAProxy -> 离线直接连接 (用于 ETL/个人查询)

# 通过集群 VIP 直接访问
postgres://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 -> 数据库离线读-写

# 智能客户端:自动进行读写分离
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

覆盖服务

你可以通过多种方式覆盖默认的服务配置,一种常见的需求是让 Primary服务Replica服务 绕过Pgbouncer连接池,直接访问 PostgreSQL 数据库。

为了实现这一点,你可以将 pg_default_service_dest 更改为 postgres,这样所有服务定义中 svc.dest='default' 的服务都会使用 postgres 而不是默认的 pgbouncer 作为目标。

如果您已经将 Primary服务 指向了 PostgreSQL,那么 default服务 就会比较多余,可以考虑移除。

如果您不需要区分个人交互式查询,分析/ETL慢查询,可以考虑从默认服务列表 pg_default_services 中移除Offline服务

如果您不需要只读从库来分担在线只读流量,也可以从默认服务列表中移除 Replica服务


委托服务

Pigsty 通过节点上的 haproxy 暴露 PostgreSQL 服务。整个集群中的所有 haproxy 实例都使用相同的服务定义进行配置。

但是,你可以将 pg 服务委托给特定的节点分组(例如,专门的 haproxy 负载均衡器集群),而不是 PostgreSQL 集群成员上的 haproxy。

为此,你需要使用 pg_default_services 覆盖默认的服务定义,并将 pg_service_provider 设置为代理组名称。

例如,此配置将在端口 10013 的 proxy haproxy 节点组上公开 pg 集群的主服务。

pg_service_provider: proxy       # 使用端口 10013 上的 `proxy` 组的负载均衡器
pg_default_services:  [{ name: primary ,port: 10013 ,dest: postgres  ,check: /primary   ,selector: "[]" }]

用户需要确保每个委托服务的端口,在代理集群中都是唯一的。

在 43 节点生产环境仿真沙箱中提供了一个使用专用负载均衡器集群的例子:prod.yml

6 - 扩展插件

定义,创建,安装,启用 PostgreSQL 插件。

扩展是 PostgreSQL 的灵魂所在

Pigsty 收录了 340 个预先编译打包、开箱即用的 PostgreSQL 强力扩展插件,其中包括一些强力扩展:

  • PostGIS:提供地理空间数据类型与索引支持,GIS 事实标准 (& pgPointCloud 点云,pgRouting 寻路)
  • TimescaleDB:添加时间序列/持续聚合/分布式/列存储/自动压缩的能力
  • PGVector:添加 AI 向量/嵌入数据类型支持,以及 ivfflat 与 hnsw 向量索引。(& pg_sparse 稀疏向量支持)
  • Citus:将经典的主从PG集群原地改造为水平分片的分布式数据库集群。
  • Hydra:添加列式存储与分析能力,提供比肩 ClickHouse 的强力分析能力。
  • ParadeDB:添加 ElasticSearch 水准的全文搜索能力与混合检索的能力。(& zhparser 中文分词)
  • Apache AGE:图数据库扩展,为 PostgreSQL 添加类 Neo4J 的 OpenCypher 查询支持,
  • PG GraphQL:为 PostgreSQL 添加原生内建的 GraphQL 查询语言支持。
  • DuckDB FDW:允许您通过 PostgreSQL 直接读写强力的嵌入式分析数据库 DuckDB 文件 (& DuckDB CLI 本体)。
  • Supabase:基于 PostgreSQL 的开源的 Firebase 替代,提供完整的应用开发存储解决方案。
  • FerretDB:基于 PostgreSQL 的开源 MongoDB 替代,兼容 MongoDB API / 驱动协议。
  • PostgresML:使用SQL完成经典机器学习算法,调用、部署、训练 AI 模型。

pigsty-extension.jpg

绝大部分扩展都是可以并存甚至组合使用的,妙用扩展可以产生 1+1 远大于 2 的协同增幅效应(例外:hydra 与 citus 互斥),实现 PostgreSQL for Everything!

绝大多数插件插件都已经收录放置在基础设施节点上的本地软件源中,可以直接通过 yum/apt 命令安装。您可以通过 Pigsty 配置文件指定需要下载、安装、启用的扩展,并自动完成安装与配置。

此外,有一些“数据库”其实并不是 PostgreSQL 扩展插件,但是基于 PostgreSQL,或与其密切相关。因此也收录在 Pigsty 中提供原生支持, 比如基于 PostgreSQL 提供开源 MongoDB 替代的 FerretDB,提供开源 Airtable 替代的 NocoDB,提供交互式分析检视的 Metabase 等。


默认扩展

当您初始化 PostgreSQL 集群时,列于 pg_packagespg_extensions 中列出的扩展插件将会被安装。

在 EL 系列系统(默认)和 Ubuntu/Debian 系列系统中,包的名称略有不同。但通常包含 pg (el) / postgres (deb),和 PG 大版本号(目前默认为 16)。

Pigsty 允许在这两个变量中使用 ${pg_version} 占位符,它将被自动替换成集群安装的 PG 大版本号。

在 EL / RPM (默认)系统中,默认安装的扩展为:

pg_packages:     # 这三个扩展插件总是随主干大版本一起安装: pg_repack, wal2json, passwordcheck_cracklib
  - pg_repack_${pg_version}* wal2json_${pg_version}* passwordcheck_cracklib_${pg_version}*
pg_extensions:   # 待安装的 pg 扩展列表,默认安装 postgis,timescaledb,pgvector
  - postgis34_${pg_version}* timescaledb-2-postgresql-${pg_version}* pgvector_${pg_version}*

在 Ubuntu / Debian 系统中,默认安装的扩展为:

pg_packages:    # 这两个扩展插件总是随主干大版本一起安装: pg_repack, wal2json
  - postgresql-${pg_version}-repack postgresql-${pg_version}-wal2json
pg_extensions:  # 待安装的 pg 扩展列表,默认安装 postgis,timescaledb,pgvector,citus
  - postgresql-${pg_version}-postgis* timescaledb-2-postgresql-${pg_version} postgresql-${pg_version}-pgvector postgresql-${pg_version}-citus-12.1

因此,Pigsty 默认安装的扩展为:

  • postgis:地理空间数据库扩展(注意:EL7 的版本为 3.3,Ubuntu20 需要在线安装)
  • timescaledb:时序数据库扩展插件(从 TimescaleDB 独立的仓库下载安装,特殊的包名)
  • pgvector:向量数据类型与IVFFLAT/HNSW索引,向量数据库替代。
  • pg_repack:在线处理表膨胀的维护性扩展:对于维护数据库健康非常重要,默认启用。
  • wal2json:通过逻辑解码抽取JSON格式的变更:对于抽取数据库变更非常实用,无需显式启用。
  • passwordcheck_cracklib:强制用户密码强度/过期策略,此扩展默认安装但可选,仅在EL中可用。
  • citus:默认在 Debian/Ubuntu 中安装,EL系因为与 Fork 出来的列存插件 hydra冲突,用户可以二者择一安装。

您也可以在集群初始化完成后再安装新扩展插件,如下一节所示。


扩展安装

当集群已经完成初始化后,如果您需要向集群中安装新扩展,可以向 pg_extensions 中添加扩展名称,并通过剧本完成安装。

例如,如果您想在 pg-meta 集群中安装用于分析的 hydrapg_lakehouse 扩展,可以在集群配置文件中添加:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1 ,pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_databases:
      - name: test
        extensions:  # <----- 在数据库中启用这些扩展 (`CREATE EXTENSION`)
          - { name: postgis, schema: public }
          - { name: timescaledb  }
          - { name: pg_lakehouse } # <---- 新增扩展
          - { name: duckdb_fdw   } # <---- 新增扩展
          - { name: hydra        } # <---- 新增扩展

    pg_libs: 'timescaledb, pg_cron, pg_stat_statements, auto_explain' # <- 个别扩展需要加载动态库方可运行
    pg_extensions:   # 安装到集群中的扩展列表 (yum/apt install)
      - postgis34_${pg_version}* timescaledb-2-postgresql-${pg_version}* pgvector_${pg_version}*          # 默认安装的三个扩展,如果需要,不要忘记保留
      - pg_lakehouse_${pg_version}* duckdb_fdw_${pg_version}* hydra_${pg_version}* #citus_${pg_version}*  # <-----+ 新增扩展
      
      #- pg_bm25_${pg_version}* pg_sparse_${pg_version}* zhparser_${pg_version}*                          # 其他备选扩展
      #- pg_graphql_${pg_version} pg_net_${pg_version}* pgsql-http_${pg_version}* vault_${pg_version} pgjwt_${pg_version} pg_tle_${pg_version}*
      #- pgml_${pg_version}* apache-age_${pg_version}* pg_roaringbitmap_${pg_version}* pointcloud_${pg_version}* pgsql-gzip_${pg_version}* pglogical_${pg_version}* pg_cron_${pg_version}*
      #- orafce_${pg_version}* mongo_fdw_${pg_version}* tds_fdw_${pg_version}* mysql_fdw_${pg_version} hdfs_fdw_${pg_version} sqlite_fdw_${pg_version} pgbouncer_fdw_${pg_version} powa_${pg_version}* pg_stat_kcache_${pg_version}* pg_stat_monitor_${pg_version}* pg_qualstats_${pg_version} pg_track_settings_${pg_version} pg_wait_sampling_${pg_version} hll_${pg_version} pgaudit_${pg_version}
      #- plprofiler_${pg_version}* plsh_${pg_version}* pldebugger_${pg_version} plpgsql_check_${pg_version}* pgtt_${pg_version} pgq_${pg_version}* pgsql_tweaks_${pg_version} count_distinct_${pg_version} hypopg_${pg_version} timestamp9_${pg_version}* semver_${pg_version}* prefix_${pg_version}* periods_${pg_version} ip4r_${pg_version} tdigest_${pg_version} pgmp_${pg_version} extra_window_functions_${pg_version} topn_${pg_version}
      #- pg_background_${pg_version} e-maj_${pg_version} pg_prioritize_${pg_version} pgcryptokey_${pg_version} logerrors_${pg_version} pg_top_${pg_version} pg_comparator_${pg_version} pg_ivm_${pg_version}* pgsodium_${pg_version}* pgfincore_${pg_version}* ddlx_${pg_version} credcheck_${pg_version} safeupdate_${pg_version} pg_squeeze_${pg_version}* pg_fkpart_${pg_version} pg_jobmon_${pg_version}
      #- pg_partman_${pg_version} pg_permissions_${pg_version} pgexportdoc_${pg_version} pgimportdoc_${pg_version} pg_statement_rollback_${pg_version}* pg_hint_plan_${pg_version}* pg_auth_mon_${pg_version} pg_checksums_${pg_version} pg_failover_slots_${pg_version} pg_readonly_${pg_version}* pg_uuidv7_${pg_version}* set_user_${pg_version}* rum_${pg_version}

使用 pgsql.ymlpg_extension 子任务,为已经创建好的集群添加扩展:

./pgsql.yml -l pg-meta -t pg_extension    # 为集群安装指定的扩展插件

您也可以在数据库服务器上使用 yum | apt 命令直接安装扩展软件包,或者使用 Ansible 模块来批量完成安装,但是这样您必须显式指明扩展的大版本号(目前为 16):

cd ~/pigsty;               # 在管理节点上进入 pigsty 源码目录,为 pg-test 集群安装 pg_analytics 与 hydra 扩展
ansible pg-meta -m package -b -a 'name=pg_analytics_16'     # 扩展的名称通常后缀以 `_<pgmajorversion>`
ansible pg-meta -m package -b -a 'name=hydra_16*'           # 例如,您的数据库大版本为16,那么就应该在扩展yum包之后添加 `_16`

请注意,Pigsty 默认只下载 PG 主版本(PG16)上的主流扩展插件,当您使用其他大版本的 PostgreSQL 时,应当调整 repo_packages 中下载的插件名称。


扩展启用

安装 PostgreSQL 扩展后,您可以在 PostgreSQL 的 pg_available_extensions 视图中看到它们。但想要实际启用扩展,通常还需要额外的步骤:

  1. 一部分扩展要求被添加到 shared_preload_libraries 中动态加载,例如 timescaledbcitus 等。
  2. 大部分扩展都需要通过 SQL 语句:CREATE EXTENSION <name>; 启用,极少量扩展不需要,例如 wal2json
  • 修改 shared_preload_libraries
    • 在数据库集群初始化前,可以通过 pg_libs 参数手工预先指定;
    • 当数据库已经初始化完毕后,您可以修改集群配置,直接修改 shared_preload_libraries 参数并应用(无需重启)。
    • 需要动态加载的典型插件:citus, timescaledb, pg_cron, pg_net, pg_tle
  • 执行 CREATE EXTENSION
    • 在数据库集群初始化前,可以在 pg_databases.extensions 列表中指定。
    • 当数据库已经初始化完毕后,您可以直接连接数据库执行此 SQL 命令,或使用其他模式变更工具管理扩展。

从原理上讲:PostgreSQL 的扩展通常由 Control文件(元数据,一定存在),SQL文件(SQL语句,可选),So文件(二进制动态连接库,可选)三部分组成。 提供 .so 文件的扩展有可能需要添加到 shared_preload_libraries 才能生效,例如 citustimescaledb,但也有许多扩展不用,例如 postgispgvector。 不通过 SQL 接口对外服务的扩展不需要执行 CREATE EXTENSION,例如提供 CDC 抽取能力的 wal2json 扩展。

在您希望启用扩展的数据库中执行 CREATE EXTENSION SQL 语句,即可完成扩展的创建:

CREATE EXTENSION vector;  -- 安装向量数据库扩展
CREATE EXTENSION hydra;   -- 安装列存数据库扩展

扩展下载

Pigsty 默认从 PostgreSQL 官方软件源下载扩展插件,如果您希望使用 Pigsty 没有收录的扩展,可以选择直接编译安装, 或者下载 RPM/DEB 包放置于管理节点上的本地软件源中(/www/pigsty),供所有节点使用,详情参考管理SOP-添加软件

7 - 认证 / HBA

Pigsty 中基于主机的身份认证 HBA(Host-Based Authentication)详解。

Pigsty 中基于主机的身份认证 HBA(Host-Based Authentication)详解。

认证是 访问控制权限系统 的基石,PostgreSQL拥有多种认证方法。

这里主要介绍 HBA:Host Based Authentication,HBA规则定义了哪些用户能够通过哪些方式从哪些地方访问哪些数据库。


客户端认证

要连接到PostgreSQL数据库,用户必须先经过认证(默认使用密码)。

您可以在连接字符串中提供密码(不安全)或使用PGPASSWORD环境变量或.pgpass文件传递密码。参考psql文档和PostgreSQL连接字符串以获取更多详细信息。

psql 'host=<host> port=<port> dbname=<dbname> user=<username> password=<password>'
psql postgres://<username>:<password>@<host>:<port>/<dbname>
PGPASSWORD=<password>; psql -U <username> -h <host> -p <port> -d <dbname>

例如,连接 Pigsty 默认的 meta 数据库,可以使用以下连接串:

psql 'host=10.10.10.10 port=5432 dbname=meta user=dbuser_dba password=DBUser.DBA'
psql postgres://dbuser_dba:DBUser.DBA@10.10.10.10:5432/meta
PGPASSWORD=DBUser.DBA; psql -U dbuser_dba -h 10.10.10.10 -p 5432 -d meta

默认配置下,Pigsty会启用服务端 SSL 加密,但不验证客户端 SSL 证书。要使用客户端SSL证书连接,你可以使用PGSSLCERTPGSSLKEY环境变量或sslkeysslcert参数提供客户端参数。

psql 'postgres://dbuser_dba:DBUser.DBA@10.10.10.10:5432/meta?sslkey=/path/to/dbuser_dba.key&sslcert=/path/to/dbuser_dba.crt'

客户端证书(CN = 用户名)可以使用本地CA与cert.yml剧本签发。


定义HBA

在Pigsty中,有四个与HBA规则有关的参数:

这些都是 HBA 规则对象的数组,每个HBA规则都是以下两种形式之一的对象:

1. 原始形式

原始形式的 HBA 与 PostgreSQL pg_hba.conf 的格式几乎完全相同:

- title: allow intranet password access
  role: common
  rules:
    - host   all  all  10.0.0.0/8      md5
    - host   all  all  172.16.0.0/12   md5
    - host   all  all  192.168.0.0/16  md5

在这种形式中,rules 字段是字符串数组,每一行都是条原始形式的 HBA规则title 字段会被渲染为一条注释,解释下面规则的作用。

role 字段用于说明该规则适用于哪些实例角色,当实例的pg_rolerole相同时,HBA规则将被添加到这台实例的 HBA 中。

  • role: common的HBA规则将被添加到所有实例上。
  • role: primary 的 HBA 规则只会添加到主库实例上。
  • role: replica 的 HBA 规则只会添加到从库实例上。
  • role: offline的HBA规则将被添加到离线实例上( pg_role = offlinepg_offline_query = true

2. 别名形式

别名形式允许您用更简单清晰便捷的方式维护 HBA 规则:它用addrauthuserdb 字段替换了 rulestitlerole 字段则仍然生效。

- addr: 'intra'    # world|intra|infra|admin|local|localhost|cluster|<cidr>
  auth: 'pwd'      # trust|pwd|ssl|cert|deny|<official auth method>
  user: 'all'      # all|${dbsu}|${repl}|${admin}|${monitor}|<user>|<group>
  db: 'all'        # all|replication|....
  rules: []        # raw hba string precedence over above all
  title: allow intranet password access
  • addr: where 哪些IP地址段受本条规则影响?
    • world: 所有的IP地址
    • intra: 所有的内网IP地址段: '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'
    • infra: Infra节点的IP地址
    • admin: admin_ip 管理节点的IP地址
    • local: 本地 Unix Socket
    • localhost: 本地 Unix Socket 以及TCP 127.0.0.1/32 环回地址
    • cluster: 同一个 PostgresQL 集群所有成员的IP地址
    • <cidr>: 一个特定的 CIDR 地址块或IP地址
  • auth: how 本条规则指定的认证方式?
    • deny: 拒绝访问
    • trust: 直接信任,不需要认证
    • pwd: 密码认证,根据 pg_pwd_enc 参数选用 md5scram-sha-256 认证
    • sha/scram-sha-256:强制使用 scram-sha-256 密码认证方式。
    • md5: md5 密码认证方式,但也可以兼容 scram-sha-256 认证,不建议使用。
    • ssl: 在密码认证 pwd 的基础上,强制要求启用SSL
    • ssl-md5: 在密码认证 md5 的基础上,强制要求启用SSL
    • ssl-sha: 在密码认证 sha 的基础上,强制要求启用SSL
    • os/ident: 使用操作系统用户的身份进行 ident 认证
    • peer: 使用 peer 认证方式,类似于 os ident
    • cert: 使用基于客户端SSL证书的认证方式,证书CN为用户名
  • user: who:哪些用户受本条规则影响?
  • db: which:哪些数据库受本条规则影响?
    • all: 所有数据库
    • replication: 允许建立复制连接(不指定特定数据库)
    • 某个特定的数据库

3. 定义位置

通常,全局的HBA定义在 all.vars 中,如果您想要修改全局默认的HBA规则,可以从 full.yml 模板中复制一份到 all.vars 中进行修改。

而集群特定的 HBA 规则定义在数据库的集群级配置中:

下面是一些集群HBA规则的定义例子:

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta
    pg_hba_rules:
      - { user: dbuser_view ,db: all    ,addr: infra        ,auth: pwd  ,title: '允许 dbuser_view 从基础设施节点密码访问所有库'}
      - { user: all         ,db: all    ,addr: 100.0.0.0/8  ,auth: pwd  ,title: '允许所有用户从K8S网段密码访问所有库'          }
      - { user: '${admin}'  ,db: world  ,addr: 0.0.0.0/0    ,auth: cert ,title: '允许管理员用户从任何地方用客户端证书登陆'       }

重载HBA

HBA 是一个静态的规则配置文件,修改后需要重载才能生效。默认的 HBA 规则集合因为不涉及 Role 与集群成员,所以通常不需要重载。

如果您设计的 HBA 使用了特定的实例角色限制,或者集群成员限制,那么当集群实例成员发生变化(新增/下线/主从切换),一部分HBA规则的生效条件/涉及范围发生变化,通常也需要重载HBA以反映最新变化。

要重新加载 postgres/pgbouncer 的 hba 规则:

bin/pgsql-hba <cls>                 # 重新加载集群 `<cls>` 的 hba 规则
bin/pgsql-hba <cls> ip1 ip2...      # 重新加载特定实例的 hba 规则

底层实际执行的 Ansible 剧本命令为:

./pgsql.yml -l <cls> -e pg_reload=true -t pg_hba,pg_reload
./pgsql.yml -l <cls> -e pg_reload=true -t pgbouncer_hba,pgbouncer_reload

默认HBA

Pigsty 有一套默认的 HBA 规则,对于绝大多数场景来说,它已经足够安全了。这些规则使用别名形式,因此基本可以自我解释。

pg_default_hba_rules:             # postgres 全局默认的HBA规则 
  - {user: '${dbsu}'    ,db: all         ,addr: local     ,auth: ident ,title: 'dbsu access via local os user ident'  }
  - {user: '${dbsu}'    ,db: replication ,addr: local     ,auth: ident ,title: 'dbsu replication from local os ident' }
  - {user: '${repl}'    ,db: replication ,addr: localhost ,auth: pwd   ,title: 'replicator replication from localhost'}
  - {user: '${repl}'    ,db: replication ,addr: intra     ,auth: pwd   ,title: 'replicator replication from intranet' }
  - {user: '${repl}'    ,db: postgres    ,addr: intra     ,auth: pwd   ,title: 'replicator postgres db from intranet' }
  - {user: '${monitor}' ,db: all         ,addr: localhost ,auth: pwd   ,title: 'monitor from localhost with password' }
  - {user: '${monitor}' ,db: all         ,addr: infra     ,auth: pwd   ,title: 'monitor from infra host with password'}
  - {user: '${admin}'   ,db: all         ,addr: infra     ,auth: ssl   ,title: 'admin @ infra nodes with pwd & ssl'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: ssl   ,title: 'admin @ everywhere with ssl & pwd'   }
  - {user: '+dbrole_readonly',db: all    ,addr: localhost ,auth: pwd   ,title: 'pgbouncer read/write via local socket'}
  - {user: '+dbrole_readonly',db: all    ,addr: intra     ,auth: pwd   ,title: 'read/write biz user via password'     }
  - {user: '+dbrole_offline' ,db: all    ,addr: intra     ,auth: pwd   ,title: 'allow etl offline tasks from intranet'}
pgb_default_hba_rules:            # pgbouncer 全局默认的HBA规则 
  - {user: '${dbsu}'    ,db: pgbouncer   ,addr: local     ,auth: peer  ,title: 'dbsu local admin access with os ident'}
  - {user: 'all'        ,db: all         ,addr: localhost ,auth: pwd   ,title: 'allow all user local access with pwd' }
  - {user: '${monitor}' ,db: pgbouncer   ,addr: intra     ,auth: pwd   ,title: 'monitor access via intranet with pwd' }
  - {user: '${monitor}' ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other monitor access addr' }
  - {user: '${admin}'   ,db: all         ,addr: intra     ,auth: pwd   ,title: 'admin access via intranet with pwd'   }
  - {user: '${admin}'   ,db: all         ,addr: world     ,auth: deny  ,title: 'reject all other admin access addr'   }
  - {user: 'all'        ,db: all         ,addr: intra     ,auth: pwd   ,title: 'allow all user intra access with pwd' }
示例:渲染 pg_hba.conf
#==============================================================#
# File      :   pg_hba.conf
# Desc      :   Postgres HBA Rules for pg-meta-1 [primary]
# Time      :   2023-01-11 15:19
# Host      :   pg-meta-1 @ 10.10.10.10:5432
# Path      :   /pg/data/pg_hba.conf
# Note      :   ANSIBLE MANAGED, DO NOT CHANGE!
# Author    :   Ruohang Feng (rh@vonng.com)
# License   :   AGPLv3
#==============================================================#

# addr alias
# local     : /var/run/postgresql
# admin     : 10.10.10.10
# infra     : 10.10.10.10
# intra     : 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16

# user alias
# dbsu    :  postgres
# repl    :  replicator
# monitor :  dbuser_monitor
# admin   :  dbuser_dba

# dbsu access via local os user ident [default]
local    all                postgres                              ident

# dbsu replication from local os ident [default]
local    replication        postgres                              ident

# replicator replication from localhost [default]
local    replication        replicator                            scram-sha-256
host     replication        replicator         127.0.0.1/32       scram-sha-256

# replicator replication from intranet [default]
host     replication        replicator         10.0.0.0/8         scram-sha-256
host     replication        replicator         172.16.0.0/12      scram-sha-256
host     replication        replicator         192.168.0.0/16     scram-sha-256

# replicator postgres db from intranet [default]
host     postgres           replicator         10.0.0.0/8         scram-sha-256
host     postgres           replicator         172.16.0.0/12      scram-sha-256
host     postgres           replicator         192.168.0.0/16     scram-sha-256

# monitor from localhost with password [default]
local    all                dbuser_monitor                        scram-sha-256
host     all                dbuser_monitor     127.0.0.1/32       scram-sha-256

# monitor from infra host with password [default]
host     all                dbuser_monitor     10.10.10.10/32     scram-sha-256

# admin @ infra nodes with pwd & ssl [default]
hostssl  all                dbuser_dba         10.10.10.10/32     scram-sha-256

# admin @ everywhere with ssl & pwd [default]
hostssl  all                dbuser_dba         0.0.0.0/0          scram-sha-256

# pgbouncer read/write via local socket [default]
local    all                +dbrole_readonly                      scram-sha-256
host     all                +dbrole_readonly   127.0.0.1/32       scram-sha-256

# read/write biz user via password [default]
host     all                +dbrole_readonly   10.0.0.0/8         scram-sha-256
host     all                +dbrole_readonly   172.16.0.0/12      scram-sha-256
host     all                +dbrole_readonly   192.168.0.0/16     scram-sha-256

# allow etl offline tasks from intranet [default]
host     all                +dbrole_offline    10.0.0.0/8         scram-sha-256
host     all                +dbrole_offline    172.16.0.0/12      scram-sha-256
host     all                +dbrole_offline    192.168.0.0/16     scram-sha-256

# allow application database intranet access [common] [DISABLED]
#host    kong            dbuser_kong         10.0.0.0/8          md5
#host    bytebase        dbuser_bytebase     10.0.0.0/8          md5
#host    grafana         dbuser_grafana      10.0.0.0/8          md5
示例: 渲染 pgb_hba.conf
#==============================================================#
# File      :   pgb_hba.conf
# Desc      :   Pgbouncer HBA Rules for pg-meta-1 [primary]
# Time      :   2023-01-11 15:28
# Host      :   pg-meta-1 @ 10.10.10.10:5432
# Path      :   /etc/pgbouncer/pgb_hba.conf
# Note      :   ANSIBLE MANAGED, DO NOT CHANGE!
# Author    :   Ruohang Feng (rh@vonng.com)
# License   :   AGPLv3
#==============================================================#

# PGBOUNCER HBA RULES FOR pg-meta-1 @ 10.10.10.10:6432
# ansible managed: 2023-01-11 14:30:58

# addr alias
# local     : /var/run/postgresql
# admin     : 10.10.10.10
# infra     : 10.10.10.10
# intra     : 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16

# user alias
# dbsu    :  postgres
# repl    :  replicator
# monitor :  dbuser_monitor
# admin   :  dbuser_dba

# dbsu local admin access with os ident [default]
local    pgbouncer          postgres                              peer

# allow all user local access with pwd [default]
local    all                all                                   scram-sha-256
host     all                all                127.0.0.1/32       scram-sha-256

# monitor access via intranet with pwd [default]
host     pgbouncer          dbuser_monitor     10.0.0.0/8         scram-sha-256
host     pgbouncer          dbuser_monitor     172.16.0.0/12      scram-sha-256
host     pgbouncer          dbuser_monitor     192.168.0.0/16     scram-sha-256

# reject all other monitor access addr [default]
host     all                dbuser_monitor     0.0.0.0/0          reject

# admin access via intranet with pwd [default]
host     all                dbuser_dba         10.0.0.0/8         scram-sha-256
host     all                dbuser_dba         172.16.0.0/12      scram-sha-256
host     all                dbuser_dba         192.168.0.0/16     scram-sha-256

# reject all other admin access addr [default]
host     all                dbuser_dba         0.0.0.0/0          reject

# allow all user intra access with pwd [default]
host     all                all                10.0.0.0/8         scram-sha-256
host     all                all                172.16.0.0/12      scram-sha-256
host     all                all                192.168.0.0/16     scram-sha-256

安全加固

对于那些需要更高安全性的场合,我们提供了一个安全加固的配置模板 security.yml,使用了以下的默认 HBA 规则集:

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

更多信息,请参考安全加固一节。

8 - 集群配置

根据需求场景选择合适的实例与集群类型,配置出满足需求的 PostgreSQL 数据库集群。

根据需求场景选择合适的实例与集群类型,配置出满足需求的 PostgreSQL 数据库集群。

您可以定义不同类型的实例和集群,下面是 Pigsty 中常见的几种 PostgreSQL 实例/集群类型:


读写主库

我们从最简单的情况开始:由一个主库(Primary)组成的单实例集群:

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

这段配置言简意赅,仅由身份参数构成。

使用以下命令在节点 10.10.10.11 上创建一个主库实例:

bin/pgsql-add pg-test

Demo展示,开发测试,承载临时需求,进行无关紧要的计算分析任务时,使用单一数据库实例可能并没有太大问题。但这样的单机集群没有高可用,当出现硬件故障时,您需要使用 PITR 或其他恢复手段来确保集群的 RTO / RPO。为此,您可以考虑为集群添加若干个只读从库


只读从库

要添加一台只读从库(Replica)实例,您可以在 pg-test 中添加一个新节点,并将其 pg_role 设置为replica

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }  # <--- 新添加的从库
  vars:
    pg_cluster: pg-test

如果整个集群不存在,您可以直接创建这个完整的集群。 如果集群主库已经初始化好了,那么您可以向现有集群添加一个从库:

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

当集群主库出现故障时,只读实例(Replica)可以在高可用系统的帮助下接管主库的工作。除此之外,只读实例还可以用于执行只读查询:许多业务的读请求要比写请求多很多,而大部分只读查询负载都可以由从库实例承担。


离线从库

离线实例(Offline)是专门用于服务慢查询、ETL、OLAP流量和交互式查询等的专用只读从库。慢查询/长事务对在线业务的性能与稳定性有不利影响,因此最好将它们与在线业务隔离开来。

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

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }
    10.10.10.13: { pg_seq: 3, pg_role: offline }  # <--- 新添加的离线从库
  vars:
    pg_cluster: pg-test

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

许多情况下,数据库资源有限,单独使用一台服务器作为离线实例是不经济的做法。作为折中,您可以选择一台现有的从库实例,打上 pg_offline_query 标记,将其标记为一台可以承载“离线查询”的实例。在这种情况下,这台只读从库会同时承担在线只读请求与离线类查询。您可以使用 pg_default_hba_rulespg_hba_rules 对离线实例进行额外的访问控制。


同步备库

当启用同步备库(Sync Standby)时,PostgreSQL 将选择一个从库作为同步备库,其他所有从库作为候选者。 主数据库会等待备库实例刷新到磁盘,然后才确认提交,备库实例始终拥有最新的数据,没有复制延迟,主从切换至同步备库不会有数据丢失。

PostgreSQL 默认使用异步流复制,这可能会有小的复制延迟(10KB / 10ms 数量级)。当主库失败时,可能会有一个小的数据丢失窗口(可以使用pg_rpo来控制),但对于大多数场景来说,这是可以接受的。

但在某些关键场景中(例如,金融交易),数据丢失是完全不可接受的,或者,读取复制延迟是不可接受的。在这种情况下,您可以使用同步提交来解决这个问题。 要启用同步备库模式,您可以简单地使用pg_conf中的crit.yml模板。

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }
    10.10.10.13: { pg_seq: 3, pg_role: replica }
  vars:
    pg_cluster: pg-test
    pg_conf: crit.yml   # <--- 使用 crit 模板

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

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

应用这些更改?[y/N]: y

在这种情况下,PostgreSQL 配置项 synchronous_standby_names 由 Patroni 自动管理。 一台从库将被选拔为同步从库,它的 application_name 将被写入 PostgreSQL 主库配置文件中并应用生效。


法定人数提交

法定人数提交(Quorum Commit)提供了比同步备库更强大的控制能力:特别是当您有多个从库时,您可以设定提交成功的标准,实现更高/更低的一致性级别(以及可用性之间的权衡)。

如果想要最少两个从库来确认提交,可以通过 Patroni 配置集群,调整参数 synchronous_node_count 并应用生效

synchronous_mode: true          # 确保同步提交已经启用
synchronous_node_count: 2       # 指定“至少”有多少个从库提交成功,才算提交成功

如果你想要使用更多的同步从库,修改 synchronous_node_count 的取值即可。当集群的规模发生变化时,您应当确保这里的配置仍然是有效的,以避免服务不可用。

在这种情况下,PostgreSQL 配置项 synchronous_standby_names 由 Patroni 自动管理。

synchronous_standby_names = '2 ("pg-test-3","pg-test-2")'
示例:使用多个同步从库
$ pg edit-config pg-test
---
+synchronous_node_count: 2

Apply these changes? [y/N]: y

应用配置后,出现两个同步备库。

+ Cluster: pg-test (7080814403632534854) +---------+----+-----------+-----------------+
| Member    | Host        | Role         | State   | TL | Lag in MB | Tags            |
+-----------+-------------+--------------+---------+----+-----------+-----------------+
| pg-test-1 | 10.10.10.10 | Leader       | running |  1 |           | clonefrom: true |
| pg-test-2 | 10.10.10.11 | Sync Standby | running |  1 |         0 | clonefrom: true |
| pg-test-3 | 10.10.10.12 | Sync Standby | running |  1 |         0 | clonefrom: true |
+-----------+-------------+--------------+---------+----+-----------+-----------------+

另一种情景是,使用 任意n个 从库来确认提交。在这种情况下,配置的方式略有不同,例如,假设我们只需要任意一个从库确认提交:

synchronous_mode: quorum        # 使用法定人数提交
postgresql:
  parameters:                   # 修改 PostgreSQL 的配置参数 synchronous_standby_names ,使用 `ANY n ()` 语法
    synchronous_standby_names: 'ANY 1 (*)'  # 你可以指定具体的从库列表,或直接使用 * 通配所有从库。
示例:启用ANY法定人数提交
$ pg edit-config pg-test

+    synchronous_standby_names: 'ANY 1 (*)' # 在 ANY 模式下,需要使用此参数
- synchronous_node_count: 2  # 在 ANY 模式下, 不需要使用此参数

Apply these changes? [y/N]: y

应用后,配置生效,所有备库在 Patroni 中变为普通的 replica。但是在 pg_stat_replication 中可以看到 sync_state 会变为 quorum


备份集群

您可以克隆现有的集群,并创建一个备份集群(Standby Cluster),用于数据迁移、水平拆分、多区域部署,或灾难恢复。

在正常情况下,备份集群将追随上游集群并保持内容同步,您可以将备份集群提升,作为真正地独立集群。

备份集群的定义方式与正常集群的定义基本相同,除了在主库上额外定义了 pg_upstream 参数,备份集群的主库被称为 备份集群领导者 (Standby Leader)。

例如,下面定义了一个pg-test集群,以及其备份集群pg-test2,其配置清单可能如下所示:

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

# pg-test2 是 pg-test 的备份集群
pg-test2:
  hosts:
    10.10.10.12: { pg_seq: 1, pg_role: primary , pg_upstream: 10.10.10.11 } # <--- pg_upstream 在这里定义
    10.10.10.13: { pg_seq: 2, pg_role: replica }
  vars: { pg_cluster: pg-test2 }

pg-test2 集群的主节点 pg-test2-1 将是 pg-test 的下游从库,并在pg-test2集群中充当备份集群领导者(Standby Leader)。

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

bin/pgsql-add pg-test     # 创建原始集群
bin/pgsql-add pg-test2    # 创建备份集群
示例:更改复制上游

如有必要(例如,上游发生主从切换/故障转移),您可以通过配置集群更改备份集群的复制上游。

要这样做,只需将standby_cluster.host更改为新的上游IP地址并应用。

$ pg edit-config pg-test2

 standby_cluster:
   create_replica_methods:
   - basebackup
-  host: 10.10.10.13     # <--- 旧的上游
+  host: 10.10.10.12     # <--- 新的上游
   port: 5432

 Apply these changes? [y/N]: y
示例:提升备份集群

你可以随时将备份集群提升为独立集群,这样该集群就可以独立承载写入请求,并与原集群分叉。

为此,你必须配置该集群并完全擦除standby_cluster部分,然后应用。

$ pg edit-config pg-test2
-standby_cluster:
-  create_replica_methods:
-  - basebackup
-  host: 10.10.10.11
-  port: 5432

Apply these changes? [y/N]: y
示例:级联复制

如果您在一台从库上指定了 pg_upstream,而不是主库。那么可以配置集群的 级联复制(Cascade Replication)

在配置级联复制时,您必须使用集群中某一个实例的IP地址作为参数的值,否则初始化会报错。该从库从特定的实例进行流复制,而不是主库。

这台充当 WAL 中继器的实例被称为 桥接实例(Bridge Instance)。使用桥接实例可以分担主库发送 WAL 的负担,当您有几十台从库时,使用桥接实例级联复制是一个不错的注意。

pg-test:
  hosts: # pg-test-1 ---> pg-test-2 ---> pg-test-3
    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_upstream: 10.10.10.12 }
    # ^--- 从 pg-test-2 (桥接)复制,而不是从 pg-test-1 (主节点) 
  vars: { pg_cluster: pg-test }

延迟集群

延迟集群(Delayed Cluster)是一种特殊类型的备份集群,用于尽快恢复“意外删除”的数据。

例如,如果你希望有一个名为 pg-testdelay 的集群,其数据内容与一小时前的 pg-test 集群相同:

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

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

你还可以在现有的备份集群配置一个“复制延迟”。

$ pg edit-config pg-testdelay
 standby_cluster:
   create_replica_methods:
   - basebackup
   host: 10.10.10.11
   port: 5432
+  recovery_min_apply_delay: 1h    # <--- 在此处添加延迟时长,例如1小时

Apply these changes? [y/N]: y

当某些元组和表格被意外删除时,你可以通过修改此参数的方式,将此延迟集群推进到适当的时间点,并从中读取数据,快速修复原始集群。

延迟集群需要额外的资源,但比起 PITR 要快得多,并且对系统的影响也小得多,对于非常关键的集群,可以考虑搭建延迟集群。


Citus集群

Pigsty 原生支持 Citus。可以参考 files/pigsty/citus.ymlprod.yml 作为样例。

要定义一个 citus 集群,您需要指定以下参数:

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

all:
  children:
    pg-citus0: # citus 0号分片
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus0 , pg_group: 0 }
    pg-citus1: # citus 1号分片
      hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus1 , pg_group: 1 }
    pg-citus2: # citus 2号分片
      hosts: { 10.10.10.12: { pg_seq: 1, pg_role: primary } }
      vars: { pg_cluster: pg-citus2 , pg_group: 2 }
    pg-citus3: # citus 3号分片
      hosts:
        10.10.10.13: { pg_seq: 1, pg_role: primary }
        10.10.10.14: { pg_seq: 2, pg_role: replica }
      vars: { pg_cluster: pg-citus3 , pg_group: 3 }
  vars:                               # 所有 Citus 集群的全局参数
    pg_mode: citus                    # pgsql 集群模式需要设置为: citus
    pg_shard: pg-citus                # citus 水平分片名称: pg-citus
    patroni_citus_db: meta            # citus 数据库名称:meta
    pg_dbsu_password: DBUser.Postgres # 如果使用 dbsu ,那么需要为其配置一个密码
    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'  }

在协调者节点上,您可以创建分布式表和引用表,并从任何数据节点查询它们。从 11.2 开始,任何 Citus 数据库节点都可以扮演协调者的角色了。

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

大版本切换

Pigsty 从 PostgreSQL 10 开始提供支持,不过目前预打包的离线软件包中仅包含 12 - 16 版本。

Pigsty 对不同大版本的支持力度不同,如下表所示:

版本 说明 软件包支持程度
16 刚发布的新版本,支持重要扩展 Core, L1, L2
15 稳定的主版本,支持全部扩展(默认) Core, L1, L2, L3
14 旧的稳定主版本,支持 L1、L2 扩展 Core, L1
13 更旧的主版本,仅支持 L1 扩展 Core, L1
12 更旧的主版本,仅支持 L1 扩展 Core, L1
  • 内核: postgresql*,提供 12 - 16 支持
  • 1类扩展: wal2jsonpg_repackpasswordcheck_cracklib (在 PG 12 - 16 中提供)
  • 2类扩展: postgiscitustimescaledbpgvector (在 PG 15,16 中提供)
  • 3类扩展: 其他扩展 (目前只在 PG 15 提供)

除了 PG15 之外,其他大版本上可能会有一些扩展不可用,您可能需要更改 pg_extensionspg_libs 以满足您的需求。

如果您确实希望在较老的大版本上使用这些扩展,可以参考添加软件安装扩展的说明,手工从PGDG源下载并安装。

这里有一些不同大版本集群的配置样例:

pg-v12:
  hosts: { 10.10.10.12: { pg_seq: 1 ,pg_role: primary } }
  vars:
    pg_cluster: pg-v12
    pg_version: 12
    pg_libs: 'pg_stat_statements, auto_explain'
    pg_extensions: [ 'wal2json_12* pg_repack_12* passwordcheck_cracklib_12*' ]

pg-v13:
  hosts: { 10.10.10.13: { pg_seq: 1 ,pg_role: primary } }
  vars:
    pg_cluster: pg-v13
    pg_version: 13
    pg_libs: 'pg_stat_statements, auto_explain'
    pg_extensions: [ 'wal2json_13* pg_repack_13* passwordcheck_cracklib_13*' ]

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

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

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

9 - 预置剧本

如何使用 ansible 剧本来管理 PostgreSQL 集群

PostgreSQL 剧本

Pigsty提供了一系列剧本,用于集群上下线扩缩容,用户/数据库管理,监控或迁移已有实例。

  • pgsql.yml :初始化PostgreSQL集群或添加新的从库。
  • pgsql-rm.yml :移除PostgreSQL集群,或移除某个实例
  • pgsql-user.yml :在现有的PostgreSQL集群中添加新的业务用户
  • pgsql-db.yml :在现有的PostgreSQL集群中添加新的业务数据库
  • pgsql-monitor.yml :将远程postgres实例纳入监控中
  • pgsql-migration.yml :为现有的PostgreSQL集群生成迁移手册和脚本

保护机制

使用 PGSQL 剧本时需要特别注意,剧本 pgsql.ymlpgsql-rm.yml 使用不当会有误删数据库的风险!

  • 在使用pgsql.yml时,请再三检查--tags|-t--limit|-l 参数是否正确。
  • 强烈建议在执行时添加-l参数,限制命令执行的对象范围,并确保自己在正确的目标上执行正确的任务。
  • 限制范围通常以一个数据库集群为宜,使用不带参数的pgsql.yml在生产环境中是一个高危操作,务必三思而后行。

出于防止误删的目的,Pigsty 的 PGSQL 模块提供了防误删保险,由以下两个参数控制:

对初始化剧本的影响

pgsql.yml 剧本执行中遭遇配置相同的运行中现存实例时,会有以下行为表现:

pg_safeguard / pg_clean pg_clean=true pg_clean=false
pg_safeguard=false 抹除实例 中止执行
pg_safeguard=true 中止执行 中止执行
  • 如果 pg_safeguard 启用,那么该剧本会中止执行,避免误删。
  • 如果没有启用,那么会进一步根据 pg_clean 的取值,来决定是否移除现有的实例。
    • 如果 pg_cleantrue,该剧本会直接清理现有实例,为新实例腾出空间。这是默认行为。
    • 如果 pg_cleanfalse,该剧本会中止执行,这需要显式配置。

对下线剧本的影响

pgsql-rm.yml 剧本执行中遭遇配置相同的运行中现存实例时,会有以下行为表现:

pg_safeguard / pg_clean pg_clean=true pg_clean=false
pg_safeguard=false 抹除实例与数据 抹除实例
pg_safeguard=true 中止执行 中止执行
  • 如果 pg_safeguard 启用,那么该剧本会中止执行,避免误删。
  • 如果没有启用,那么会继续抹除实例,同时 pg_clean 在本剧本中会被解释为:是否移除数据目录。
    • 如果 pg_cleantrue,该剧本会直接一并清理 PostgreSQL 数据目录,即所谓“删库”,这是默认行为。
    • 如果 pg_cleanfalse,该剧本保留数据目录,继续完成其他清理工作,这需要显式配置。

pgsql.yml

剧本 pgsql.yml 用于初始化PostgreSQL集群或添加新的从库。

下面是使用此剧本初始化沙箱环境中 PostgreSQL 集群的过程:

asciicast

本剧本包含以下子任务:

# pg_clean      : 清理现有的 postgres(如有必要)
# pg_dbsu       : 为 postgres dbsu 设置操作系统用户sudo
# pg_install    : 安装 postgres 包和扩展
#   - pg_pkg              : 安装 postgres 相关包
#   - pg_extension        : 仅安装 postgres 扩展
#   - pg_path             : 将 pgsql 版本 bin 链接到 /usr/pgsql
#   - pg_env              : 将 pgsql bin 添加到系统路径
# pg_dir        : 创建 postgres 目录并设置 fhs
# pg_util       : 复制工具脚本,设置别名和环境
#   - pg_bin              : 同步 postgres 工具脚本 /pg/bin
#   - pg_alias            : 写入 /etc/profile.d/pg-alias.sh
#   - pg_psql             : 为 psql 创建 psqlrc 文件
#   - pg_dummy            : 创建 dummy 占位文件
# patroni       : 使用 patroni 引导 postgres
#   - pg_config           : 生成 postgres 配置
#   - pg_conf           : 生成 patroni 配置
#   - pg_systemd        : 生成 patroni systemd 配置
#   - pgbackrest_config : 生成 pgbackrest 配置
#   -  pg_cert            : 为 postgres 签发证书
#   -  pg_launch          : 启动 postgres 主服务器和副本
#   - pg_watchdog       : 授予 postgres watchdog 权限
#   - pg_primary        : 启动 patroni/postgres 主服务器
#   - pg_init           : 使用角色/模板初始化 pg 集群
#   - pg_pass           : 将 .pgpass 文件写入 pg 主目录
#   - pg_replica        : 启动 patroni/postgres 副本
#   - pg_hba            : 生成 pg HBA 规则
#   - patroni_reload    : 重新加载 patroni 配置
#   - pg_patroni        : 必要时暂停或删除 patroni
# pg_user       : 配置 postgres 业务用户
#   - pg_user_config      : 渲染创建用户的 sql
#   - pg_user_create      : 在 postgres 上创建用户
# pg_db         : 配置 postgres 业务数据库
#   - pg_db_config        : 渲染创建数据库的 sql
#   - pg_db_create        : 在 postgres 上创建数据库
# pg_backup               : 初始化 pgbackrest 仓库和基础备份
#   - pgbackrest_init     : 初始化 pgbackrest 仓库
#   - pgbackrest_backup   : 引导后进行初始备份
# pgbouncer     : 与 postgres 一起部署 pgbouncer 边车
#   - pgbouncer_clean     : 清理现有的 pgbouncer
#   - pgbouncer_dir       : 创建 pgbouncer 目录
#   - pgbouncer_config    : 生成 pgbouncer 配置
#       -  pgbouncer_svc    : 生成 pgbouncer systemd 配置
#       -  pgbouncer_ini    : 生成 pgbouncer 主配置
#       -  pgbouncer_hba    : 生成 pgbouncer hba 配置
#       -  pgbouncer_db     : 生成 pgbouncer 数据库配置
#       -  pgbouncer_user   : 生成 pgbouncer 用户配置
#   -  pgbouncer_launch   : 启动 pgbouncer 池化服务
#   -  pgbouncer_reload   : 重新加载 pgbouncer 配置
# pg_vip        : 使用 vip-manager 将 vip 绑定到 pgsql 主服务器
#   - pg_vip_config       : 为 vip-manager 生成配置
#   - pg_vip_launch       : 启动 vip-manager 绑定 vip
# pg_dns        : 将 dns 名称注册到 infra dnsmasq
#   - pg_dns_ins          : 注册 pg 实例名称
#   - pg_dns_cls          : 注册 pg 集群名称
# pg_service    : 使用 haproxy 公开 pgsql 服务
#   - pg_service_config   : 为 pg 服务生成本地 haproxy 配置
#   - pg_service_reload   : 使用 haproxy 公开 postgres 服务
# pg_exporter   : 使用 haproxy 公开 pgsql 服务
#   - pg_exporter_config  : 配置 pg_exporter 和 pgbouncer_exporter
#   - pg_exporter_launch  : 启动 pg_exporter
#   - pgbouncer_exporter_launch : 启动 pgbouncer 导出器
# pg_register   : 将 postgres 注册到 pigsty 基础设施
#   - register_prometheus : 将 pg 注册为 prometheus 监控目标
#   - register_grafana    : 将 pg 数据库注册为 grafana 数据源

以下管理任务使用到了此剧本

一些关于本剧本的注意事项

单独针对某一集群从库执行此剧本时,用户应当确保 集群主库已经完成初始化!

集群扩容时,如果Patroni拉起从库的时间过长,Ansible剧本可能会因为超时而中止。

  • 典型错误信息为:wait for postgres/patroni replica 任务执行很长时间后中止
  • 但制作从库的进程会继续,例如制作从库需超过1天的场景,后续处理请参考 FAQ:制作从库失败。

pgsql-rm.yml

剧本 pgsql-rm.yml 用于移除PostgreSQL集群,或移除某个实例。

下面是使用此剧本移除沙箱环境中 PostgreSQL 集群的过程:

asciicast

本剧本包含以下子任务

# register       : 在 prometheus、grafana、nginx 中移除注册
#   - prometheus : 从 prometheus 移除监控目标
#   - grafana    : 从 grafana 移除数据源
# dns            : 移除 INFRA节点上 DNSMASQ 的 pg dns 记录
# vip            : 移除 vip-manager,与绑定在集群主库上的 VIP
# pg_service     : 从 haproxy 上移除 PostgreSQL 服务定义并重载生效
# pg_exporter    : 移除 pg_exporter 和 pgbouncer_exporter 监控组件
# pgbouncer      : 移除 pgbouncer 连接池中间件
# postgres       : 移除 postgres 实例数据库实例
#   - pg_replica : 移除所有从库
#   - pg_primary : 最后移除主库
#   - dcs        : 从 dcs:etcd 移除元数据
# pg_data        : 移除 PostgreSQL 数据目录(使用 `pg_clean=false` 禁用)
# pgbackrest     : 移除主实例时,一并移除 PostgreSQL 备份(使用 `pgbackrest_clean=false` 禁用)
# pg_pkg         : 移除 PostgreSQL 软件包(使用 `pg_uninstall=true` 启用)

本剧本可以使用一些命令行参数影响其行为:

./pgsql-rm.yml -l pg-test     # 移除集群 `pg-test`
    -e pg_clean=true          # 是否一并移除 PostgreSQL 数据库目录?默认移除数据目录。
    -e pgbackrest_clean=true  # 是否一并移除 PostgreSQL 备份?(只针对主库执行时生效),默认移除备份数据。
    -e pg_uninstall=false     # 默认不会卸载 PostgreSQL 软件包,需要显式指定此参数才会卸载。
    -e pg_safeguard=false     # 防误删保险默认不打开,如果打开,可以在这里用命令行参数强行覆盖。

以下管理任务使用到了此剧本

一些关于本剧本的注意事项

请不要直接对还有从库的集群主库单独直接执行此剧本

  • 否则抹除主库后,其余从库会自动触发高可用自动故障切换。
  • 总是先下线所有从库后,再下线主库,当一次性下线整个集群时不需要操心此问题。

实例下线后请刷新集群服务

  • 当您从集群中下线掉某一个从库实例时,它仍然存留于在负载均衡器的配置文件中。
  • 因为任何健康检查都无法通过,所以下线后的实例不会对集群产生影响。
  • 但您应当在恰当的时间点 重载服务,确保生产环境与配置清单的一致性。

pgsql-user.yml

剧本 pgsql-user.yml 用于在现有的PostgreSQL集群中添加新的业务用户

详情请参考:管理SOP:创建用户


pgsql-db.yml

剧本 pgsql-db.yml 用于在现有的PostgreSQL集群中添加新的业务数据库

详情请参考:管理SOP:创建数据库


pgsql-monitor.yml

剧本 pgsql-monitor.yml 用于将远程postgres实例纳入监控中

详情请参考:管理SOP:监控现有PG


pgsql-migration.yml

剧本 pgsql-migration.yml 用于为现有的PostgreSQL集群生成迁移手册和脚本

详情请参考:管理SOP:迁移数据库集群

10 - 管理预案

Pigsty 中常用的 PostgreSQL 管理预案,用于维护生产环境中的数据库集群。

本文整理了 Pigsty 中常用的 PostgreSQL 管理预案,用于维护生产环境中的数据库集群。

这里是一些常见 PostgreSQL 管理任务的 SOP 预案:


命令速查

PGSQL 剧本与快捷方式:

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

Patroni 管理命令与快捷方式:

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

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

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

使用 Systemd 管理系统组件的命令:

systemctl stop patroni                  # 启动 停止 重启 重载
systemctl stop pgbouncer                # 启动 停止 重启 重载
systemctl stop pg_exporter              # 启动 停止 重启 重载
systemctl stop pgbouncer_exporter       # 启动 停止 重启 重载
systemctl stop node_exporter            # 启动 停止 重启
systemctl stop haproxy                  # 启动 停止 重启 重载
systemctl stop vip-manager              # 启动 停止 重启 重载
systemctl stop postgres                 # 仅当 patroni_mode == 'remove' 时使用这个服务

创建集群

要创建一个新的Postgres集群,请首先在配置清单中定义,然后进行初始化:

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

请注意,PGSQL 模块需要在 Pigsty 纳管的节点上安装,请先使用 bin/node-add 纳管节点。

示例:创建集群

asciicast


创建用户

要在现有的Postgres集群上创建一个新的业务用户,请将用户定义添加到 all.children.<cls>.pg_users,然后使用以下命令将其创建:

bin/pgsql-user <cls> <username>   # ./pgsql-user.yml -l <cls> -e username=<username>
示例:创建业务用户

asciicast


创建数据库

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

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

注意:如果数据库指定了一个非默认的属主,该属主用户应当已存在,否则您必须先创建用户

示例:创建业务数据库

asciicast


重载服务

服务是 PostgreSQL 对外提供能力的访问点(PGURL可达),由主机节点上的 HAProxy 对外暴露。

当集群成员发生变化时使用此任务,例如:添加移除副本,主从切换/故障转移 / 暴露新服务,或更新现有服务的配置(例如,LB权重)

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

bin/pgsql-svc <cls>               # pgsql.yml -l <cls> -t pg_service -e pg_reload=true
bin/pgsql-svc <cls> [ip...]       # pgsql.yml -l ip... -t pg_service -e pg_reload=true
示例:重载PG服务以踢除一个实例

asciicast


重载HBA

当您的 Postgres/Pgbouncer HBA 规则发生更改时,您 可能 需要重载 HBA 以应用更改。

如果您有任何特定于角色的 HBA 规则,或者在IP地址段中引用了集群成员的别名,那么当主从切换/集群扩缩容后也可能需要重载HBA。

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

bin/pgsql-hba <cls>               # pgsql.yml -l <cls> -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true
bin/pgsql-hba <cls> [ip...]       # pgsql.yml -l ip... -t pg_hba,pg_reload,pgbouncer_hba,pgbouncer_reload -e pg_reload=true
示例:重载集群 HBA 规则

asciicast


配置集群

要更改现有的 Postgres 集群配置,您需要在管理节点上使用管理员用户(安装Pigsty的用户,nopass ssh/sudo)发起控制命令:

另一种方式是在数据库集群中的任何节点上,使用 dbsu (默认为 postgres) ,也可以执行管理命令,但只能管理本集群。

pg edit-config <cls>              # interactive config a cluster with patronictl

更改 patroni 参数和 postgresql.parameters,根据提示保存并应用更改即可。

示例:非交互式方式配置集群

您可以跳过交互模式,并使用 -p 选项覆盖 postgres 参数,例如:

pg edit-config -p log_min_duration_statement=1000 pg-test
pg edit-config --force -p shared_preload_libraries='timescaledb, pg_cron, pg_stat_statements, auto_explain'
示例:使用 Patroni REST API 更改集群配置

您还可以使用 Patroni REST API 以非交互式方式更改配置,例如:

$ curl -s 10.10.10.11:8008/config | jq .  # get current config
$ curl -u 'postgres:Patroni.API' \
        -d '{"postgresql":{"parameters": {"log_min_duration_statement":200}}}' \
        -s -X PATCH http://10.10.10.11:8008/config | jq .

注意:Patroni 敏感API(例如重启等) 访问仅限于从基础设施/管理节点发起,并且有 HTTP 基本认证(用户名/密码)以及可选的 HTTPS 保护。

示例:使用 patronictl 配置集群

asciicast


添加实例

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

bin/node-add <ip>                 # 将节点 <ip> 纳入 Pigsty 管理                
bin/pgsql-add <cls> <ip>          # 初始化 <ip> ,作为集群 <cls> 的新从库

这将会把节点 <ip> 添加到 pigsty 并将其初始化为集群 <cls> 的一个副本。

集群服务将会重新加载以接纳新成员。

示例:为 pg-test 添加从库

asciicast

例如,如果您想将 pg-test-3 / 10.10.10.13 添加到现有的集群 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 }

然后按如下方式应用更改:

bin/node-add          10.10.10.13   # 将节点添加到 pigsty
bin/pgsql-add pg-test 10.10.10.13   # 在 10.10.10.13 上为集群 pg-test 初始化新的副本

这与集群初始化相似,但只在单个实例上工作:

[ OK ] 初始化实例  10.10.10.11 到 pgsql 集群 'pg-test' 中:
[WARN]   提醒:先将节点添加到 pigsty 中,然后再安装模块 'pgsql'
[HINT]     $ bin/node-add  10.10.10.11  # 除 infra 节点外,先运行此命令
[WARN]   从集群初始化实例:
[ OK ]     $ ./pgsql.yml -l '10.10.10.11,&pg-test'
[WARN]   重新加载现有实例上的 pg_service:
[ OK ]     $ ./pgsql.yml -l 'pg-test,!10.10.10.11' -t pg_service

移除实例

若要从现有的 PostgreSQL 集群中移除副本:

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

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

示例:从 pg-test 移除从库

asciicast

例如,如果您想从现有的集群 pg-test 中移除 pg-test-3 / 10.10.10.13

bin/pgsql-rm pg-test 10.10.10.13  # 从 pg-test 中移除 pgsql 实例 10.10.10.13
bin/node-rm  10.10.10.13          # 从 pigsty 中移除该节点(可选)
vi pigsty.yml                     # 从目录中移除实例定义
bin/pgsql-svc pg-test             # 刷新现有实例上的 pg_service,以从负载均衡器中踢除已移除的实例
[ OK ]'pg-test' 移除 10.10.10.13 的 pgsql 实例:
[WARN]   从集群中移除实例:
[ OK ]     $ ./pgsql-rm.yml -l '10.10.10.13,&pg-test'

并从配置清单中移除实例定义:

pg-test:
  hosts:
    10.10.10.11: { pg_seq: 1, pg_role: primary }
    10.10.10.12: { pg_seq: 2, pg_role: replica }
    10.10.10.13: { pg_seq: 3, pg_role: replica } # <--- 执行后移除此行
  vars: { pg_cluster: pg-test }

最后,您可以重载PG服务并从负载均衡器中踢除已移除的实例:

bin/pgsql-svc pg-test             # 重载 pg-test 上的服务

下线集群

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

bin/pgsql-rm <cls>                # ./pgsql-rm.yml -l <cls>
示例:移除集群

asciicast

示例:强制移除集群

注意:如果为这个集群配置了pg_safeguard(或全局设置为 true),pgsql-rm.yml 将中止,以避免意外移除集群。

您可以使用 playbook 命令行参数明确地覆盖它,以强制执行清除:

./pgsql-rm.yml -l pg-meta -e pg_safeguard=false    # 强制移除 pg 集群 pg-meta

主动切换

您可以使用 patroni 命令行工具执行 PostgreSQL 集群的切换操作。

pg switchover <cls>   # 交互模式,您可以使用下面的参数组合直接跳过此交互向导
pg switchover --leader pg-test-1 --candidate=pg-test-2 --scheduled=now --force pg-test
示例:pg-test 主从切换

asciicast

$ pg switchover pg-test
Master [pg-test-1]:
Candidate ['pg-test-2', 'pg-test-3'] []: pg-test-2
When should the switchover take place (e.g. 2022-12-26T07:39 )  [now]: now
Current cluster topology
+ Cluster: pg-test (7181325041648035869) -----+----+-----------+-----------------+
| Member    | Host        | Role    | State   | TL | Lag in MB | Tags            |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-1 | 10.10.10.11 | Leader  | running |  1 |           | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-2 | 10.10.10.12 | Replica | running |  1 |         0 | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-3 | 10.10.10.13 | Replica | running |  1 |         0 | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
Are you sure you want to switchover cluster pg-test, demoting current master pg-test-1? [y/N]: y
2022-12-26 06:39:58.02468 Successfully switched over to "pg-test-2"
+ Cluster: pg-test (7181325041648035869) -----+----+-----------+-----------------+
| Member    | Host        | Role    | State   | TL | Lag in MB | Tags            |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-1 | 10.10.10.11 | Replica | stopped |    |   unknown | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-2 | 10.10.10.12 | Leader  | running |  1 |           | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+
| pg-test-3 | 10.10.10.13 | Replica | running |  1 |         0 | clonefrom: true |
|           |             |         |         |    |           | conf: tiny.yml  |
|           |             |         |         |    |           | spec: 1C.2G.50G |
|           |             |         |         |    |           | version: '15'   |
+-----------+-------------+---------+---------+----+-----------+-----------------+

要通过 Patroni API 来执行此操作(例如,在指定时间将主库从 2号实例 切换到 1号实例)

curl -u 'postgres:Patroni.API' \
  -d '{"leader":"pg-test-2", "candidate": "pg-test-1","scheduled_at":"2022-12-26T14:47+08"}' \
  -s -X POST http://10.10.10.11:8008/switchover

无论是主动切换还是故障切换,您都需要在集群成员身份发生变化后,重新刷新服务与HBA规则。您应当在变更发生后及时(例如几个小时,一天内),完成此操作:

bin/pgsql-svc <cls>
bin/pgsql-hba <cls>

备份集群

使用 pgBackRest 创建备份,需要以本地 dbsu (默认为 postgres)的身份运行以下命令:

pg-backup       # 执行备份,如有必要,执行增量或全量备份
pg-backup full  # 执行全量备份
pg-backup diff  # 执行差异备份
pg-backup incr  # 执行增量备份
pb info         # 打印备份信息 (pgbackrest info)

参阅备份恢复获取更多信息。

示例:创建备份

asciicast

示例:创建定时备份任务

您可以将 crontab 添加到 node_crontab 以指定您的备份策略。

# 每天凌晨1点做一次全备份
- '00 01 * * * postgres /pg/bin/pg-backup full'

# 周一凌晨1点进全量备份,其他工作日进行增量备份
- '00 01 * * 1 postgres /pg/bin/pg-backup full'
- '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

恢复集群

要将集群恢复到先前的时间点 (PITR),请以本地 dbsu 用户(默认为postgres)运行 Pigsty 提供的辅助脚本 pg-pitr

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

该命令会输出操作手册,请按照说明进行操作。查看备份恢复-PITR获取详细信息。

示例:使用原始pgBackRest命令进行 PITR
# 恢复到最新可用的点(例如硬件故障)
pgbackrest --stanza=pg-meta restore

# PITR 到特定的时间点(例如意外删除表)
pgbackrest --stanza=pg-meta --type=time --target="2022-11-08 10:58:48" \
   --target-action=promote restore

# 恢复特定的备份点,然后提升(或暂停|关闭)
pgbackrest --stanza=pg-meta --type=immediate --target-action=promote \
  --set=20221108-105325F_20221108-105938I restore

添加软件

要添加新版本的 RPM 包,你需要将它们加入到 repo_packagesrepo_url_packages 中。

使用 ./infra.yml -t repo_build 子任务在 Infra 节点上重新构建本地软件仓库。然后,你可以使用 ansiblepackage 模块安装这些包:

ansible pg-test -b -m package -a "name=pg_cron_15,topn_15,pg_stat_monitor_15*"  # 使用 ansible 安装一些包
示例:手动更本地新软件源中的包
# 在基础设施/管理节点上添加上游软件仓库,然后手工下载所需的软件包
cd ~/pigsty; ./infra.yml -t repo_upstream,repo_cache # 添加上游仓库(互联网)
cd /www/pigsty;  repotrack "some_new_package_name"   # 下载最新的 RPM 包

# 更新本地软件仓库元数据
cd ~/pigsty; ./infra.yml -t repo_create              # 重新创建本地软件仓库
./node.yml -t node_repo                              # 刷新所有节点上的 YUM/APT 缓存

# 也可以使用 Ansible 手工刷新节点上的 YUM/APT 缓存
ansible all -b -a 'yum clean all'                    # 清理节点软件仓库缓存
ansible all -b -a 'yum makecache'                    # 从新的仓库重建yum/apt缓存
ansible all -b -a 'apt clean'                        # 清理 APT 缓存(Ubuntu/Debian)
ansible all -b -a 'apt update'                       # 重建 APT 缓存(Ubuntu/Debian)

例如,你可以使用以下方式安装或升级包:

ansible pg-test -b -m package -a "name=postgresql15* state=latest"

安装扩展

如果你想在 PostgreSQL 集群上安装扩展,请将它们加入到 pg_extensions 中,并执行:

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

一部分扩展需要在 shared_preload_libraries 中加载后才能生效。你可以将它们加入到 pg_libs 中,或者配置一个已有的集群。

最后,在集群的主库上执行 CREATE EXTENSION <extname>; 来完成扩展的安装。

示例:在 pg-test 集群上安装 pg_cron 扩展
ansible pg-test -b -m package -a "name=pg_cron_15"          # 在所有节点上安装 pg_cron 包
# 将 pg_cron 添加到 shared_preload_libraries 中
pg edit-config --force -p shared_preload_libraries='timescaledb, pg_cron, pg_stat_statements, auto_explain'
pg restart --force pg-test                                  # 重新启动集群
psql -h pg-test -d postgres -c 'CREATE EXTENSION pg_cron;'  # 在主库上安装 pg_cron

更多细节,请参考PGSQL扩展安装


小版本升级

要执行小版本的服务器升级/降级,您首先需要在本地软件仓库中添加软件:最新的PG小版本 RPM/DEB。

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

ansible <cls> -b -a "yum upgrade/downgrade -y <pkg>"    # 升级/降级软件包
pg restart --force <cls>                                # 重启集群
示例:将PostgreSQL 15.2降级到15.1

将15.1的包添加到软件仓库并刷新节点的 yum/apt 缓存:

cd ~/pigsty; ./infra.yml -t repo_upstream               # 添加上游仓库
cd /www/pigsty; repotrack postgresql15-*-15.1           # 将15.1的包添加到yum仓库
cd ~/pigsty; ./infra.yml -t repo_create                 # 重建仓库元数据
ansible pg-test -b -a 'yum clean all'                   # 清理节点仓库缓存
ansible pg-test -b -a 'yum makecache'                   # 从新仓库重新生成yum缓存

# 对于 Ubutnu/Debian 用户,使用 apt 替换 yum
ansible pg-test -b -a 'apt clean'                       # 清理节点仓库缓存
ansible pg-test -b -a 'apt update'                      # 从新仓库重新生成apt缓存

执行降级并重启集群:

ansible pg-test -b -a "yum downgrade -y postgresql15*"  # 降级软件包)
pg restart --force pg-test                              # 重启整个集群以完成升级
示例:将PostgreSQL 15.1升级回15.2

这次我们采用滚动方式升级:

ansible pg-test -b -a "yum upgrade -y postgresql15*"    # 升级软件包(或 apt upgrade)
ansible pg-test -b -a '/usr/pgsql/bin/pg_ctl --version' # 检查二进制版本是否为15.2
pg restart --role replica --force pg-test               # 重启从库
pg switchover --leader pg-test-1 --candidate=pg-test-2 --scheduled=now --force pg-test    # 切换主从
pg restart --role primary --force pg-test               # 重启主库

大版本升级

实现大版本升级的最简单办法是:创建一个使用新版本的新集群,然后通过逻辑复制,蓝绿部署,并进行在线迁移

您也可以进行原地大版本升级,当您只使用数据库内核本身时,这并不复杂,使用 PostgreSQL 自带的 pg_upgrade 即可:

假设您想将 PostgreSQL 大版本从 14 升级到 15,您首先需要在仓库中添加软件,并确保两个大版本两侧安装的核心扩展插件也具有相同的版本号。

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

11 - 访问控制

Pigsty 提供的默认角色系统与权限模型

Pigsty 提供了一套开箱即用的,基于角色系统权限系统的访问控制模型。

权限控制很重要,但很多用户做不好。因此 Pigsty 提供了一套开箱即用的精简访问控制模型,为您的集群安全性提供一个兜底。


角色系统

Pigsty 默认的角色系统包含四个默认角色和四个默认用户

角色名称 属性 所属 描述
dbrole_readonly NOLOGIN 角色:全局只读访问
dbrole_readwrite NOLOGIN dbrole_readonly 角色:全局读写访问
dbrole_admin NOLOGIN pg_monitor,dbrole_readwrite 角色:管理员/对象创建
dbrole_offline NOLOGIN 角色:受限的只读访问
postgres SUPERUSER 系统超级用户
replicator REPLICATION pg_monitor,dbrole_readonly 系统复制用户
dbuser_dba SUPERUSER dbrole_admin pgsql 管理用户
dbuser_monitor pg_monitor pgsql 监控用户

这些角色与用户的详细定义如下所示:

pg_default_roles:                 # 全局默认的角色与系统用户
  - { name: dbrole_readonly  ,login: false ,comment: role for global read-only access     }
  - { name: dbrole_offline   ,login: false ,comment: role for restricted read-only access }
  - { name: dbrole_readwrite ,login: false ,roles: [dbrole_readonly] ,comment: role for global read-write access }
  - { name: dbrole_admin     ,login: false ,roles: [pg_monitor, dbrole_readwrite] ,comment: role for object creation }
  - { name: postgres     ,superuser: true  ,comment: system superuser }
  - { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly] ,comment: system replicator }
  - { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 ,comment: pgsql admin user }
  - { name: dbuser_monitor ,roles: [pg_monitor] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

默认角色

Pigsty 中有四个默认角色:

  • 业务只读 (dbrole_readonly): 用于全局只读访问的角色。如果别的业务想要此库只读访问权限,可以使用此角色。
  • 业务读写 (dbrole_readwrite): 用于全局读写访问的角色,主属业务使用的生产账号应当具有数据库读写权限
  • 业务管理员 (dbrole_admin): 拥有DDL权限的角色,通常用于业务管理员,或者需要在应用中建表的场景(比如各种业务软件)
  • 离线只读访问 (dbrole_offline): 受限的只读访问角色(只能访问 offline 实例,通常是个人用户,ETL工具账号)

默认角色在 pg_default_roles 中定义,除非您确实知道自己在干什么,建议不要更改默认角色的名称。

- { name: dbrole_readonly  , login: false , comment: role for global read-only access  }                            # 生产环境的只读角色
- { name: dbrole_offline ,   login: false , comment: role for restricted read-only access (offline instance) }      # 受限的只读角色
- { name: dbrole_readwrite , login: false , roles: [dbrole_readonly], comment: role for global read-write access }  # 生产环境的读写角色
- { name: dbrole_admin , login: false , roles: [pg_monitor, dbrole_readwrite] , comment: role for object creation } # 生产环境的 DDL 更改角色

默认用户

Pigsty 也有四个默认用户(系统用户):

  • 超级用户 (postgres),集群的所有者和创建者,与操作系统 dbsu 名称相同。
  • 复制用户 (replicator),用于主-从复制的系统用户。
  • 监控用户 (dbuser_monitor),用于监控数据库和连接池指标的用户。
  • 管理用户 (dbuser_dba),执行日常操作和数据库更改的管理员用户。

这4个默认用户的用户名/密码通过4对专用参数进行定义,并在很多地方引用:

在生产部署中记得更改这些密码,不要使用默认值!

pg_dbsu: postgres                             # 数据库超级用户名,这个用户名建议不要修改。
pg_dbsu_password: ''                          # 数据库超级用户密码,这个密码建议留空!禁止dbsu密码登陆。
pg_replication_username: replicator           # 系统复制用户名
pg_replication_password: DBUser.Replicator    # 系统复制密码,请务必修改此密码!
pg_monitor_username: dbuser_monitor           # 系统监控用户名
pg_monitor_password: DBUser.Monitor           # 系统监控密码,请务必修改此密码!
pg_admin_username: dbuser_dba                 # 系统管理用户名
pg_admin_password: DBUser.DBA                 # 系统管理密码,请务必修改此密码!

如果您修改默认用户的参数,在 pg_default_roles 中修改相应的角色定义即可:

- { name: postgres     ,superuser: true                                          ,comment: system superuser }
- { name: replicator ,replication: true  ,roles: [pg_monitor, dbrole_readonly]   ,comment: system replicator }
- { name: dbuser_dba   ,superuser: true  ,roles: [dbrole_admin]  ,pgbouncer: true ,pool_mode: session, pool_connlimit: 16 , comment: pgsql admin user }
- { name: dbuser_monitor   ,roles: [pg_monitor, dbrole_readonly] ,pgbouncer: true ,parameters: {log_min_duration_statement: 1000 } ,pool_mode: session ,pool_connlimit: 8 ,comment: pgsql monitor user }

权限系统

Pigsty 拥有一套开箱即用的权限模型,该模型与默认角色一起配合工作。

  • 所有用户都可以访问所有模式。
  • 只读用户(dbrole_readonly)可以从所有表中读取数据。(SELECT,EXECUTE)
  • 读写用户(dbrole_readwrite)可以向所有表中写入数据并运行 DML。(INSERT,UPDATE,DELETE)。
  • 管理员用户(dbrole_admin)可以创建对象并运行 DDL(CREATE,USAGE,TRUNCATE,REFERENCES,TRIGGER)。
  • 离线用户(dbrole_offline)类似只读用户,但访问受到限制,只允许访问离线实例pg_role = 'offline'pg_offline_query = true
  • 由管理员用户创建的对象将具有正确的权限。
  • 所有数据库上都配置了默认权限,包括模板数据库。
  • 数据库连接权限由数据库定义管理。
  • 默认撤销PUBLIC在数据库和public模式下的CREATE权限。

对象权限

数据库中新建对象的默认权限由参数 pg_default_privileges 所控制:

- GRANT USAGE      ON SCHEMAS   TO dbrole_readonly
- GRANT SELECT     ON TABLES    TO dbrole_readonly
- GRANT SELECT     ON SEQUENCES TO dbrole_readonly
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_readonly
- GRANT USAGE      ON SCHEMAS   TO dbrole_offline
- GRANT SELECT     ON TABLES    TO dbrole_offline
- GRANT SELECT     ON SEQUENCES TO dbrole_offline
- GRANT EXECUTE    ON FUNCTIONS TO dbrole_offline
- GRANT INSERT     ON TABLES    TO dbrole_readwrite
- GRANT UPDATE     ON TABLES    TO dbrole_readwrite
- GRANT DELETE     ON TABLES    TO dbrole_readwrite
- GRANT USAGE      ON SEQUENCES TO dbrole_readwrite
- GRANT UPDATE     ON SEQUENCES TO dbrole_readwrite
- GRANT TRUNCATE   ON TABLES    TO dbrole_admin
- GRANT REFERENCES ON TABLES    TO dbrole_admin
- GRANT TRIGGER    ON TABLES    TO dbrole_admin
- GRANT CREATE     ON SCHEMAS   TO dbrole_admin

由管理员新创建的对象,默认将会上述权限。使用 \ddp+ 可以查看这些默认权限:

类型 访问权限
函数 =X
dbrole_readonly=X
dbrole_offline=X
dbrole_admin=X
模式 dbrole_readonly=U
dbrole_offline=U
dbrole_admin=UC
序列号 dbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=wU
dbrole_admin=rwU
dbrole_readonly=r
dbrole_offline=r
dbrole_readwrite=awd
dbrole_admin=arwdDxt

默认权限

ALTER DEFAULT PRIVILEGES 允许您设置将来创建的对象的权限。 它不会影响已经存在对象的权限,也不会影响非管理员用户创建的对象。

在 Pigsty 中,默认权限针对三个角色进行定义:

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_dbsu }} {{ priv }};
{% endfor %}

{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE {{ pg_admin_username }} {{ priv }};
{% endfor %}

-- 对于其他业务管理员而言,它们应当在执行 DDL 前执行 SET ROLE dbrole_admin,从而使用对应的默认权限配置。
{% for priv in pg_default_privileges %}
ALTER DEFAULT PRIVILEGES FOR ROLE "dbrole_admin" {{ priv }};
{% endfor %}

这些内容将会被 PG集群初始化模板 pg-init-template.sql 所使用,在集群初始化的过程中渲染并输出至 /pg/tmp/pg-init-template.sql。 该命令会在 template1postgres 数据库中执行,新创建的数据库会通过模板 template1 继承这些默认权限配置。

也就是说,为了维持正确的对象权限,您必须用管理员用户来执行 DDL,它们可以是:

  1. {{ pg_dbsu }},默认为 postgres
  2. {{ pg_admin_username }},默认为 dbuser_dba
  3. 授予了 dbrole_admin 角色的业务管理员用户(通过 SET ROLE 切换为 dbrole_admin 身份)。

使用 postgres 作为全局对象所有者是明智的。如果您希望以业务管理员用户身份创建对象,创建之前必须使用 SET ROLE dbrole_admin 来维护正确的权限。

当然,您也可以在数据库中通过 ALTER DEFAULT PRIVILEGE FOR ROLE <some_biz_admin> XXX 来显式对业务管理员授予默认权限。


数据库权限

在 Pigsty 中,数据库(Database)层面的权限在数据库定义中被涵盖。

数据库有三个级别的权限:CONNECTCREATETEMP,以及一个特殊的’权限’:OWNERSHIP

- name: meta         # 必选,`name` 是数据库定义中唯一的必选字段
  owner: postgres    # 可选,数据库所有者,默认为 postgres
  allowconn: true    # 可选,是否允许连接,默认为 true。显式设置 false 将完全禁止连接到此数据库
  revokeconn: false  # 可选,撤销公共连接权限。默认为 false,设置为 true 时,属主和管理员之外用户的 CONNECT 权限会被回收
  • 如果 owner 参数存在,它作为数据库属主,替代默认的 {{ pg_dbsu }}(通常也就是postgres
  • 如果 revokeconnfalse,所有用户都有数据库的 CONNECT 权限,这是默认的行为。
  • 如果显式设置了 revokeconntrue
    • 数据库的 CONNECT 权限将从 PUBLIC 中撤销:普通用户无法连接上此数据库
    • CONNECT 权限将被显式授予 {{ pg_replication_username }}{{ pg_monitor_username }}{{ pg_admin_username }}
    • CONNECT 权限将 GRANT OPTION 被授予数据库属主,数据库属主用户可以自行授权其他用户连接权限。
  • revokeconn 选项可用于在同一个集群间隔离跨数据库访问,您可以为每个数据库创建不同的业务用户作为属主,并为它们设置 revokeconn 选项。
示例:数据库隔离
pg-infra:
  hosts:
    10.10.10.40: { pg_seq: 1, pg_role: primary }
    10.10.10.41: { pg_seq: 2, pg_role: replica , pg_offline_query: true }
  vars:
    pg_cluster: pg-infra
    pg_users:
      - { name: dbuser_confluence, password: mc2iohos , pgbouncer: true, roles: [ dbrole_admin ] }
      - { name: dbuser_gitlab, password: sdf23g22sfdd , pgbouncer: true, roles: [ dbrole_readwrite ] }
      - { name: dbuser_jira, password: sdpijfsfdsfdfs , pgbouncer: true, roles: [ dbrole_admin ] }
    pg_databases:
      - { name: confluence , revokeconn: true, owner: dbuser_confluence , connlimit: 100 }
      - { name: gitlab , revokeconn: true, owner: dbuser_gitlab, connlimit: 100 }
      - { name: jira , revokeconn: true, owner: dbuser_jira , connlimit: 100 }

CREATE权限

出于安全考虑,Pigsty 默认从 PUBLIC 撤销数据库上的 CREATE 权限,从 PostgreSQL 15 开始这也是默认行为。

数据库属主总是可以根据实际需要,来自行调整 CREATE 权限。

12 - 备份恢复

如何使用 pgBackRest 备份/恢复/PITR PostgreSQL 数据库集群

Pigsty 使用 pgBackRest 进行 PITR 备份和恢复。

对于硬件故障来说,基于物理复制的高可用故障切换可能会是最佳选择。而对于数据损坏(无论是机器还是人为错误),时间点恢复(PITR)则更为合适:它提供了对最坏情况的兜底。


备份

使用以下命令备份 PostgreSQL 数据库集群:

# stanza 是 pgbackrest 在同一个存储库中区别不同的集群的标识,默认 stanza 名称 = {{ pg_cluster }}
pgbackrest --stanza=${stanza} --type=full|diff|incr backup

# 你也可以在 pigsty 中使用 dbsu 执行以下命令 (/pg/bin/pg-backup) 进行备份
pg-backup       # 执行备份,如有必要,执行增量或全量备份
pg-backup full  # 执行全量备份
pg-backup diff  # 执行差异备份
pg-backup incr  # 执行增量备份

使用以下命令打印备份信息:

pb info   # pgbackrest info 打印备份信息
备份信息示例
$ pb info
stanza: pg-meta
    status: ok
    cipher: none

    db (current)
        wal archive min/max (14): 000000010000000000000001/000000010000000000000023

        full backup: 20221108-105325F
            timestamp start/stop: 2022-11-08 10:53:25 / 2022-11-08 10:53:29
            wal start/stop: 000000010000000000000004 / 000000010000000000000004
            database size: 96.6MB, database backup size: 96.6MB
            repo1: backup set size: 18.9MB, backup size: 18.9MB

        incr backup: 20221108-105325F_20221108-105938I
            timestamp start/stop: 2022-11-08 10:59:38 / 2022-11-08 10:59:41
            wal start/stop: 00000001000000000000000F / 00000001000000000000000F
            database size: 246.7MB, database backup size: 167.3MB
            repo1: backup set size: 35.4MB, backup size: 20.4MB
            backup reference list: 20221108-105325F

您也可以从监控系统查阅备份信息:PGCAT 实例 - 备份


恢复

以下命令可以用于 PostgreSQL 数据库集群的 恢复

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

Pigsty 提供的 pg-pitr 脚本会帮助您生成进行 PITR 指令,例如,如果您希望将当前集群状态回滚至 "2023-02-07 12:38:00+08"

$ pg-pitr -t "2023-02-07 12:38:00+08"
pgbackrest --stanza=pg-meta --type=time --target='2023-02-07 12:38:00+08' restore
执行pg-meta时间点恢复
[1. 停止PostgreSQL] ===========================================
   1.1 暂停Patroni(如果有任何副本)
       $ pg pause <cls>  # 暂停patroni自动故障转移
   1.2 关闭Patroni
       $ pt-stop         # sudo systemctl stop patroni
   1.3 关闭Postgres
       $ pg-stop         # pg_ctl -D /pg/data stop -m fast

[2. 执行PITR] ===========================================
   2.1 恢复备份
       $ pgbackrest --stanza=pg-meta --type=time --target='2023-02-07 12:38:00+08' restore
   2.2 启动PG以重放WAL
       $ pg-start        # pg_ctl -D /pg/data start
   2.3 验证并提升
     - 如果数据库内容正确,提升它以完成恢复,否则转到2.1
       $ pg-promote      # pg_ctl -D /pg/data promote

[3. 重启Patroni] ===========================================
   3.1 启动Patroni
       $ pt-start;        # sudo systemctl start patroni
   3.2 再次启用归档
       $ psql -c 'ALTER SYSTEM SET archive_mode = on; SELECT pg_reload_conf();'
   3.3 重启Patroni
       $ pt-restart      # sudo systemctl start patroni

[4. 恢复集群] ===========================================
   3.1 重新初始化所有副本(如果有任何副本)
       $ pg reinit <cls> <ins>
   3.2 恢复Patroni
       $ pg resume <cls> # 恢复patroni自动故障转移
   3.2 完整备份(可选)
       $ pg-backup full  # pgbackrest --stanza=pg-meta backup --type=full

安装说明依次操作,即可完成集群的恢复。


备份策略

您可以使用node_crontabpgbackrest_repo自定义备份策略。

本地备份仓库

例如,默认的pg-meta将每天凌晨1点进行一次全量备份。

node_crontab:  # 每天凌晨1点进行全量备份
  - '00 01 * * * postgres /pg/bin/pg-backup full'

使用默认的本地备份仓库保留策略,它最多保留两个完整备份,在备份过程中临时允许第三个备份存在。

pgbackrest_repo:                  # pgbackrest 仓库定义: https://pgbackrest.org/configuration.html#section-repository
  local:                          # 默认使用本地文件系统的 pgbackrest 备份仓库
    path: /pg/backup              # 本地备份目录,默认为`/pg/backup`
    retention_full_type: count    # 指定全量备份保留数量:2
    retention_full: 2             # 使用本地文件系统仓库时,最多保留2个完整备份,备份时临时允许3个

您的备份磁盘存储空间至少应该能放下最近三个数据库全量备份文件,以及这段期间(3天)内的WAL归档文件。

MinIO备份仓库

使用MinIO时,存储容量通常不是问题。您可以按需保留备份。例如,默认的 pg-test 样例集群将在星期一进行全量备份,其他工作日进行增量备份。

node_crontab:  # 周一凌晨1点进全量备份,其他工作日进行增量备份
  - '00 01 * * 1 postgres /pg/bin/pg-backup full'
  - '00 01 * * 2,3,4,5,6,7 postgres /pg/bin/pg-backup'

MinIO备份仓库可以使用14天的时间保留策略,这将保留最近两周内的备份。

pgbackrest_repo:                  # pgbackrest 仓库: https://pgbackrest.org/configuration.html#section-repository=
  minio:                          # pgbackrest 的可选minio仓库
    type: s3                      # minio 是s3兼容的,因此使用s3
    s3_endpoint: sss.pigsty       # minio终端域名,默认为`sss.pigsty`
    s3_region: us-east-1          # minio区域,默认为us-east-1,对minio来说没有用
    s3_bucket: pgsql              # minio桶名,默认为`pgsql`
    s3_key: pgbackrest            # pgbackrest的minio用户访问密钥
    s3_key_secret: S3User.Backup  # pgbackrest的minio用户密钥,这里请按实际情况填写密码,最好不要使用默认密码。
    s3_uri_style: path            # 使用路径风格的uri,而不是主机风格的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天的完整备份

13 - 迁移

如何将现有的 PostgreSQL 集群以最小的停机时间迁移至新的、由Pigsty管理的 PostgreSQL 集群?

Pigsty 内置了一个剧本 pgsql-migration.yml ,基于逻辑复制来实现在线数据库迁移。

通过预生成的自动化脚本,应用停机时间可以缩减到几秒内。但请注意,逻辑复制需要 PostgreSQL 10 以上的版本才能工作。

当然如果您有充足的停机时间预算,那么总是可以使用 pg_dump | psql 的方式进行停机迁移。


定义迁移任务

想要使用Pigsty提供的在线迁移剧本,您需要创建一个定义文件,来描述迁移任务的细节。

请查看任务定义文件示例作为参考: files/migration/pg-meta.yml

这个迁移任务要将 pg-meta.meta 在线迁移到 pg-test.test,前者称为 源集群(SRC), 后者称为 宿集群(DST)

pg-meta-1	10.10.10.10  --> pg-test-1	10.10.10.11 (10.10.10.12,10.10.10.13)

基于逻辑复制的迁移以数据库为单位,您需要指定需要迁移的数据库名称,以及数据库源宿集群主节点的 IP 地址,以及超级用户的连接信息。

---
#-----------------------------------------------------------------
# PG_MIGRATION
#-----------------------------------------------------------------
context_dir: ~/migration  # 迁移手册 & 脚本的放置目录
#-----------------------------------------------------------------
# SRC Cluster (旧集群)
#-----------------------------------------------------------------
src_cls: pg-meta      # 源集群名称                  <必填>
src_db: meta          # 源数据库名称                <必填>
src_ip: 10.10.10.10   # 源集群主 IP                <必填>
#src_pg: ''            # 如果定义,使用此作为源 dbsu pgurl 代替:
#                      # postgres://{{ pg_admin_username }}@{{ src_ip }}/{{ src_db }}
#                      # 例如: 'postgres://dbuser_dba:DBUser.DBA@10.10.10.10:5432/meta'
#sub_conn: ''          # 如果定义,使用此作为订阅连接字符串代替:
#                      # host={{ src_ip }} dbname={{ src_db }} user={{ pg_replication_username }}'
#                      # 例如: 'host=10.10.10.10 dbname=meta user=replicator password=DBUser.Replicator'
#-----------------------------------------------------------------
# DST Cluster (新集群)
#-----------------------------------------------------------------
dst_cls: pg-test      # 宿集群名称                  <必填>
dst_db: test          # 宿数据库名称                 <必填>
dst_ip: 10.10.10.11   # 宿集群主 IP                <必填>
#dst_pg: ''            # 如果定义,使用此作为目标 dbsu pgurl 代替:
#                      # postgres://{{ pg_admin_username }}@{{ dst_ip }}/{{ dst_db }}
#                      # 例如: 'postgres://dbuser_dba:DBUser.DBA@10.10.10.11:5432/test'
#-----------------------------------------------------------------
# PGSQL
#-----------------------------------------------------------------
pg_dbsu: postgres
pg_replication_username: replicator
pg_replication_password: DBUser.Replicator
pg_admin_username: dbuser_dba
pg_admin_password: DBUser.DBA
pg_monitor_username: dbuser_monitor
pg_monitor_password: DBUser.Monitor
#-----------------------------------------------------------------
...

默认情况下,源宿集群两侧的超级用户连接串会使用全局的管理员用户和各自主库的 IP 地址拼接而成,但您总是可以通过 src_pgdst_pg 参数来覆盖这些默认值。 同理,您也可以通过 sub_conn 参数来覆盖订阅连接串的默认值。


生成迁移计划

此剧本不会主动完成集群的迁移工作,但它会生成迁移所需的操作手册与自动化脚本。

默认情况下,你会在 ~/migration/pg-meta.meta 下找到迁移上下文目录。 按照 README.md 的说明,依次执行这些脚本,你就可以完成数据库迁移了!

# 激活迁移上下文:启用相关环境变量
. ~/migration/pg-meta.meta/activate

# 这些脚本用于检查 src 集群状态,并帮助在 pigsty 中生成新的集群定义
./check-user     # 检查 src 用户
./check-db       # 检查 src 数据库
./check-hba      # 检查 src hba 规则
./check-repl     # 检查 src 复制身份
./check-misc     # 检查 src 特殊对象

# 这些脚本用于在现有的 src 集群和由 pigsty 管理的 dst 集群之间建立逻辑复制,除序列外的数据将实时同步
./copy-schema    # 将模式复制到目标
./create-pub     # 在 src 上创建发布
./create-sub     # 在 dst 上创建订阅
./copy-progress  # 打印逻辑复制进度
./copy-diff      # 通过计数表快速比较 src 和 dst 的差异

# 这些脚本将在在线迁移中运行,该迁移将停止 src 集群,复制序列号(逻辑复制不复制序列号!)
./copy-seq [n]   # 同步序列号,如果给出了 n,则会应用额外的偏移

# 你必须根据你的访问方式(dns,vip,haproxy,pgbouncer等),将应用流量切换至新的集群!
#./disable-src   # 将 src 集群访问限制为管理节点和新集群(你的实现)
#./re-routing    # 从 SRC 到 DST 重新路由应用流量!(你的实现)

# 然后进行清理以删除订阅和发布
./drop-sub       # 迁移后在 dst 上删除订阅
./drop-pub       # 迁移后在 src 上删除发布

注意事项

如果担心拷贝序列号时出现主键冲突,您可以在拷贝时将所有序列号向前推进一段距离,例如 +1000 ,你可以使用 ./copy-seq 加一个参数 1000 来实现这一点。

你必须实现自己的 ./re-routing 脚本,以将你的应用流量从 src 路由到 dst。 因为我们不知道你的流量是如何路由的(例如 dns, VIP, haproxy 或 pgbouncer)。 当然,您也可以手动完成这项操作…

你可以实现一个 ./disable-src 脚本来限制应用对 src 集群的访问,这是可选的:如果你能确保所有应用流量都在 ./re-routing 中干净利落地切完,其实不用这一步。

但如果您有未知来源的各种访问无法梳理干净,那么最好使用更为彻底的方式:更改 HBA 规则并重新加载来实现(推荐),或者只是简单粗暴地关停源主库上的 postgres、pgbouncer 或 haproxy 进程。

14 - 监控接入

Pigsty监控系统架构概览,以及如何监控现存的 PostgreSQL 实例?

本文介绍了 Pigsty 的监控系统架构,包括监控指标,日志,与目标管理的方式。以及如何监控现有PG集群与远程 RDS服务


监控概览

Pigsty使用现代的可观测技术栈对 PostgreSQL 进行监控:

  • 使用 Grafana 进行指标可视化和 PostgreSQL 数据源。
  • 使用 Prometheus 来采集 PostgreSQL / Pgbouncer / Patroni / HAProxy / Node 的指标
  • 使用 Loki 来记录 PostgreSQL / Pgbouncer / Patroni / pgBackRest 以及主机组件的日志
  • Pigsty 提供了开箱即用的 Grafana 仪表盘,展示与 PostgreSQL 有关的方方面面。

监控指标

PostgreSQL 本身的监控指标完全由 pg_exporter 配置文件所定义:pg_exporter.yml 它将进一步被 Prometheus 记录规则和告警规则进行加工处理:files/prometheus/rules/pgsql.yml

Pigsty使用三个身份标签:clsinsip,它们将附加到所有指标和日志上。此外,Pgbouncer的监控指标,主机节点 NODE,与负载均衡器的监控指标也会被 Pigsty 所使用,并尽可能地使用相同的标签以便于关联分析。

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

日志

与 PostgreSQL 有关的日志由 promtail 负责收集,并发送至 infra 节点上的 Loki 日志存储/查询服务。

目标管理

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

# pg-meta-1 [primary] @ 10.10.10.10
- labels: { cls: pg-meta, ins: pg-meta-1, ip: 10.10.10.10 }
  targets:
    - 10.10.10.10:9630    # <--- pg_exporter 用于PostgreSQL指标
    - 10.10.10.10:9631    # <--- pg_exporter 用于pgbouncer指标
    - 10.10.10.10:8008    # <--- patroni指标(未启用 API SSL 时)

当全局标志 patroni_ssl_enabled 被设置时,patroni目标将被移动到单独的文件 /etc/prometheus/targets/patroni/<ins>.yml。 因为此时使用的是 https 抓取端点。当您监控RDS实例时,监控目标会被单独放置于: /etc/prometheus/targets/pgrds/ 目录下,并以集群为单位进行管理。

当使用 bin/pgsql-rmpgsql-rm.yml 移除集群时,Prometheus监控目标将被移除。您也可以手动移除它,或使用剧本里的子任务:

bin/pgmon-rm <cls|ins>    # 从所有infra节点中移除 prometheus 监控目标

远程 RDS 监控目标会被放置于 /etc/prometheus/targets/pgrds/<cls>.yml,它们是由 pgsql-monitor.yml 剧本或 bin/pgmon-add 脚本所创建的。


监控模式

Pigsty 提供三种监控模式,以适应不同的监控需求。

事项\等级 L1 L2 L3
名称 基础部署 托管部署 标准部署
英文 RDS MANAGED FULL
场景 只有连接串,例如RDS DB已存在,节点可管理 实例由 Pigsty 创建
PGCAT功能 ✅ 完整可用 ✅ 完整可用 ✅ 完整可用
PGSQL功能 ✅ 限PG指标 ✅ 限PG与节点指标 ✅ 完整功能
连接池指标 ❌ 不可用 ⚠️ 选装 ✅ 预装项
负载均衡器指标 ❌ 不可用 ⚠️ 选装 ✅ 预装项
PGLOG功能 ❌ 不可用 ⚠️ 选装 ✅ 预装项
PG Exporter ⚠️ 部署于Infra节点 ✅ 部署于DB节点 ✅ 部署于DB节点
Node Exporter ❌ 不部署 ✅ 部署于DB节点 ✅ 部署于DB节点
侵入DB节点 ✅ 无侵入 ⚠️ 安装Exporter ⚠️ 完全由Pigsty管理
监控现有实例 ✅ 可支持 ✅ 可支持 ❌ 仅用于Pigsty托管实例
监控用户与视图 人工创建 人工创建 Pigsty自动创建
部署使用剧本 bin/pgmon-add <cls> 部分执行 pgsql.ym/node.yml pgsql.yml
所需权限 Infra 节点可达的 PGURL DB节点ssh与sudo权限 DB节点ssh与sudo权限
功能概述 PGCAT + PGRDS 大部分功能 完整功能

由Pigsty完全管理的数据库会自动纳入监控,并拥有最好的监控支持,通常不需要任何配置。对于现有的 PostgreSQL 集群或者 RDS 服务,如果如果目标DB节点可以被Pigsty所管理(ssh可达,sudo可用),那么您可以考虑 托管部署,实现与 Pigsty 基本类似的监控管理体验。如果您只能通过PGURL(数据库连接串)的方式访问目标数据库,例如远程的RDS服务,则可以考虑使用 精简模式 监控目标数据库。


监控现有集群

如果目标DB节点可以被Pigsty所管理ssh可达且sudo可用),那么您可以使用 pgsql.yml 剧本中的pg_exporter任务, 使用与标准部署相同的的方式,在目标节点上部署监控组件:PG Exporter。您也可以使用该剧本的 pgbouncerpgbouncer_exporter 任务在已有实例节点上部署连接池及其监控。此外,您也可以使用 node.yml 中的 node_exporterhaproxypromtail 部署主机监控,负载均衡,日志收集组件。从而获得与原生Pigsty数据库实例完全一致的使用体验。

现有集群的定义方式与 Pigsty 所管理的集群定义方式完全相同,您只是选择性执行 pgsql.yml 剧本中的部分任务,而不是执行整个剧本。

./node.yml  -l <cls> -t node_repo,node_pkg           # 在主机节点上添加 INFRA节点的 YUM 源并安装软件包。
./node.yml  -l <cls> -t node_exporter,node_register  # 配置主机监控,并加入 Prometheus
./node.yml  -l <cls> -t promtail                     # 配置主机日志采集,并发送至 Loki
./pgsql.yml -l <cls> -t pg_exporter,pg_register      # 配置 PostgreSQL 监控,并注册至 Prometheus/Grafana

因为目标数据库集群已存在,所以您需要手工在目标数据库集群上创建监控用户、模式与扩展


监控RDS

如果您只能通过PGURL(数据库连接串)的方式访问目标数据库,那么可以参照这里的说明进行配置。在这种模式下,Pigsty 在 INFRA节点 上部署对应的 PG Exporter,抓取远端数据库指标信息。如下图所示:

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

在这种模式下,监控系统不会有主机,连接池,负载均衡器,高可用组件的相关指标,但数据库本身,以及数据目录(Catalog)中的实时状态信息仍然可用。Pigsty提供了两个专用的监控面板,专注于 PostgreSQL 本身的监控指标: PGRDS ClusterPGRDS Instance,总览与数据库内监控则复用现有监控面板。因为Pigsty不能管理您的RDS,所以用户需要在目标数据库上提前配置好监控对象

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

  1. 在目标上创建监控模式、用户和权限。详情请参考监控对象配置

  2. 在配置清单中声明集群。例如,假设我们想要监控“远端”的 pg-meta & pg-test 集群:

    infra:            # 代理、监控、警报等的infra集群..
      hosts: { 10.10.10.10: { infra_seq: 1 } }
      vars:           # 在组'infra'上为远程postgres RDS安装pg_exporter
        pg_exporters: # 在此列出所有远程实例,为k分配一个唯一的未使用的本地端口
          20001: { pg_cluster: pg-foo, pg_seq: 1, pg_host: 10.10.10.10 , pg_databases: [{ name: meta }] } # 注册 meta 数据库为 Grafana 数据源
    
          20002: { pg_cluster: pg-bar, pg_seq: 1, pg_host: 10.10.10.11 , pg_port: 5432 } # 几种不同的连接串拼接方法
          20003: { pg_cluster: pg-bar, pg_seq: 2, pg_host: 10.10.10.12 , pg_exporter_url: 'postgres://dbuser_monitor:DBUser.Monitor@10.10.10.12:5432/postgres?sslmode=disable'}
          20004: { pg_cluster: pg-bar, pg_seq: 3, pg_host: 10.10.10.13 , pg_monitor_username: dbuser_monitor, pg_monitor_password: DBUser.Monitor }
    

    其中, pg_databases 字段中所列出的数据库,将会被注册至 Grafana 中,成为一个 PostgreSQL 数据源,为 PGCAT 监控面板提供数据支持。如果您不想使用PGCAT,将注册数据库到Grafana中,只需要将 pg_databases 设置为空数组或直接留空即可。

    pigsty-monitor.jpg

  3. 执行添加监控命令:bin/pgmon-add <clsname>

    bin/pgmon-add pg-foo  # 将 pg-foo 集群纳入监控
    bin/pgmon-add pg-bar  # 将 pg-bar 集群纳入监控
    
  4. 要删除远程集群的监控目标,可以使用 bin/pgmon-rm <clsname>

    bin/pgmon-rm pg-foo  # 将 pg-foo 从 Pigsty 监控中移除
    bin/pgmon-rm pg-bar  # 将 pg-bar 从 Pigsty 监控中移除
    

您可以使用更多的参数来覆盖默认 pg_exporter 的选项,下面是一个使用 Pigsty 监控阿里云 RDS 与 PolarDB 的配置样例:

示例:监控阿里云 RDS for PostgreSQL 与 PolarDB

详情请参考:remote.yml

infra:            # 代理、监控、警报等的infra集群..
  hosts: { 10.10.10.10: { infra_seq: 1 } }
  vars:
    pg_exporters:   # 在此列出所有待监控的远程 RDS PG 实例

      20001:        # 分配一个唯一的未使用的本地端口,供本地监控 Agent 使用,这里是一个 PolarDB 的主库
        pg_cluster: pg-polar                  # RDS 集群名 (身份参数,手工指定分配监控系统内名称)
        pg_seq: 1                             # RDS 实例号 (身份参数,手工指定分配监控系统内名称)
        pg_host: pc-2ze379wb1d4irc18x.polardbpg.rds.aliyuncs.com # RDS 主机地址
        pg_port: 1921                         # RDS 端口(从控制台连接信息获取)
        pg_exporter_auto_discovery: true      # 禁用新数据库自动发现功能
        pg_exporter_include_database: 'test'  # 仅监控这个列表中的数据库(多个数据库用逗号分隔)
        pg_monitor_username: dbuser_monitor   # 监控用的用户名,覆盖全局配置
        pg_monitor_password: DBUser_Monitor   # 监控用的密码,覆盖全局配置
        pg_databases: [{ name: test }]        # 希望启用PGCAT的数据库列表,只要name字段即可,register_datasource设置为false则不注册。

      20002:       # 这是一个 PolarDB  从库
        pg_cluster: pg-polar                  # RDS 集群名 (身份参数,手工指定分配监控系统内名称)
        pg_seq: 2                             # RDS 实例号 (身份参数,手工指定分配监控系统内名称)
        pg_host: pe-2ze7tg620e317ufj4.polarpgmxs.rds.aliyuncs.com # RDS 主机地址
        pg_port: 1521                         # RDS 端口(从控制台连接信息获取)
        pg_exporter_auto_discovery: true      # 禁用新数据库自动发现功能
        pg_exporter_include_database: 'test,postgres'  # 仅监控这个列表中的数据库(多个数据库用逗号分隔)
        pg_monitor_username: dbuser_monitor   # 监控用的用户名
        pg_monitor_password: DBUser_Monitor   # 监控用的密码
        pg_databases: [ { name: test } ]        # 希望启用PGCAT的数据库列表,只要name字段即可,register_datasource设置为false则不注册。

      20004: # 这是一个基础版的单节点 RDS for PostgreSQL 实例
        pg_cluster: pg-rds                    # RDS 集群名 (身份参数,手工指定分配监控系统内名称)
        pg_seq: 1                             # RDS 实例号 (身份参数,手工指定分配监控系统内名称)
        pg_host: pgm-2zern3d323fe9ewk.pg.rds.aliyuncs.com  # RDS 主机地址
        pg_port: 5432                         # RDS 端口(从控制台连接信息获取)
        pg_exporter_auto_discovery: true      # 禁用新数据库自动发现功能
        pg_exporter_include_database: 'rds'   # 仅监控这个列表中的数据库(多个数据库用逗号分隔)
        pg_monitor_username: dbuser_monitor   # 监控用的用户名
        pg_monitor_password: DBUser_Monitor   # 监控用的密码
        pg_databases: [ { name: rds } ]       # 希望启用PGCAT的数据库列表,只要name字段即可,register_datasource设置为false则不注册。

      20005: # 这是一个高可用版的 RDS for PostgreSQL 集群主库
        pg_cluster: pg-rdsha                  # RDS 集群名 (身份参数,手工指定分配监控系统内名称)
        pg_seq: 1                             # RDS 实例号 (身份参数,手工指定分配监控系统内名称)
        pg_host: pgm-2ze3d35d27bq08wu.pg.rds.aliyuncs.com  # RDS 主机地址
        pg_port: 5432                         # RDS 端口(从控制台连接信息获取)
        pg_exporter_include_database: 'rds'   # 仅监控这个列表中的数据库(多个数据库用逗号分隔)
        pg_databases: [ { name: rds }, {name : test} ]  # 将这两个数据库纳入 PGCAT 管理,注册为 Grafana 数据源

      20006: # 这是一个高可用版的 RDS for PostgreSQL 集群只读实例(从库)
        pg_cluster: pg-rdsha                  # RDS 集群名 (身份参数,手工指定分配监控系统内名称)
        pg_seq: 2                             # RDS 实例号 (身份参数,手工指定分配监控系统内名称)
        pg_host: pgr-2zexqxalk7d37edt.pg.rds.aliyuncs.com  # RDS 主机地址
        pg_port: 5432                         # RDS 端口(从控制台连接信息获取)
        pg_exporter_include_database: 'rds'   # 仅监控这个列表中的数据库(多个数据库用逗号分隔)
        pg_databases: [ { name: rds }, {name : test} ]  # 将这两个数据库纳入 PGCAT 管理,注册为 Grafana 数据源

监控对象配置

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

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

  • 监控用户:默认使用的用户名为 dbuser_monitor, 该用户属于 pg_monitor 角色组,或确保具有相关视图访问权限。
  • 监控认证:默认使用密码访问,您需要确保HBA策略允许监控用户从管理机或DB节点本地访问数据库。
  • 监控模式:固定使用名称 monitor,用于安装额外的监控视图与扩展插件,非必选,但建议创建。
  • 监控扩展强烈建议启用PG自带的监控扩展 pg_stat_statements
  • 监控视图:监控视图是可选项,可以提供更多的监控指标支持。

监控用户

以Pigsty默认使用的监控用户dbuser_monitor为例,在目标数据库集群创建以下用户。

CREATE USER dbuser_monitor;                                       -- 创建监控用户
COMMENT ON ROLE dbuser_monitor IS 'system monitor user';          -- 监控用户备注
GRANT pg_monitor TO dbuser_monitor;                               -- 授予监控用户 pg_monitor 权限,否则一些指标将无法采集

ALTER USER dbuser_monitor PASSWORD 'DBUser.Monitor';              -- 按需修改监控用户密码(强烈建议修改!但请与Pigsty配置一致)
ALTER USER dbuser_monitor SET log_min_duration_statement = 1000;  -- 建议设置此参数,避免日志塞满监控慢查询
ALTER USER dbuser_monitor SET search_path = monitor,public;       -- 建议设置此参数,避免 pg_stat_statements 扩展无法生效

请注意,这里创建的监控用户与密码需要与 pg_monitor_usernamepg_monitor_password 保持一致。


监控认证

配置数据库 pg_hba.conf 文件,添加以下规则以允许监控用户从本地,以及管理机使用密码访问所有数据库。

# allow local role monitor with password
local   all  dbuser_monitor                    md5
host    all  dbuser_monitor  127.0.0.1/32      md5
host    all  dbuser_monitor  <管理机器IP地址>/32 md5

如果您的 RDS 不支持定义 HBA,那么把安装 Pigsty 机器的内网 IP 地址开白即可。


监控模式

监控模式可选项,即使没有,Pigsty监控系统的主体也可以正常工作,但我们强烈建议设置此模式。

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

监控扩展

监控扩展是可选项,但我们强烈建议启用 pg_stat_statements 扩展该扩展提供了关于查询性能的重要数据。

注意:该扩展必须列入数据库参数 shared_preload_libraries 中方可生效,而修改该参数需要重启数据库。

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

请注意,您应当在默认的管理数据库 postgres 中安装此扩展。有些时候,RDS不允许您在 postgres 数据库中创建监控模式, 在这种情况下,您可以将 pg_stat_statements 插件安装到默认的 public 下,只要确保监控用户的 search_path 按照上面的配置,能够找到 pg_stat_statements 视图即可。

CREATE EXTENSION IF NOT EXISTS "pg_stat_statements";
ALTER USER dbuser_monitor SET search_path = monitor,public; -- 建议设置此参数,避免 pg_stat_statements 扩展无法生效

监控视图

监控视图提供了若干常用的预处理结果,并对某些需要高权限的监控指标进行权限封装(例如共享内存分配),便于查询与使用。强烈建议在所有需要监控的数据库中创建

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

GRANT SELECT ON monitor.pg_table_bloat TO pg_monitor;

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

GRANT SELECT ON monitor.pg_index_bloat TO pg_monitor;

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

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

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


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


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


----------------------------------------------------------------------
-- Sequential Scan: monitor.pg_seq_scan
----------------------------------------------------------------------
DROP VIEW IF EXISTS monitor.pg_seq_scan CASCADE;
CREATE OR REPLACE VIEW monitor.pg_seq_scan AS
SELECT schemaname                                                        AS nspname,
       relname,
       seq_scan,
       seq_tup_read,
       seq_tup_read / seq_scan                                           AS seq_tup_avg,
       idx_scan,
       n_live_tup + n_dead_tup                                           AS tuples,
       round(n_live_tup * 100.0::NUMERIC / (n_live_tup + n_dead_tup), 2) AS live_ratio
FROM pg_stat_user_tables
WHERE seq_scan > 0
  and (n_live_tup + n_dead_tup) > 0
ORDER BY seq_scan DESC;
COMMENT ON VIEW monitor.pg_seq_scan IS 'table that have seq scan';
GRANT SELECT ON monitor.pg_seq_scan TO pg_monitor;
查看共享内存分配的函数(PG13以上可用)
DROP FUNCTION IF EXISTS monitor.pg_shmem() CASCADE;
CREATE OR REPLACE FUNCTION monitor.pg_shmem() RETURNS SETOF
    pg_shmem_allocations AS $$ SELECT * FROM pg_shmem_allocations;$$ LANGUAGE SQL SECURITY DEFINER;
COMMENT ON FUNCTION monitor.pg_shmem() IS 'security wrapper for system view pg_shmem';
REVOKE ALL ON FUNCTION monitor.pg_shmem() FROM PUBLIC;
GRANT EXECUTE ON FUNCTION monitor.pg_shmem() TO pg_monitor;

15 - 监控面板

Pigsty 为 PostgreSQL 提供了诸多开箱即用的 Grafana 监控仪表盘

Pigsty 为 PostgreSQL 提供了诸多开箱即用的 Grafana 监控仪表盘: Demo & Gallery

在 Pigsty 中共有 26 个与 PostgreSQL 相关的监控面板,按照层次分为 总览,集群,实例,数据库四大类,按照数据来源又分为 PGSQLPGCATPGLOG 三大类。

pigsty-dashboard.jpg


总览

总览 集群 实例 数据库
PGSQL Overview PGSQL Cluster PGSQL Instance PGSQL Database
PGSQL Alert PGRDS Cluster PGRDS Instance PGCAT Database
PGSQL Shard PGSQL Activity PGCAT Instance PGSQL Tables
PGSQL Replication PGSQL Persist PGSQL Table
PGSQL Service PGSQL Proxy PGCAT Table
PGSQL Databases PGSQL Pgbouncer PGSQL Query
PGSQL Patroni PGSQL Session PGCAT Query
PGSQL PITR PGSQL Xacts PGCAT Locks
PGSQL Exporter PGCAT Schema

概览

  • pgsql-overview : PGSQL模块的主仪表板
  • pgsql-alert : PGSQL的全局关键指标和警报事件
  • pgsql-shard : 关于水平分片的PGSQL集群的概览,例如 citus / gpsql 集群

集群

  • pgsql-cluster: 一个PGSQL集群的主仪表板
  • pgrds-cluster: PGSQL Cluster 的RDS版本,专注于所有 PostgreSQL 本身的指标
  • pgsql-activity: 关注PGSQL集群的会话/负载/QPS/TPS/锁定情况
  • pgsql-replication: 关注PGSQL集群复制、插槽和发布/订阅
  • pgsql-service: 关注PGSQL集群服务、代理、路由和负载均衡
  • pgsql-databases: 关注所有实例的数据库CRUD、慢查询和表统计信息
  • pgsql-patroni: 关注集群高可用状态,Patroni组件状态
  • pgsql-pitr: 关注集群 PITR 过程的上下文,用于辅助时间点恢复

实例

数据库

  • pgsql-database: 单个PGSQL数据库的主仪表板
  • pgcat-database: 直接从数据库目录获取的数据库信息
  • pgsql-tables : 单个数据库内的表/索引访问指标
  • pgsql-table: 单个表的详细信息(QPS/RT/索引/序列…)
  • pgcat-table: 直接从数据库目录获取的单个表的详细信息(统计/膨胀…)
  • pgsql-query: 单个查询的详细信息(QPS/RT)
  • pgcat-query: 直接从数据库目录获取的单个查询的详细信息(SQL/统计)
  • pgcat-schema: 直接从数据库目录获取关于模式的信息(表/索引/序列…)
  • pgcat-locks: 直接从数据库目录获取的关于活动与锁等待的信息

总览

PGSQL Overview:PGSQL模块的主仪表板

PGSQL Overview

pgsql-overview.jpg

PGSQL Alert:PGSQL 全局核心指标总览与告警事件一览

PGSQL Alert

pgsql-alert.jpg

PGSQL Shard:展示一个PGSQL 水平分片集群内的横向指标对比:例如 CITUS / GPSQL 集群。

PGSQL Shard

pgsql-shard.jpg


集群

PGSQL Cluster:一个PGSQL集群的主仪表板

PGSQL Cluster

pgsql-cluster.jpg

PGRDS Cluster:PGSQL Cluster 的RDS版本,专注于所有 PostgreSQL 本身的指标

PGRDS Cluster

pgrds-cluster.jpg

PGSQL Service:关注PGSQL集群服务、代理、路由和负载均衡。

PGSQL Service

pgsql-service.jpg

PGSQL Activity:关注PGSQL集群的会话/负载/QPS/TPS/锁定情况

PGSQL Activity

pgsql-activity.jpg

PGSQL Replication:关注PGSQL集群复制、插槽和发布/订阅。

PGSQL Replication

pgsql-replication.jpg

PGSQL Databases:关注所有实例的数据库CRUD、慢查询和表统计信息。

PGSQL Databases

pgsql-databases.jpg

PGSQL Patroni:关注集群高可用状态,Patroni组件状态

PGSQL Patroni

pgsql-patroni.jpg

PGSQL PITR:关注集群 PITR 过程的上下文,用于辅助时间点恢复

PGSQL PITR

pgsql-patroni.jpg


实例

PGSQL Instance:单个PGSQL实例的主仪表板

PGSQL Instance

pgsql-instance.jpg

PGRDS Instance:PGSQL Instance 的RDS版本,专注于所有 PostgreSQL 本身的指标

PGRDS Instance

pgrds-instance.jpg

PGSQL Proxy:单个haproxy负载均衡器的详细指标

PGSQL Proxy

pgsql-proxy.jpg

PGSQL Pgbouncer:单个Pgbouncer连接池实例中的指标总览

PGSQL Pgbouncer

pgsql-pgbouncer.jpg

PGSQL Persist:持久性指标:WAL、XID、检查点、存档、IO

PGSQL Persist

pgsql-persist.jpg

PGSQL Xacts:关于事务、锁、TPS/QPS相关的指标

PGSQL Xacts

pgsql-xacts.jpg

PGSQL Session:单个实例中的会话和活动/空闲时间的指标

PGSQL Session

pgsql-session.jpg

PGSQL Exporter:Postgres/Pgbouncer 监控组件自我监控指标

PGSQL Exporter

pgsql-exporter.jpg


数据库

PGSQL Database:单个PGSQL数据库的主仪表板

PGSQL Database

pgsql-database.jpg

PGSQL Tables:单个数据库内的表/索引访问指标

PGSQL Tables

pgsql-tables.jpg

PGSQL Table:单个表的详细信息(QPS/RT/索引/序列…)

PGSQL Table

pgsql-table.jpg

PGSQL Query:单类查询的详细信息(QPS/RT)

PGSQL Query

pgsql-query.jpg


PGCAT

PGCAT Instance:直接从数据库目录获取的实例信息

PGCAT Instance

pgcat-instance.jpg

PGCAT Database:直接从数据库目录获取的数据库信息

PGCAT Database

pgcat-database.jpg

PGCAT Schema:直接从数据库目录获取关于模式的信息(表/索引/序列…)

PGCAT Schema

pgcat-schema.jpg

PGCAT Table:直接从数据库目录获取的单个表的详细信息(统计/膨胀…)

PGCAT Table

pgcat-table.jpg

PGCAT Query:直接从数据库目录获取的单类查询的详细信息(SQL/统计)

PGCAT Query

pgcat-query.jpg

PGCAT Locks:直接从数据库目录获取的关于活动与锁等待的信息

PGCAT Locks

pgcat-locks.jpg


PGLOG

PGLOG Overview:总览 Pigsty CMDB 中的CSV日志样本

PGLOG Overview

pglog-overview.jpg

PGLOG Overview:Pigsty CMDB 中的CSV日志样本中某一条会话的日志详情

PGLOG Session

pglog-session.jpg


画廊

详情请参考 pigsty/wiki/gallery

PGSQL Overview

pgsql-overview.jpg

PGSQL Shard

pgsql-shard.jpg

PGSQL Cluster

pgsql-cluster.jpg

PGSQL Service

pgsql-service.jpg

PGSQL Activity

pgsql-activity.jpg

PGSQL Replication

pgsql-replication.jpg

PGSQL Databases

pgsql-databases.jpg

PGSQL Instance

pgsql-instance.jpg

PGSQL Proxy

pgsql-proxy.jpg

PGSQL Pgbouncer

pgsql-pgbouncer.jpg

PGSQL Session

pgsql-session.jpg

PGSQL Xacts

pgsql-xacts.jpg

PGSQL Persist

pgsql-persist.jpg

PGSQL Database

pgsql-database.jpg

PGSQL Tables

pgsql-tables.jpg

PGSQL Table

pgsql-table.jpg

PGSQL Query

pgsql-query.jpg

PGCAT Instance

pgcat-instance.jpg

PGCAT Database

pgcat-database.jpg

PGCAT Schema

pgcat-schema.jpg

PGCAT Table

pgcat-table.jpg

PGCAT Lock

pgcat-locks.jpg

PGCAT Query

pgcat-query.jpg

PGLOG Overview

pglog-overview.jpg

PGLOG Session

pglog-session.jpg

16 - 指标列表

Pigsty PGSQL 模块提供的完整监控指标列表与释义

PGSQL 模块包含有 638 类可用监控指标。

Metric Name Type Labels Description
ALERTS Unknown category, job, level, ins, severity, ip, alertname, alertstate, instance, cls N/A
ALERTS_FOR_STATE Unknown category, job, level, ins, severity, ip, alertname, instance, cls N/A
cls:pressure1 Unknown job, cls N/A
cls:pressure15 Unknown job, cls N/A
cls:pressure5 Unknown job, cls N/A
go_gc_duration_seconds summary job, ins, ip, instance, quantile, cls A summary of the pause duration of garbage collection cycles.
go_gc_duration_seconds_count Unknown job, ins, ip, instance, cls N/A
go_gc_duration_seconds_sum Unknown job, ins, ip, instance, cls N/A
go_goroutines gauge job, ins, ip, instance, cls Number of goroutines that currently exist.
go_info gauge version, job, ins, ip, instance, cls Information about the Go environment.
go_memstats_alloc_bytes gauge job, ins, ip, instance, cls Number of bytes allocated and still in use.
go_memstats_alloc_bytes_total counter job, ins, ip, instance, cls Total number of bytes allocated, even if freed.
go_memstats_buck_hash_sys_bytes gauge job, ins, ip, instance, cls Number of bytes used by the profiling bucket hash table.
go_memstats_frees_total counter job, ins, ip, instance, cls Total number of frees.
go_memstats_gc_sys_bytes gauge job, ins, ip, instance, cls Number of bytes used for garbage collection system metadata.
go_memstats_heap_alloc_bytes gauge job, ins, ip, instance, cls Number of heap bytes allocated and still in use.
go_memstats_heap_idle_bytes gauge job, ins, ip, instance, cls Number of heap bytes waiting to be used.
go_memstats_heap_inuse_bytes gauge job, ins, ip, instance, cls Number of heap bytes that are in use.
go_memstats_heap_objects gauge job, ins, ip, instance, cls Number of allocated objects.
go_memstats_heap_released_bytes gauge job, ins, ip, instance, cls Number of heap bytes released to OS.
go_memstats_heap_sys_bytes gauge job, ins, ip, instance, cls Number of heap bytes obtained from system.
go_memstats_last_gc_time_seconds gauge job, ins, ip, instance, cls Number of seconds since 1970 of last garbage collection.
go_memstats_lookups_total counter job, ins, ip, instance, cls Total number of pointer lookups.
go_memstats_mallocs_total counter job, ins, ip, instance, cls Total number of mallocs.
go_memstats_mcache_inuse_bytes gauge job, ins, ip, instance, cls Number of bytes in use by mcache structures.
go_memstats_mcache_sys_bytes gauge job, ins, ip, instance, cls Number of bytes used for mcache structures obtained from system.
go_memstats_mspan_inuse_bytes gauge job, ins, ip, instance, cls Number of bytes in use by mspan structures.
go_memstats_mspan_sys_bytes gauge job, ins, ip, instance, cls Number of bytes used for mspan structures obtained from system.
go_memstats_next_gc_bytes gauge job, ins, ip, instance, cls Number of heap bytes when next garbage collection will take place.
go_memstats_other_sys_bytes gauge job, ins, ip, instance, cls Number of bytes used for other system allocations.
go_memstats_stack_inuse_bytes gauge job, ins, ip, instance, cls Number of bytes in use by the stack allocator.
go_memstats_stack_sys_bytes gauge job, ins, ip, instance, cls Number of bytes obtained from system for stack allocator.
go_memstats_sys_bytes gauge job, ins, ip, instance, cls Number of bytes obtained from system.
go_threads gauge job, ins, ip, instance, cls Number of OS threads created.
ins:pressure1 Unknown job, ins, ip, cls N/A
ins:pressure15 Unknown job, ins, ip, cls N/A
ins:pressure5 Unknown job, ins, ip, cls N/A
patroni_cluster_unlocked gauge job, ins, ip, instance, cls, scope Value is 1 if the cluster is unlocked, 0 if locked.
patroni_dcs_last_seen gauge job, ins, ip, instance, cls, scope Epoch timestamp when DCS was last contacted successfully by Patroni.
patroni_failsafe_mode_is_active gauge job, ins, ip, instance, cls, scope Value is 1 if failsafe mode is active, 0 if inactive.
patroni_is_paused gauge job, ins, ip, instance, cls, scope Value is 1 if auto failover is disabled, 0 otherwise.
patroni_master gauge job, ins, ip, instance, cls, scope Value is 1 if this node is the leader, 0 otherwise.
patroni_pending_restart gauge job, ins, ip, instance, cls, scope Value is 1 if the node needs a restart, 0 otherwise.
patroni_postgres_in_archive_recovery gauge job, ins, ip, instance, cls, scope Value is 1 if Postgres is replicating from archive, 0 otherwise.
patroni_postgres_running gauge job, ins, ip, instance, cls, scope Value is 1 if Postgres is running, 0 otherwise.
patroni_postgres_server_version gauge job, ins, ip, instance, cls, scope Version of Postgres (if running), 0 otherwise.
patroni_postgres_streaming gauge job, ins, ip, instance, cls, scope Value is 1 if Postgres is streaming, 0 otherwise.
patroni_postgres_timeline counter job, ins, ip, instance, cls, scope Postgres timeline of this node (if running), 0 otherwise.
patroni_postmaster_start_time gauge job, ins, ip, instance, cls, scope Epoch seconds since Postgres started.
patroni_primary gauge job, ins, ip, instance, cls, scope Value is 1 if this node is the leader, 0 otherwise.
patroni_replica gauge job, ins, ip, instance, cls, scope Value is 1 if this node is a replica, 0 otherwise.
patroni_standby_leader gauge job, ins, ip, instance, cls, scope Value is 1 if this node is the standby_leader, 0 otherwise.
patroni_sync_standby gauge job, ins, ip, instance, cls, scope Value is 1 if this node is a sync standby replica, 0 otherwise.
patroni_up Unknown job, ins, ip, instance, cls N/A
patroni_version gauge job, ins, ip, instance, cls, scope Patroni semver without periods.
patroni_xlog_location counter job, ins, ip, instance, cls, scope Current location of the Postgres transaction log, 0 if this node is not the leader.
patroni_xlog_paused gauge job, ins, ip, instance, cls, scope Value is 1 if the Postgres xlog is paused, 0 otherwise.
patroni_xlog_received_location counter job, ins, ip, instance, cls, scope Current location of the received Postgres transaction log, 0 if this node is not a replica.
patroni_xlog_replayed_location counter job, ins, ip, instance, cls, scope Current location of the replayed Postgres transaction log, 0 if this node is not a replica.
patroni_xlog_replayed_timestamp gauge job, ins, ip, instance, cls, scope Current timestamp of the replayed Postgres transaction log, 0 if null.
pg:cls:active_backends Unknown job, cls N/A
pg:cls:active_time_rate15m Unknown job, cls N/A
pg:cls:active_time_rate1m Unknown job, cls N/A
pg:cls:active_time_rate5m Unknown job, cls N/A
pg:cls:age Unknown job, cls N/A
pg:cls:buf_alloc_rate1m Unknown job, cls N/A
pg:cls:buf_clean_rate1m Unknown job, cls N/A
pg:cls:buf_flush_backend_rate1m Unknown job, cls N/A
pg:cls:buf_flush_checkpoint_rate1m Unknown job, cls N/A
pg:cls:cpu_count Unknown job, cls N/A
pg:cls:cpu_usage Unknown job, cls N/A
pg:cls:cpu_usage_15m Unknown job, cls N/A
pg:cls:cpu_usage_1m Unknown job, cls N/A
pg:cls:cpu_usage_5m Unknown job, cls N/A
pg:cls:db_size Unknown job, cls N/A
pg:cls:file_size Unknown job, cls N/A
pg:cls:ixact_backends Unknown job, cls N/A
pg:cls:ixact_time_rate1m Unknown job, cls N/A
pg:cls:lag_bytes Unknown job, cls N/A
pg:cls:lag_seconds Unknown job, cls N/A
pg:cls:leader Unknown job, ins, ip, instance, cls N/A
pg:cls:load1 Unknown job, cls N/A
pg:cls:load15 Unknown job, cls N/A
pg:cls:load5 Unknown job, cls N/A
pg:cls:lock_count Unknown job, cls N/A
pg:cls:locks Unknown job, cls, mode N/A
pg:cls:log_size Unknown job, cls N/A
pg:cls:lsn_rate1m Unknown job, cls N/A
pg:cls:members Unknown job, ins, ip, cls N/A
pg:cls:num_backends Unknown job, cls N/A
pg:cls:partition Unknown job, cls N/A
pg:cls:receiver Unknown state, slot_name, job, appname, ip, cls, sender_host, sender_port N/A
pg:cls:rlock_count Unknown job, cls N/A
pg:cls:saturation1 Unknown job, cls N/A
pg:cls:saturation15 Unknown job, cls N/A
pg:cls:saturation5 Unknown job, cls N/A
pg:cls:sender Unknown pid, usename, address, job, ins, appname, ip, cls N/A
pg:cls:session_time_rate1m Unknown job, cls N/A
pg:cls:size Unknown job, cls N/A
pg:cls:slot_count Unknown job, cls N/A
pg:cls:slot_retained_bytes Unknown job, cls N/A
pg:cls:standby_count Unknown job, cls N/A
pg:cls:sync_state Unknown job, cls N/A
pg:cls:timeline Unknown job, cls N/A
pg:cls:tup_deleted_rate1m Unknown job, cls N/A
pg:cls:tup_fetched_rate1m Unknown job, cls N/A
pg:cls:tup_inserted_rate1m Unknown job, cls N/A
pg:cls:tup_modified_rate1m Unknown job, cls N/A
pg:cls:tup_returned_rate1m Unknown job, cls N/A
pg:cls:wal_size Unknown job, cls N/A
pg:cls:xact_commit_rate15m Unknown job, cls N/A
pg:cls:xact_commit_rate1m Unknown job, cls N/A
pg:cls:xact_commit_rate5m Unknown job, cls N/A
pg:cls:xact_rollback_rate15m Unknown job, cls N/A
pg:cls:xact_rollback_rate1m Unknown job, cls N/A
pg:cls:xact_rollback_rate5m Unknown job, cls N/A
pg:cls:xact_total_rate15m Unknown job, cls N/A
pg:cls:xact_total_rate1m Unknown job, cls N/A
pg:cls:xact_total_sigma15m Unknown job, cls N/A
pg:cls:xlock_count Unknown job, cls N/A
pg:db:active_backends Unknown datname, job, ins, ip, instance, cls N/A
pg:db:active_time_rate15m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:active_time_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:active_time_rate5m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:age Unknown datname, job, ins, ip, instance, cls N/A
pg:db:age_deriv1h Unknown datname, job, ins, ip, instance, cls N/A
pg:db:age_exhaust Unknown datname, job, ins, ip, instance, cls N/A
pg:db:blk_io_time_seconds_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:blk_read_time_seconds_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:blk_write_time_seconds_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:blks_access_1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:blks_hit_1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:blks_hit_ratio1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:blks_read_1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:conn_limit Unknown datname, job, ins, ip, instance, cls N/A
pg:db:conn_usage Unknown datname, job, ins, ip, instance, cls N/A
pg:db:db_size Unknown datname, job, ins, ip, instance, cls N/A
pg:db:ixact_backends Unknown datname, job, ins, ip, instance, cls N/A
pg:db:ixact_time_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:lock_count Unknown datname, job, ins, ip, instance, cls N/A
pg:db:num_backends Unknown datname, job, ins, ip, instance, cls N/A
pg:db:rlock_count Unknown datname, job, ins, ip, instance, cls N/A
pg:db:session_time_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:temp_bytes_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:temp_files_1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:tup_deleted_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:tup_fetched_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:tup_inserted_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:tup_modified_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:tup_returned_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:wlock_count Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_commit_rate15m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_commit_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_commit_rate5m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_rollback_rate15m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_rollback_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_rollback_rate5m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_total_rate15m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_total_rate1m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_total_rate5m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xact_total_sigma15m Unknown datname, job, ins, ip, instance, cls N/A
pg:db:xlock_count Unknown datname, job, ins, ip, instance, cls N/A
pg:env:active_backends Unknown job N/A
pg:env:active_time_rate15m Unknown job N/A
pg:env:active_time_rate1m Unknown job N/A
pg:env:active_time_rate5m Unknown job N/A
pg:env:age Unknown job N/A
pg:env:cpu_count Unknown job N/A
pg:env:cpu_usage Unknown job N/A
pg:env:cpu_usage_15m Unknown job N/A
pg:env:cpu_usage_1m Unknown job N/A
pg:env:cpu_usage_5m Unknown job N/A
pg:env:ixact_backends Unknown job N/A
pg:env:ixact_time_rate1m Unknown job N/A
pg:env:lag_bytes Unknown job N/A
pg:env:lag_seconds Unknown job N/A
pg:env:lsn_rate1m Unknown job N/A
pg:env:session_time_rate1m Unknown job N/A
pg:env:tup_deleted_rate1m Unknown job N/A
pg:env:tup_fetched_rate1m Unknown job N/A
pg:env:tup_inserted_rate1m Unknown job N/A
pg:env:tup_modified_rate1m Unknown job N/A
pg:env:tup_returned_rate1m Unknown job N/A
pg:env:xact_commit_rate15m Unknown job N/A
pg:env:xact_commit_rate1m Unknown job N/A
pg:env:xact_commit_rate5m Unknown job N/A
pg:env:xact_rollback_rate15m Unknown job N/A
pg:env:xact_rollback_rate1m Unknown job N/A
pg:env:xact_rollback_rate5m Unknown job N/A
pg:env:xact_total_rate15m Unknown job N/A
pg:env:xact_total_rate1m Unknown job N/A
pg:env:xact_total_sigma15m Unknown job N/A
pg:ins:active_backends Unknown job, ins, ip, instance, cls N/A
pg:ins:active_time_rate15m Unknown job, ins, ip, instance, cls N/A
pg:ins:active_time_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:active_time_rate5m Unknown job, ins, ip, instance, cls N/A
pg:ins:age Unknown job, ins, ip, instance, cls N/A
pg:ins:blks_hit_ratio1m Unknown job, ins, ip, instance, cls N/A
pg:ins:buf_alloc_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:buf_clean_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:buf_flush_backend_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:buf_flush_checkpoint_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:ckpt_1h Unknown job, ins, ip, instance, cls N/A
pg:ins:ckpt_req_1m Unknown job, ins, ip, instance, cls N/A
pg:ins:ckpt_timed_1m Unknown job, ins, ip, instance, cls N/A
pg:ins:conn_limit Unknown job, ins, ip, instance, cls N/A
pg:ins:conn_usage Unknown job, ins, ip, instance, cls N/A
pg:ins:cpu_count Unknown job, ins, ip, instance, cls N/A
pg:ins:cpu_usage Unknown job, ins, ip, instance, cls N/A
pg:ins:cpu_usage_15m Unknown job, ins, ip, instance, cls N/A
pg:ins:cpu_usage_1m Unknown job, ins, ip, instance, cls N/A
pg:ins:cpu_usage_5m Unknown job, ins, ip, instance, cls N/A
pg:ins:db_size Unknown job, ins, ip, instance, cls N/A
pg:ins:file_size Unknown job, ins, ip, instance, cls N/A
pg:ins:fs_size Unknown job, ins, ip, instance, cls N/A
pg:ins:is_leader Unknown job, ins, ip, instance, cls N/A
pg:ins:ixact_backends Unknown job, ins, ip, instance, cls N/A
pg:ins:ixact_time_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:lag_bytes Unknown job, ins, ip, instance, cls N/A
pg:ins:lag_seconds Unknown job, ins, ip, instance, cls N/A
pg:ins:load1 Unknown job, ins, ip, instance, cls N/A
pg:ins:load15 Unknown job, ins, ip, instance, cls N/A
pg:ins:load5 Unknown job, ins, ip, instance, cls N/A
pg:ins:lock_count Unknown job, ins, ip, instance, cls N/A
pg:ins:locks Unknown job, ins, ip, mode, instance, cls N/A
pg:ins:log_size Unknown job, ins, ip, instance, cls N/A
pg:ins:lsn_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:mem_size Unknown job, ins, ip, instance, cls N/A
pg:ins:num_backends Unknown job, ins, ip, instance, cls N/A
pg:ins:rlock_count Unknown job, ins, ip, instance, cls N/A
pg:ins:saturation1 Unknown job, ins, ip, cls N/A
pg:ins:saturation15 Unknown job, ins, ip, cls N/A
pg:ins:saturation5 Unknown job, ins, ip, cls N/A
pg:ins:session_time_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:slot_retained_bytes Unknown job, ins, ip, instance, cls N/A
pg:ins:space_usage Unknown job, ins, ip, instance, cls N/A
pg:ins:status Unknown job, ins, ip, instance, cls N/A
pg:ins:sync_state Unknown job, ins, instance, cls N/A
pg:ins:target_count Unknown job, cls, ins N/A
pg:ins:timeline Unknown job, ins, ip, instance, cls N/A
pg:ins:tup_deleted_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:tup_fetched_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:tup_inserted_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:tup_modified_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:tup_returned_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:wal_size Unknown job, ins, ip, instance, cls N/A
pg:ins:wlock_count Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_commit_rate15m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_commit_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_commit_rate5m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_rollback_rate15m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_rollback_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_rollback_rate5m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_total_rate15m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_total_rate1m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_total_rate5m Unknown job, ins, ip, instance, cls N/A
pg:ins:xact_total_sigma15m Unknown job, ins, ip, instance, cls N/A
pg:ins:xlock_count Unknown job, ins, ip, instance, cls N/A
pg:query:call_rate1m Unknown datname, query, job, ins, ip, instance, cls N/A
pg:query:rt_1m Unknown datname, query, job, ins, ip, instance, cls N/A
pg:table:scan_rate1m Unknown datname, relname, job, ins, ip, instance, cls N/A
pg_activity_count gauge datname, state, job, ins, ip, instance, cls Count of connection among (datname,state)
pg_activity_max_conn_duration gauge datname, state, job, ins, ip, instance, cls Max backend session duration since state change among (datname, state)
pg_activity_max_duration gauge datname, state, job, ins, ip, instance, cls Max duration since last state change among (datname, state)
pg_activity_max_tx_duration gauge datname, state, job, ins, ip, instance, cls Max transaction duration since state change among (datname, state)
pg_archiver_failed_count counter job, ins, ip, instance, cls Number of failed attempts for archiving WAL files
pg_archiver_finish_count counter job, ins, ip, instance, cls Number of WAL files that have been successfully archived
pg_archiver_last_failed_time counter job, ins, ip, instance, cls Time of the last failed archival operation
pg_archiver_last_finish_time counter job, ins, ip, instance, cls Time of the last successful archive operation
pg_archiver_reset_time gauge job, ins, ip, instance, cls Time at which archive statistics were last reset
pg_backend_count gauge type, job, ins, ip, instance, cls Database backend process count by backend_type
pg_bgwriter_buffers_alloc counter job, ins, ip, instance, cls Number of buffers allocated
pg_bgwriter_buffers_backend counter job, ins, ip, instance, cls Number of buffers written directly by a backend
pg_bgwriter_buffers_backend_fsync counter job, ins, ip, instance, cls Number of times a backend had to execute its own fsync call
pg_bgwriter_buffers_checkpoint counter job, ins, ip, instance, cls Number of buffers written during checkpoints
pg_bgwriter_buffers_clean counter job, ins, ip, instance, cls Number of buffers written by the background writer
pg_bgwriter_checkpoint_sync_time counter job, ins, ip, instance, cls Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in seconds
pg_bgwriter_checkpoint_write_time counter job, ins, ip, instance, cls Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in seconds
pg_bgwriter_checkpoints_req counter job, ins, ip, instance, cls Number of requested checkpoints that have been performed
pg_bgwriter_checkpoints_timed counter job, ins, ip, instance, cls Number of scheduled checkpoints that have been performed
pg_bgwriter_maxwritten_clean counter job, ins, ip, instance, cls Number of times the background writer stopped a cleaning scan because it had written too many buffers
pg_bgwriter_reset_time counter job, ins, ip, instance, cls Time at which bgwriter statistics were last reset
pg_boot_time gauge job, ins, ip, instance, cls unix timestamp when postmaster boot
pg_checkpoint_checkpoint_lsn counter job, ins, ip, instance, cls Latest checkpoint location
pg_checkpoint_elapse gauge job, ins, ip, instance, cls Seconds elapsed since latest checkpoint in seconds
pg_checkpoint_full_page_writes gauge job, ins, ip, instance, cls Latest checkpoint’s full_page_writes enabled
pg_checkpoint_newest_commit_ts_xid counter job, ins, ip, instance, cls Latest checkpoint’s newestCommitTsXid
pg_checkpoint_next_multi_offset counter job, ins, ip, instance, cls Latest checkpoint’s NextMultiOffset
pg_checkpoint_next_multixact_id counter job, ins, ip, instance, cls Latest checkpoint’s NextMultiXactId
pg_checkpoint_next_oid counter job, ins, ip, instance, cls Latest checkpoint’s NextOID
pg_checkpoint_next_xid counter job, ins, ip, instance, cls Latest checkpoint’s NextXID xid
pg_checkpoint_next_xid_epoch counter job, ins, ip, instance, cls Latest checkpoint’s NextXID epoch
pg_checkpoint_oldest_active_xid counter job, ins, ip, instance, cls Latest checkpoint’s oldestActiveXID
pg_checkpoint_oldest_commit_ts_xid counter job, ins, ip, instance, cls Latest checkpoint’s oldestCommitTsXid
pg_checkpoint_oldest_multi_dbid gauge job, ins, ip, instance, cls Latest checkpoint’s oldestMulti’s DB OID
pg_checkpoint_oldest_multi_xid counter job, ins, ip, instance, cls Latest checkpoint’s oldestMultiXid
pg_checkpoint_oldest_xid counter job, ins, ip, instance, cls Latest checkpoint’s oldestXID
pg_checkpoint_oldest_xid_dbid gauge job, ins, ip, instance, cls Latest checkpoint’s oldestXID’s DB OID
pg_checkpoint_prev_tli counter job, ins, ip, instance, cls Latest checkpoint’s PrevTimeLineID
pg_checkpoint_redo_lsn counter job, ins, ip, instance, cls Latest checkpoint’s REDO location
pg_checkpoint_time counter job, ins, ip, instance, cls Time of latest checkpoint
pg_checkpoint_tli counter job, ins, ip, instance, cls Latest checkpoint’s TimeLineID
pg_conf_reload_time gauge job, ins, ip, instance, cls seconds since last configuration reload
pg_db_active_time counter datname, job, ins, ip, instance, cls Time spent executing SQL statements in this database, in seconds
pg_db_age gauge datname, job, ins, ip, instance, cls Age of database calculated from datfrozenxid
pg_db_allow_conn gauge datname, job, ins, ip, instance, cls If false(0) then no one can connect to this database.
pg_db_blk_read_time counter datname, job, ins, ip, instance, cls Time spent reading data file blocks by backends in this database, in seconds
pg_db_blk_write_time counter datname, job, ins, ip, instance, cls Time spent writing data file blocks by backends in this database, in seconds
pg_db_blks_access counter datname, job, ins, ip, instance, cls Number of times disk blocks that accessed read+hit
pg_db_blks_hit counter datname, job, ins, ip, instance, cls Number of times disk blocks were found already in the buffer cache
pg_db_blks_read counter datname, job, ins, ip, instance, cls Number of disk blocks read in this database
pg_db_cks_fail_time gauge datname, job, ins, ip, instance, cls Time at which the last data page checksum failure was detected in this database
pg_db_cks_fails counter datname, job, ins, ip, instance, cls Number of data page checksum failures detected in this database, -1 for not enabled
pg_db_confl_confl_bufferpin counter datname, job, ins, ip, instance, cls Number of queries in this database that have been canceled due to pinned buffers
pg_db_confl_confl_deadlock counter datname, job, ins, ip, instance, cls Number of queries in this database that have been canceled due to deadlocks
pg_db_confl_confl_lock counter datname, job, ins, ip, instance, cls Number of queries in this database that have been canceled due to lock timeouts
pg_db_confl_confl_snapshot counter datname, job, ins, ip, instance, cls Number of queries in this database that have been canceled due to old snapshots
pg_db_confl_confl_tablespace counter datname, job, ins, ip, instance, cls Number of queries in this database that have been canceled due to dropped tablespaces
pg_db_conflicts counter datname, job, ins, ip, instance, cls Number of queries canceled due to conflicts with recovery in this database
pg_db_conn_limit gauge datname, job, ins, ip, instance, cls Sets maximum number of concurrent connections that can be made to this database. -1 means no limit.
pg_db_datid gauge datname, job, ins, ip, instance, cls OID of the database
pg_db_deadlocks counter datname, job, ins, ip, instance, cls Number of deadlocks detected in this database
pg_db_frozen_xid gauge datname, job, ins, ip, instance, cls All transaction IDs before this one have been frozened
pg_db_is_template gauge datname, job, ins, ip, instance, cls If true(1), then this database can be cloned by any user with CREATEDB privileges
pg_db_ixact_time counter datname, job, ins, ip, instance, cls Time spent idling while in a transaction in this database, in seconds
pg_db_numbackends gauge datname, job, ins, ip, instance, cls Number of backends currently connected to this database
pg_db_reset_time counter datname, job, ins, ip, instance, cls Time at which database statistics were last reset
pg_db_session_time counter datname, job, ins, ip, instance, cls Time spent by database sessions in this database, in seconds
pg_db_sessions counter datname, job, ins, ip, instance, cls Total number of sessions established to this database
pg_db_sessions_abandoned counter datname, job, ins, ip, instance, cls Number of database sessions to this database that were terminated because connection to the client was lost
pg_db_sessions_fatal counter datname, job, ins, ip, instance, cls Number of database sessions to this database that were terminated by fatal errors
pg_db_sessions_killed counter datname, job, ins, ip, instance, cls Number of database sessions to this database that were terminated by operator intervention
pg_db_temp_bytes counter datname, job, ins, ip, instance, cls Total amount of data written to temporary files by queries in this database.
pg_db_temp_files counter datname, job, ins, ip, instance, cls Number of temporary files created by queries in this database
pg_db_tup_deleted counter datname, job, ins, ip, instance, cls Number of rows deleted by queries in this database
pg_db_tup_fetched counter datname, job, ins, ip, instance, cls Number of rows fetched by queries in this database
pg_db_tup_inserted counter datname, job, ins, ip, instance, cls Number of rows inserted by queries in this database
pg_db_tup_modified counter datname, job, ins, ip, instance, cls Number of rows modified by queries in this database
pg_db_tup_returned counter datname, job, ins, ip, instance, cls Number of rows returned by queries in this database
pg_db_tup_updated counter datname, job, ins, ip, instance, cls Number of rows updated by queries in this database
pg_db_xact_commit counter datname, job, ins, ip, instance, cls Number of transactions in this database that have been committed
pg_db_xact_rollback counter datname, job, ins, ip, instance, cls Number of transactions in this database that have been rolled back
pg_db_xact_total counter datname, job, ins, ip, instance, cls Number of transactions in this database
pg_downstream_count gauge state, job, ins, ip, instance, cls Count of corresponding state
pg_exporter_agent_up Unknown job, ins, ip, instance, cls N/A
pg_exporter_last_scrape_time gauge job, ins, ip, instance, cls seconds exporter spending on scrapping
pg_exporter_query_cache_ttl gauge datname, query, job, ins, ip, instance, cls times to live of query cache
pg_exporter_query_scrape_duration gauge datname, query, job, ins, ip, instance, cls seconds query spending on scrapping
pg_exporter_query_scrape_error_count gauge datname, query, job, ins, ip, instance, cls times the query failed
pg_exporter_query_scrape_hit_count gauge datname, query, job, ins, ip, instance, cls numbers been scrapped from this query
pg_exporter_query_scrape_metric_count gauge datname, query, job, ins, ip, instance, cls numbers of metrics been scrapped from this query
pg_exporter_query_scrape_total_count gauge datname, query, job, ins, ip, instance, cls times exporter server was scraped for metrics
pg_exporter_scrape_duration gauge job, ins, ip, instance, cls seconds exporter spending on scrapping
pg_exporter_scrape_error_count counter job, ins, ip, instance, cls times exporter was scraped for metrics and failed
pg_exporter_scrape_total_count counter job, ins, ip, instance, cls times exporter was scraped for metrics
pg_exporter_server_scrape_duration gauge datname, job, ins, ip, instance, cls seconds exporter server spending on scrapping
pg_exporter_server_scrape_error_count Unknown datname, job, ins, ip, instance, cls N/A
pg_exporter_server_scrape_total_count gauge datname, job, ins, ip, instance, cls times exporter server was scraped for metrics
pg_exporter_server_scrape_total_seconds gauge datname, job, ins, ip, instance, cls seconds exporter server spending on scrapping
pg_exporter_up gauge job, ins, ip, instance, cls always be 1 if your could retrieve metrics
pg_exporter_uptime gauge job, ins, ip, instance, cls seconds since exporter primary server inited
pg_flush_lsn counter job, ins, ip, instance, cls primary only, location of current wal syncing
pg_func_calls counter datname, funcname, job, ins, ip, instance, cls Number of times this function has been called
pg_func_self_time counter datname, funcname, job, ins, ip, instance, cls Total time spent in this function itself, not including other functions called by it, in ms
pg_func_total_time counter datname, funcname, job, ins, ip, instance, cls Total time spent in this function and all other functions called by it, in ms
pg_in_recovery gauge job, ins, ip, instance, cls server is in recovery mode? 1 for yes 0 for no
pg_index_idx_blks_hit counter datname, relname, job, ins, relid, ip, instance, cls, idxname Number of buffer hits in this index
pg_index_idx_blks_read counter datname, relname, job, ins, relid, ip, instance, cls, idxname Number of disk blocks read from this index
pg_index_idx_scan counter datname, relname, job, ins, relid, ip, instance, cls, idxname Number of index scans initiated on this index
pg_index_idx_tup_fetch counter datname, relname, job, ins, relid, ip, instance, cls, idxname Number of live table rows fetched by simple index scans using this index
pg_index_idx_tup_read counter datname, relname, job, ins, relid, ip, instance, cls, idxname Number of index entries returned by scans on this index
pg_index_relpages gauge datname, relname, job, ins, relid, ip, instance, cls, idxname Size of the on-disk representation of this index in pages
pg_index_reltuples gauge datname, relname, job, ins, relid, ip, instance, cls, idxname Estimate relation tuples
pg_insert_lsn counter job, ins, ip, instance, cls primary only, location of current wal inserting
pg_io_evictions counter type, job, ins, object, ip, context, instance, cls Number of times a block has been written out from a shared or local buffer
pg_io_extend_time counter type, job, ins, object, ip, context, instance, cls Time spent in extend operations in seconds
pg_io_extends counter type, job, ins, object, ip, context, instance, cls Number of relation extend operations, each of the size specified in op_bytes.
pg_io_fsync_time counter type, job, ins, object, ip, context, instance, cls Time spent in fsync operations in seconds
pg_io_fsyncs counter type, job, ins, object, ip, context, instance, cls Number of fsync calls. These are only tracked in context normal
pg_io_hits counter type, job, ins, object, ip, context, instance, cls The number of times a desired block was found in a shared buffer.
pg_io_op_bytes gauge type, job, ins, object, ip, context, instance, cls The number of bytes per unit of I/O read, written, or extended. 8192 by default
pg_io_read_time counter type, job, ins, object, ip, context, instance, cls Time spent in read operations in seconds
pg_io_reads counter type, job, ins, object, ip, context, instance, cls Number of read operations, each of the size specified in op_bytes.
pg_io_reset_time gauge type, job, ins, object, ip, context, instance, cls Timestamp at which these statistics were last reset
pg_io_reuses counter type, job, ins, object, ip, context, instance, cls The number of times an existing buffer in reused
pg_io_write_time counter type, job, ins, object, ip, context, instance, cls Time spent in write operations in seconds
pg_io_writeback_time counter type, job, ins, object, ip, context, instance, cls Time spent in writeback operations in seconds
pg_io_writebacks counter type, job, ins, object, ip, context, instance, cls Number of units of size op_bytes which the process requested the kernel write out to permanent storage.
pg_io_writes counter type, job, ins, object, ip, context, instance, cls Number of write operations, each of the size specified in op_bytes.
pg_is_in_recovery gauge job, ins, ip, instance, cls 1 if in recovery mode
pg_is_wal_replay_paused gauge job, ins, ip, instance, cls 1 if wal play paused
pg_lag gauge job, ins, ip, instance, cls replica only, replication lag in seconds
pg_last_replay_time gauge job, ins, ip, instance, cls time when last transaction been replayed
pg_lock_count gauge datname, job, ins, ip, mode, instance, cls Number of locks of corresponding mode and database
pg_lsn counter job, ins, ip, instance, cls log sequence number, current write location
pg_meta_info gauge cls, extensions, version, job, ins, primary_conninfo, conf_path, hba_path, ip, cluster_id, instance, listen_port, wal_level, ver_num, cluster_name, data_dir constant 1
pg_query_calls counter datname, query, job, ins, ip, instance, cls Number of times the statement was executed
pg_query_exec_time counter datname, query, job, ins, ip, instance, cls Total time spent executing the statement, in seconds
pg_query_io_time counter datname, query, job, ins, ip, instance, cls Total time the statement spent reading and writing blocks, in seconds
pg_query_rows counter datname, query, job, ins, ip, instance, cls Total number of rows retrieved or affected by the statement
pg_query_sblk_dirtied counter datname, query, job, ins, ip, instance, cls Total number of shared blocks dirtied by the statement
pg_query_sblk_hit counter datname, query, job, ins, ip, instance, cls Total number of shared block cache hits by the statement
pg_query_sblk_read counter datname, query, job, ins, ip, instance, cls Total number of shared blocks read by the statement
pg_query_sblk_written counter datname, query, job, ins, ip, instance, cls Total number of shared blocks written by the statement
pg_query_wal_bytes counter datname, query, job, ins, ip, instance, cls Total amount of WAL bytes generated by the statement
pg_receive_lsn counter job, ins, ip, instance, cls replica only, location of wal synced to disk
pg_recovery_backup_end_lsn counter job, ins, ip, instance, cls Backup end location
pg_recovery_backup_start_lsn counter job, ins, ip, instance, cls Backup start location
pg_recovery_min_lsn counter job, ins, ip, instance, cls Minimum recovery ending location
pg_recovery_min_timeline counter job, ins, ip, instance, cls Min recovery ending loc’s timeline
pg_recovery_prefetch_block_distance gauge job, ins, ip, instance, cls How many blocks ahead the prefetcher is looking
pg_recovery_prefetch_hit counter job, ins, ip, instance, cls Number of blocks not prefetched because they were already in the buffer pool
pg_recovery_prefetch_io_depth gauge job, ins, ip, instance, cls How many prefetches have been initiated but are not yet known to have completed
pg_recovery_prefetch_prefetch counter job, ins, ip, instance, cls Number of blocks prefetched because they were not in the buffer pool
pg_recovery_prefetch_reset_time counter job, ins, ip, instance, cls Time at which these recovery prefetch statistics were last reset
pg_recovery_prefetch_skip_fpw gauge job, ins, ip, instance, cls Number of blocks not prefetched because a full page image was included in the WAL
pg_recovery_prefetch_skip_init counter job, ins, ip, instance, cls Number of blocks not prefetched because they would be zero-initialized
pg_recovery_prefetch_skip_new counter job, ins, ip, instance, cls Number of blocks not prefetched because they didn’t exist yet
pg_recovery_prefetch_skip_rep counter job, ins, ip, instance, cls Number of blocks not prefetched because they were already recently prefetched
pg_recovery_prefetch_wal_distance gauge job, ins, ip, instance, cls How many bytes ahead the prefetcher is looking
pg_recovery_require_record gauge job, ins, ip, instance, cls End-of-backup record required
pg_recv_flush_lsn counter state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Last write-ahead log location already received and flushed to disk
pg_recv_flush_tli counter state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Timeline number of last write-ahead log location received and flushed to disk
pg_recv_init_lsn counter state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port First write-ahead log location used when WAL receiver is started
pg_recv_init_tli counter state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port First timeline number used when WAL receiver is started
pg_recv_msg_recv_time gauge state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Receipt time of last message received from origin WAL sender
pg_recv_msg_send_time gauge state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Send time of last message received from origin WAL sender
pg_recv_pid gauge state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Process ID of the WAL receiver process
pg_recv_reported_lsn counter state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Last write-ahead log location reported to origin WAL sender
pg_recv_reported_time gauge state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Time of last write-ahead log location reported to origin WAL sender
pg_recv_time gauge state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Time of current snapshot
pg_recv_write_lsn counter state, slot_name, job, ins, ip, instance, cls, sender_host, sender_port Last write-ahead log location already received and written to disk, but not flushed.
pg_relkind_count gauge datname, job, ins, ip, instance, cls, relkind Number of relations of corresponding relkind
pg_repl_backend_xmin counter pid, usename, address, job, ins, appname, ip, instance, cls This standby’s xmin horizon reported by hot_standby_feedback.
pg_repl_client_port gauge pid, usename, address, job, ins, appname, ip, instance, cls TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used
pg_repl_flush_diff gauge pid, usename, address, job, ins, appname, ip, instance, cls Last log position flushed to disk by this standby server diff with current lsn
pg_repl_flush_lag gauge pid, usename, address, job, ins, appname, ip, instance, cls Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it
pg_repl_flush_lsn counter pid, usename, address, job, ins, appname, ip, instance, cls Last write-ahead log location flushed to disk by this standby server
pg_repl_launch_time counter pid, usename, address, job, ins, appname, ip, instance, cls Time when this process was started, i.e., when the client connected to this WAL sender
pg_repl_lsn counter pid, usename, address, job, ins, appname, ip, instance, cls Current log position on this server
pg_repl_replay_diff gauge pid, usename, address, job, ins, appname, ip, instance, cls Last log position replayed into the database on this standby server diff with current lsn
pg_repl_replay_lag gauge pid, usename, address, job, ins, appname, ip, instance, cls Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it
pg_repl_replay_lsn counter pid, usename, address, job, ins, appname, ip, instance, cls Last write-ahead log location replayed into the database on this standby server
pg_repl_reply_time gauge pid, usename, address, job, ins, appname, ip, instance, cls Send time of last reply message received from standby server
pg_repl_sent_diff gauge pid, usename, address, job, ins, appname, ip, instance, cls Last log position sent to this standby server diff with current lsn
pg_repl_sent_lsn counter pid, usename, address, job, ins, appname, ip, instance, cls Last write-ahead log location sent on this connection
pg_repl_state gauge pid, usename, address, job, ins, appname, ip, instance, cls Current WAL sender encoded state 0-4 for streaming startup catchup backup stopping
pg_repl_sync_priority gauge pid, usename, address, job, ins, appname, ip, instance, cls Priority of this standby server for being chosen as the synchronous standby
pg_repl_sync_state gauge pid, usename, address, job, ins, appname, ip, instance, cls Encoded synchronous state of this standby server, 0-3 for async potential sync quorum
pg_repl_time counter pid, usename, address, job, ins, appname, ip, instance, cls Current timestamp in unix epoch
pg_repl_write_diff gauge pid, usename, address, job, ins, appname, ip, instance, cls Last log position written to disk by this standby server diff with current lsn
pg_repl_write_lag gauge pid, usename, address, job, ins, appname, ip, instance, cls Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it
pg_repl_write_lsn counter pid, usename, address, job, ins, appname, ip, instance, cls Last write-ahead log location written to disk by this standby server
pg_replay_lsn counter job, ins, ip, instance, cls replica only, location of wal applied
pg_seq_blks_hit counter datname, job, ins, ip, instance, cls, seqname Number of buffer hits in this sequence
pg_seq_blks_read counter datname, job, ins, ip, instance, cls, seqname Number of disk blocks read from this sequence
pg_seq_last_value counter datname, job, ins, ip, instance, cls, seqname The last sequence value written to disk
pg_setting_block_size gauge job, ins, ip, instance, cls pg page block size, 8192 by default
pg_setting_data_checksums gauge job, ins, ip, instance, cls whether data checksum is enabled, 1 enabled 0 disabled
pg_setting_max_connections gauge job, ins, ip, instance, cls number of concurrent connections to the database server
pg_setting_max_locks_per_transaction gauge job, ins, ip, instance, cls no more than this many distinct objects can be locked at any one time
pg_setting_max_prepared_transactions gauge job, ins, ip, instance, cls maximum number of transactions that can be in the prepared state simultaneously
pg_setting_max_replication_slots gauge job, ins, ip, instance, cls maximum number of replication slots
pg_setting_max_wal_senders gauge job, ins, ip, instance, cls maximum number of concurrent connections from standby servers
pg_setting_max_worker_processes gauge job, ins, ip, instance, cls maximum number of background processes that the system can support
pg_setting_wal_log_hints gauge job, ins, ip, instance, cls whether wal_log_hints is enabled, 1 enabled 0 disabled
pg_size_bytes gauge datname, job, ins, ip, instance, cls File size in bytes
pg_slot_active gauge slot_name, job, ins, ip, instance, cls True(1) if this slot is currently actively being used
pg_slot_catalog_xmin counter slot_name, job, ins, ip, instance, cls The oldest transaction affecting the system catalogs that this slot needs the database to retain.
pg_slot_confirm_lsn counter slot_name, job, ins, ip, instance, cls The address (LSN) up to which the logical slot’s consumer has confirmed receiving data.
pg_slot_reset_time counter slot_name, job, ins, ip, instance, cls When statistics were last reset
pg_slot_restart_lsn counter slot_name, job, ins, ip, instance, cls The address (LSN) of oldest WAL which still might be required by the consumer of this slot
pg_slot_retained_bytes gauge slot_name, job, ins, ip, instance, cls Size of bytes that retained for this slot
pg_slot_safe_wal_size gauge slot_name, job, ins, ip, instance, cls bytes that can be written to WAL which will not make slot into lost
pg_slot_spill_bytes counter slot_name, job, ins, ip, instance, cls Bytes that spilled to disk due to logical decode mem exceeding
pg_slot_spill_count counter slot_name, job, ins, ip, instance, cls Xacts that spilled to disk due to logical decode mem exceeding (a xact can be spilled multiple times)
pg_slot_spill_txns counter slot_name, job, ins, ip, instance, cls Xacts that spilled to disk due to logical decode mem exceeding (subtrans included)
pg_slot_stream_bytes counter slot_name, job, ins, ip, instance, cls Bytes that streamed to decoding output plugin after mem exceed
pg_slot_stream_count counter slot_name, job, ins, ip, instance, cls Xacts that streamed to decoding output plugin after mem exceed (a xact can be streamed multiple times)
pg_slot_stream_txns counter slot_name, job, ins, ip, instance, cls Xacts that streamed to decoding output plugin after mem exceed
pg_slot_temporary gauge slot_name, job, ins, ip, instance, cls True(1) if this is a temporary replication slot.
pg_slot_total_bytes counter slot_name, job, ins, ip, instance, cls Number of decoded bytes sent to the decoding output plugin for this slot
pg_slot_total_txns counter slot_name, job, ins, ip, instance, cls Number of decoded xacts sent to the decoding output plugin for this slot
pg_slot_wal_status gauge slot_name, job, ins, ip, instance, cls WAL reserve status 0-3 means reserved,extended,unreserved,lost, -1 means other
pg_slot_xmin counter slot_name, job, ins, ip, instance, cls The oldest transaction that this slot needs the database to retain.
pg_slru_blks_exists counter job, ins, ip, instance, cls Number of blocks checked for existence for this SLRU
pg_slru_blks_hit counter job, ins, ip, instance, cls Number of times disk blocks were found already in the SLRU, so that a read was not necessary
pg_slru_blks_read counter job, ins, ip, instance, cls Number of disk blocks read for this SLRU
pg_slru_blks_written counter job, ins, ip, instance, cls Number of disk blocks written for this SLRU
pg_slru_blks_zeroed counter job, ins, ip, instance, cls Number of blocks zeroed during initializations
pg_slru_flushes counter job, ins, ip, instance, cls Number of flushes of dirty data for this SLRU
pg_slru_reset_time counter job, ins, ip, instance, cls Time at which these statistics were last reset
pg_slru_truncates counter job, ins, ip, instance, cls Number of truncates for this SLRU
pg_ssl_disabled gauge job, ins, ip, instance, cls Number of client connection that does not use ssl
pg_ssl_enabled gauge job, ins, ip, instance, cls Number of client connection that use ssl
pg_sync_standby_enabled gauge job, ins, ip, names, instance, cls Synchronous commit enabled, 1 if enabled, 0 if disabled
pg_table_age gauge datname, relname, job, ins, ip, instance, cls Age of this table in vacuum cycles
pg_table_analyze_count counter datname, relname, job, ins, ip, instance, cls Number of times this table has been manually analyzed
pg_table_autoanalyze_count counter datname, relname, job, ins, ip, instance, cls Number of times this table has been analyzed by the autovacuum daemon
pg_table_autovacuum_count counter datname, relname, job, ins, ip, instance, cls Number of times this table has been vacuumed by the autovacuum daemon
pg_table_frozenxid counter datname, relname, job, ins, ip, instance, cls All txid before this have been frozen on this table
pg_table_heap_blks_hit counter datname, relname, job, ins, ip, instance, cls Number of buffer hits in this table
pg_table_heap_blks_read counter datname, relname, job, ins, ip, instance, cls Number of disk blocks read from this table
pg_table_idx_blks_hit counter datname, relname, job, ins, ip, instance, cls Number of buffer hits in all indexes on this table
pg_table_idx_blks_read counter datname, relname, job, ins, ip, instance, cls Number of disk blocks read from all indexes on this table
pg_table_idx_scan counter datname, relname, job, ins, ip, instance, cls Number of index scans initiated on this table
pg_table_idx_tup_fetch counter datname, relname, job, ins, ip, instance, cls Number of live rows fetched by index scans
pg_table_kind gauge datname, relname, job, ins, ip, instance, cls Relation kind r/table/114
pg_table_n_dead_tup gauge datname, relname, job, ins, ip, instance, cls Estimated number of dead rows
pg_table_n_ins_since_vacuum gauge datname, relname, job, ins, ip, instance, cls Estimated number of rows inserted since this table was last vacuumed
pg_table_n_live_tup gauge datname, relname, job, ins, ip, instance, cls Estimated number of live rows
pg_table_n_mod_since_analyze gauge datname, relname, job, ins, ip, instance, cls Estimated number of rows modified since this table was last analyzed
pg_table_n_tup_del counter datname, relname, job, ins, ip, instance, cls Number of rows deleted
pg_table_n_tup_hot_upd counter datname, relname, job, ins, ip, instance, cls Number of rows HOT updated (i.e with no separate index update required)
pg_table_n_tup_ins counter datname, relname, job, ins, ip, instance, cls Number of rows inserted
pg_table_n_tup_mod counter datname, relname, job, ins, ip, instance, cls Number of rows modified (insert + update + delete)
pg_table_n_tup_newpage_upd counter datname, relname, job, ins, ip, instance, cls Number of rows updated where the successor version goes onto a new heap page
pg_table_n_tup_upd counter datname, relname, job, ins, ip, instance, cls Number of rows updated (includes HOT updated rows)
pg_table_ncols gauge datname, relname, job, ins, ip, instance, cls Number of columns in the table
pg_table_pages gauge datname, relname, job, ins, ip, instance, cls Size of the on-disk representation of this table in pages
pg_table_relid gauge datname, relname, job, ins, ip, instance, cls Relation oid of this table
pg_table_seq_scan counter datname, relname, job, ins, ip, instance, cls Number of sequential scans initiated on this table
pg_table_seq_tup_read counter datname, relname, job, ins, ip, instance, cls Number of live rows fetched by sequential scans
pg_table_size_bytes gauge datname, relname, job, ins, ip, instance, cls Total bytes of this table (including toast, index, toast index)
pg_table_size_indexsize gauge datname, relname, job, ins, ip, instance, cls Bytes of all related indexes of this table
pg_table_size_relsize gauge datname, relname, job, ins, ip, instance, cls Bytes of this table itself (main, vm, fsm)
pg_table_size_toastsize gauge datname, relname, job, ins, ip, instance, cls Bytes of toast tables of this table
pg_table_tbl_scan counter datname, relname, job, ins, ip, instance, cls Number of scans initiated on this table
pg_table_tup_read counter datname, relname, job, ins, ip, instance, cls Number of live rows fetched by scans
pg_table_tuples counter datname, relname, job, ins, ip, instance, cls All txid before this have been frozen on this table
pg_table_vacuum_count counter datname, relname, job, ins, ip, instance, cls Number of times this table has been manually vacuumed (not counting VACUUM FULL)
pg_timestamp gauge job, ins, ip, instance, cls database current timestamp
pg_up gauge job, ins, ip, instance, cls last scrape was able to connect to the server: 1 for yes, 0 for no
pg_uptime gauge job, ins, ip, instance, cls seconds since postmaster start
pg_version gauge job, ins, ip, instance, cls server version number
pg_wait_count gauge datname, job, ins, event, ip, instance, cls Count of WaitEvent on target database
pg_wal_buffers_full counter job, ins, ip, instance, cls Number of times WAL data was written to disk because WAL buffers became full
pg_wal_bytes counter job, ins, ip, instance, cls Total amount of WAL generated in bytes
pg_wal_fpi counter job, ins, ip, instance, cls Total number of WAL full page images generated
pg_wal_records counter job, ins, ip, instance, cls Total number of WAL records generated
pg_wal_reset_time counter job, ins, ip, instance, cls When statistics were last reset
pg_wal_sync counter job, ins, ip, instance, cls Number of times WAL files were synced to disk via issue_xlog_fsync request
pg_wal_sync_time counter job, ins, ip, instance, cls Total amount of time spent syncing WAL files to disk via issue_xlog_fsync request, in seconds
pg_wal_write counter job, ins, ip, instance, cls Number of times WAL buffers were written out to disk via XLogWrite request.
pg_wal_write_time counter job, ins, ip, instance, cls Total amount of time spent writing WAL buffers to disk via XLogWrite request in seconds
pg_write_lsn counter job, ins, ip, instance, cls primary only, location of current wal writing
pg_xact_xmax counter job, ins, ip, instance, cls First as-yet-unassigned txid. txid >= this are invisible.
pg_xact_xmin counter job, ins, ip, instance, cls Earliest txid that is still active
pg_xact_xnum gauge job, ins, ip, instance, cls Current active transaction count
pgbouncer:cls:load1 Unknown job, cls N/A
pgbouncer:cls:load15 Unknown job, cls N/A
pgbouncer:cls:load5 Unknown job, cls N/A
pgbouncer:db:conn_usage Unknown datname, job, ins, ip, instance, host, cls, real_datname, port N/A
pgbouncer:db:conn_usage_reserve Unknown datname, job, ins, ip, instance, host, cls, real_datname, port N/A
pgbouncer:db:pool_current_conn Unknown datname, job, ins, ip, instance, host, cls, real_datname, port N/A
pgbouncer:db:pool_disabled Unknown datname, job, ins, ip, instance, host, cls, real_datname, port N/A
pgbouncer:db:pool_max_conn Unknown datname, job, ins, ip, instance, host, cls, real_datname, port N/A
pgbouncer:db:pool_paused Unknown datname, job, ins, ip, instance, host, cls, real_datname, port N/A
pgbouncer:db:pool_reserve_size Unknown datname, job, ins, ip, instance, host, cls, real_datname, port N/A
pgbouncer:db:pool_size Unknown datname, job, ins, ip, instance, host, cls, real_datname, port N/A
pgbouncer:ins:free_clients Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:free_servers Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:load1 Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:load15 Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:load5 Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:login_clients Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:pool_databases Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:pool_users Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:pools Unknown job, ins, ip, instance, cls N/A
pgbouncer:ins:used_clients Unknown job, ins, ip, instance, cls N/A
pgbouncer_database_current_connections gauge datname, job, ins, ip, instance, host, cls, real_datname, port Current number of connections for this database
pgbouncer_database_disabled gauge datname, job, ins, ip, instance, host, cls, real_datname, port True(1) if this database is currently disabled, else 0
pgbouncer_database_max_connections gauge datname, job, ins, ip, instance, host, cls, real_datname, port Maximum number of allowed connections for this database
pgbouncer_database_min_pool_size gauge datname, job, ins, ip, instance, host, cls, real_datname, port Minimum number of server connections
pgbouncer_database_paused gauge datname, job, ins, ip, instance, host, cls, real_datname, port True(1) if this database is currently paused, else 0
pgbouncer_database_pool_size gauge datname, job, ins, ip, instance, host, cls, real_datname, port Maximum number of server connections
pgbouncer_database_reserve_pool gauge datname, job, ins, ip, instance, host, cls, real_datname, port Maximum number of additional connections for this database
pgbouncer_exporter_agent_up Unknown job, ins, ip, instance, cls N/A
pgbouncer_exporter_last_scrape_time gauge job, ins, ip, instance, cls seconds exporter spending on scrapping
pgbouncer_exporter_query_cache_ttl gauge datname, query, job, ins, ip, instance, cls times to live of query cache
pgbouncer_exporter_query_scrape_duration gauge datname, query, job, ins, ip, instance, cls seconds query spending on scrapping
pgbouncer_exporter_query_scrape_error_count gauge datname, query, job, ins, ip, instance, cls times the query failed
pgbouncer_exporter_query_scrape_hit_count gauge datname, query, job, ins, ip, instance, cls numbers been scrapped from this query
pgbouncer_exporter_query_scrape_metric_count gauge datname, query, job, ins, ip, instance, cls numbers of metrics been scrapped from this query
pgbouncer_exporter_query_scrape_total_count gauge datname, query, job, ins, ip, instance, cls times exporter server was scraped for metrics
pgbouncer_exporter_scrape_duration gauge job, ins, ip, instance, cls seconds exporter spending on scrapping
pgbouncer_exporter_scrape_error_count counter job, ins, ip, instance, cls times exporter was scraped for metrics and failed
pgbouncer_exporter_scrape_total_count counter job, ins, ip, instance, cls times exporter was scraped for metrics
pgbouncer_exporter_server_scrape_duration gauge datname, job, ins, ip, instance, cls seconds exporter server spending on scrapping
pgbouncer_exporter_server_scrape_total_count gauge datname, job, ins, ip, instance, cls times exporter server was scraped for metrics
pgbouncer_exporter_server_scrape_total_seconds gauge datname, job, ins, ip, instance, cls seconds exporter server spending on scrapping
pgbouncer_exporter_up gauge job, ins, ip, instance, cls always be 1 if your could retrieve metrics
pgbouncer_exporter_uptime gauge job, ins, ip, instance, cls seconds since exporter primary server inited
pgbouncer_in_recovery gauge job, ins