Citus
PostgreSQL 分片的原生分布式扩展
Citus 是一个 PostgreSQL 扩展,它将 PostgreSQL 转换为分布式数据库,能够跨多个节点水平扩展以处理大量数据和查询。
自 Patroni v3.0 以来,已原生支持 Citus 高可用性,简化了 Citus 集群的设置。Pigsty 也为此提供原生支持。
注意:最新版本的 Citus(12.1.6)支持 PostgreSQL 版本 16、15 和 14,但不支持 PostgreSQL 17,也缺乏官方 ARM64 支持。Pigsty 的扩展仓库为 Citus 提供 ARM64 包,但在 ARM 架构上使用时请谨慎。
Citus 集群
Pigsty 原生支持 Citus。参考 conf/citus.yml
。
此示例使用四节点沙盒,包含一个名为 pg-citus
的 Citus 集群,由一个双节点协调器集群 pg-citus0
和两个工作节点集群 pg-citus1
和 pg-citus2
组成。
pg-citus:
hosts:
10.10.10.10: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.2/24 ,pg_seq: 1, pg_role: primary }
10.10.10.11: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.2/24 ,pg_seq: 2, pg_role: replica }
10.10.10.12: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.3/24 ,pg_seq: 1, pg_role: primary }
10.10.10.13: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.4/24 ,pg_seq: 1, pg_role: primary }
vars:
pg_mode: citus # pgsql 集群模式:citus
pg_version: 16 # Citus 暂不支持 pg16
pg_shard: pg-citus # Citus 分片名称:pg-citus
pg_primary_db: citus # Citus 使用的主数据库
pg_vip_enabled: true # 为 Citus 集群启用 VIP
pg_vip_interface: eth1 # 所有成员的 VIP 接口
pg_dbsu_password: DBUser.Postgres # Citus 集群的所有 DBSU 密码
pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ] # 安装这些扩展
pg_libs: 'citus, pg_cron, pg_stat_statements' # Citus 将由 Patroni 自动添加
pg_users: [{ name: dbuser_citus ,password: DBUser.Citus ,pgbouncer: true ,roles: [ dbrole_admin ] }]
pg_databases: [{ name: citus ,owner: dbuser_citus ,extensions: [ citus, vector, topn, pg_cron, hll ] }]
pg_parameters:
cron.database_name: citus
citus.node_conninfo: 'sslmode=require sslrootcert=/pg/cert/ca.crt sslmode=verify-full'
pg_hba_rules:
- { user: 'all' ,db: all ,addr: 127.0.0.1/32 ,auth: ssl ,title: 'all user ssl access from localhost' }
- { user: 'all' ,db: all ,addr: intra ,auth: ssl ,title: 'all user ssl access from intranet' }
与标准 PostgreSQL 集群相比,Citus 集群配置有一些特定要求。首先,确保 Citus 扩展被下载、安装、加载和启用。这涉及以下四个参数:
repo_packages
:必须包含citus
扩展,或者您需要使用带有 Citus 扩展的 PostgreSQL 离线包。pg_extensions
:必须包含citus
扩展,意味着您需要在每个节点上安装citus
扩展。pg_libs
:必须包含citus
扩展,且必须在列表中排第一,但现在 Patroni 会自动处理。pg_databases
:定义安装了citus
扩展的主数据库。
另外,确保 Citus 集群的配置正确:
pg_mode
:必须设置为citus
以告知 Patroni 使用 Citus 模式。pg_primary_db
:指定主数据库名称,该数据库必须安装citus
扩展(此处命名为citus
)。pg_shard
:指定统一名称作为所有水平分片 PG 集群的前缀(例如,pg-citus
)。pg_group
:指定分片编号,协调器集群从零开始,工作节点集群递增。pg_cluster
:必须匹配 [pg_shard
] 和 [pg_group
] 的组合。pg_dbsu_password
:设置非空明文密码以确保 Citus 正常运行。pg_parameters
:建议设置citus.node_conninfo
参数,强制 SSL 访问并要求节点间客户端证书验证。
配置完成后,使用 pgsql.yml
部署 Citus 集群,就像常规 PostgreSQL 集群一样。
管理 Citus 集群
定义 Citus 集群后,使用相同的剧本 pgsql.yml
部署 Citus 集群:
./pgsql.yml -l pg-citus # 部署 Citus 集群 pg-citus
任何 DBSU 用户(postgres
)都可以使用 patronictl
(别名:pg
)列出 Citus 集群的状态:
$ pg list
+ Citus cluster: pg-citus ----------+---------+-----------+----+-----------+--------------------+
| Group | Member | Host | Role | State | TL | Lag in MB | Tags |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
| 0 | pg-citus0-1 | 10.10.10.10 | Leader | running | 1 | | clonefrom: true |
| | | | | | | | conf: tiny.yml |
| | | | | | | | spec: 20C.40G.125G |
| | | | | | | | version: '16' |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
| 1 | pg-citus1-1 | 10.10.10.11 | Leader | running | 1 | | clonefrom: true |
| | | | | | | | conf: tiny.yml |
| | | | | | | | spec: 10C.20G.125G |
| | | | | | | | version: '16' |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
| 2 | pg-citus2-1 | 10.10.10.12 | Leader | running | 1 | | clonefrom: true |
| | | | | | | | conf: tiny.yml |
| | | | | | | | spec: 10C.20G.125G |
| | | | | | | | version: '16' |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
| 2 | pg-citus2-2 | 10.10.10.13 | Replica | streaming | 1 | 0 | clonefrom: true |
| | | | | | | | conf: tiny.yml |
| | | | | | | | spec: 10C.20G.125G |
| | | | | | | | version: '16' |
+-------+-------------+-------------+---------+-----------+----+-----------+--------------------+
每个水平分片集群都可以作为单独的 PGSQL 集群处理,使用 pg
(patronictl
)命令管理。注意使用 pg
管理 Citus 集群时,必须使用 --group
参数指定集群分片编号:
pg list pg-citus --group 0 # 使用 --group 0 指定分片编号
Citus 有一个名为 pg_dist_node
的系统表来记录节点信息,Patroni 会自动维护。
PGURL=postgres://postgres:DBUser.Postgres@10.10.10.10/citus
psql $PGURL -c 'SELECT * FROM pg_dist_node;' # 查看节点信息
另外,您可以查看用户认证信息(仅限超级用户):
$ psql $PGURL -c 'SELECT * FROM pg_dist_authinfo;' # 查看节点认证信息(仅超级用户)
然后您可以使用常规业务用户(例如,具有 DDL 权限的 dbuser_citus
)访问 Citus 集群:
psql postgres://dbuser_citus:DBUser.Citus@10.10.10.10/citus -c 'SELECT * FROM pg_dist_node;'
使用 Citus 集群
使用 Citus 集群时,我们强烈建议阅读 Citus 官方文档 了解其架构和核心概念。
关键是理解 Citus 中五种类型的表、它们的特征和用例:
- 分布式表
- 引用表
- 本地表
- 本地管理表
- 模式表
在协调器节点上,您可以创建分布式表和引用表,并从任何数据节点查询它们。自版本 11.2 以来,任何 Citus 数据库节点都可以充当协调器。
我们可以使用 pgbench
创建一些表,将主表(pgbench_accounts
)分布到各个节点,并将其他较小的表用作引用表:
PGURL=postgres://dbuser_citus:DBUser.Citus@10.10.10.10/citus
pgbench -i $PGURL
psql $PGURL <<-EOF
SELECT create_distributed_table('pgbench_accounts', 'aid'); SELECT truncate_local_data_after_distributing_table('public.pgbench_accounts');
SELECT create_reference_table('pgbench_branches') ; SELECT truncate_local_data_after_distributing_table('public.pgbench_branches');
SELECT create_reference_table('pgbench_history') ; SELECT truncate_local_data_after_distributing_table('public.pgbench_history');
SELECT create_reference_table('pgbench_tellers') ; SELECT truncate_local_data_after_distributing_table('public.pgbench_tellers');
EOF
运行读写基准测试:
pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:DBUser.Citus@10.10.10.10/citus # 直连协调器 5432 端口
pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:DBUser.Citus@10.10.10.10:6432/citus # 通过连接池,减少客户端连接数压力,可以有效提高整体吞吐。
pgbench -nv -P1 -c10 -T500 postgres://dbuser_citus:DBUser.Citus@10.10.10.13/citus # 任意 primary 节点都可以作为 coordinator
pgbench --select-only -nv -P1 -c10 -T500 postgres://dbuser_citus:DBUser.Citus@10.10.10.11/citus # 可以发起只读查询
生产部署
生产环境的 Citus 部署通常需要为协调器和每个工作节点集群提供物理复制。
例如,在 simu.yml
中有一个 10 节点集群:
pg-citus: # citus 组
hosts:
10.10.10.50: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 0, pg_role: primary }
10.10.10.51: { pg_group: 0, pg_cluster: pg-citus0 ,pg_vip_address: 10.10.10.60/24 ,pg_seq: 1, pg_role: replica }
10.10.10.52: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 0, pg_role: primary }
10.10.10.53: { pg_group: 1, pg_cluster: pg-citus1 ,pg_vip_address: 10.10.10.61/24 ,pg_seq: 1, pg_role: replica }
10.10.10.54: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 0, pg_role: primary }
10.10.10.55: { pg_group: 2, pg_cluster: pg-citus2 ,pg_vip_address: 10.10.10.62/24 ,pg_seq: 1, pg_role: replica }
10.10.10.56: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 0, pg_role: primary }
10.10.10.57: { pg_group: 3, pg_cluster: pg-citus3 ,pg_vip_address: 10.10.10.63/24 ,pg_seq: 1, pg_role: replica }
10.10.10.58: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 0, pg_role: primary }
10.10.10.59: { pg_group: 4, pg_cluster: pg-citus4 ,pg_vip_address: 10.10.10.64/24 ,pg_seq: 1, pg_role: replica }
vars:
pg_mode: citus # pgsql 集群模式:citus
pg_version: 16 # citus 没有 pg16 可用
pg_shard: pg-citus # citus 分片名称:pg-citus
pg_primary_db: citus # citus 使用的主数据库
pg_vip_enabled: true # 为 citus 集群启用 vip
pg_vip_interface: eth1 # 所有成员的 vip 接口
pg_dbsu_password: DBUser.Postgres # 为 citus 启用 dbsu 密码访问
pg_extensions: [ citus, postgis, pgvector, topn, pg_cron, hll ] # 安装这些扩展
pg_libs: 'citus, pg_cron, pg_stat_statements' # citus 将由 patroni 自动添加
pg_users: [{ name: dbuser_citus ,password: DBUser.Citus ,pgbouncer: true ,roles: [ dbrole_admin ] }]
pg_databases: [{ name: citus ,owner: dbuser_citus ,extensions: [ citus, vector, topn, pg_cron, hll ] }]
pg_parameters:
cron.database_name: citus
citus.node_conninfo: 'sslrootcert=/pg/cert/ca.crt sslmode=verify-full'
pg_hba_rules:
- { user: 'all' ,db: all ,addr: 127.0.0.1/32 ,auth: ssl ,title: 'all user ssl access from localhost' }
- { user: 'all' ,db: all ,addr: intra ,auth: ssl ,title: 'all user ssl access from intranet' }
我们将在后续教程中涵盖一系列高级主题:
- 读写分离
- 故障转移处理
- 一致性备份和恢复
- 高级监控和故障排除
- 连接池