
点击蓝字关注我们
PGD(EDB Postgres Distributed) 极致高可用解决方案前面文章已经多次介绍。PGD在普通Postgres 逻辑复制之上添加的最酷的功能之一是除了DML之外还能够复制事务性DDL。本文将使用 PGD 在一台机器上构建一个三节点 Postgres 集群,每个节点运行不同版本的 Postgres。来观察DDL和DML在这些节点之间无缝复制。
一.复制:Postgres实现可扩展性及可靠性集群的关键
为了确保Postgres集群环境高可用性,需要在数据库集群中维护数据的多个副本。这些副本之间的一致性至关重要。还需要支持 Postgres 集群的滚动升级、处理节点的删除以进行维护,以及管理集群内节点之间的DDL更改。在遵守数据治理策略的同时,可能需要低延迟的读副本,甚至数据处于不同地理分布。
我们可能无法通过普通Postgres 甚至某些典型的高可用性 (HA) 工具来完成这些任务。要理解这一点,有必要看看 Postgres 中的两种复制类型:物理复制和逻辑复制。
物理复制:想象两个Postgres节点:一个接收直接用户查询的“上游”节点,和一个订阅上游节点更改的“下游”节点。物理复制通过网络将字节从上游节点上的磁盘传输到下游节点,然后逐字写回磁盘。
由于物理复制基于数据块(数据页)的更改进行复制,因此两个节点都不了解它最初从用户复制什么数据。因此,如果上游节点和下游节点运行不同版本的Postgres,下游节点可能无法正确解释来自上游节点的物理数据。因此,诸如滚动升级之类的要求(例如在升级集群时临时从Postgres 12节点复制到Postgres 13节点)通过一些高可用工具就可能无法实现。
逻辑复制: Postgres逻辑复制保持对用户数据的感知,将插入、更新和删除等逻辑更改从上游节点复制到下游节点。这种更高级别的感知允许集群运行Postgres 的混合版本。
然而,Postgres中的逻辑复制有明显的局限性,最重要的是无法复制DDL。虽然可以创建/回滚表更改,但通过标准 Postgres 中的逻辑复制顺利执行此类操作仍然很困难。
PGD(EDB Postgres Distributed):在逻辑复制之上添加的最酷的功能之一是除了DML之外还能够复制事务性DDL。
虽然不鼓励永久运行不同版本的Postgres,但PGD是支持滚动升级的。因此本文通过运行混合版本PGD数据库集群来验证。本例采用一台运行Debian 12 的 amd64 机器来测试。
二.获取Postgres 14、15和16
首先,我们按照postgresql.org的官方说明来配置软件包存储库。
# Import the repository signing key:sudo apt install curl ca-certificatessudo install -d usr/share/postgresql-common/pgdgsudo curl -o usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc# Create the repository configuration file:sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > etc/apt/sources.list.d/pgdg.list'# Update the package lists:sudo apt update
然后,安装三个版本的 Postgres。
sudo apt install -y postgresql-16 postgresql-client-16sudo apt install -y postgresql-15 postgresql-client-15sudo apt install -y postgresql-14 postgresql-client-14
三.获取EDB PGD
如果没有EDB帐户,可以免费注册以获得 EDB 软件存储库的试用订阅。获得令牌后(之前有介绍),设置环境变量:
export EDB_SUBSCRIPTION_TOKEN=<your-repo-token>
设置软件包存储库:
curl -1sLf "https://downloads.enterprisedb.com/$EDB_SUBSCRIPTION_TOKEN/postgres_distributed/setup.deb.sh" | sudo -E bash
然后为每个版本安装pgd:
sudo apt install -y edb-bdr5-pg14sudo apt install -y edb-bdr5-pg15sudo apt install -y edb-bdr5-pg16
四.启动三个 Postgres 实例
在本地安装了三个不同版本的 Postgres 后,就可以创建和启动数据库。在启动每个数据库之前,编辑数据库的postgresql.conf 以加载 PGD 扩展(称为 bdr)。
4.1 创建 Postgres 14 数据库
创建一个干净的初始环境:
admin@localhost $ sudo su postgrespostgres@localhost $ rm -rf var/lib/postgresql/14postgres@localhost $ usr/lib/postgresql/14/bin/initdb var/lib/postgresql/pg14The files belonging to this database system will be owned by user "postgres".This user must also own the server process.The database cluster will be initialized with locale "C.UTF-8".The default database encoding has accordingly been set to "UTF8".The default text search configuration will be set to "english".Data page checksums are disabled.creating directory var/lib/postgresql/pg14 ... okcreating subdirectories ... okselecting dynamic shared memory implementation ... posixselecting default max_connections ... 100selecting default shared_buffers ... 128MBselecting default time zone ... Etc/UTCcreating configuration files ... okrunning bootstrap script ... okperforming post-bootstrap initialization ... oksyncing data to disk ... okinitdb: warning: enabling "trust" authentication for local connectionsYou can change this by editing pg_hba.conf or using the option -A, or--auth-local and --auth-host, the next time you run initdb.Success. You can now start the database server using:/usr/lib/postgresql/14/bin/pg_ctl -D var/lib/postgresql/pg14 -l logfile start
4.2 为 PGD 配置pg14的postgresql.conf
postgres@localhost $ echo "shared_preload_libraries = 'bdr'wal_level = 'logical'track_commit_timestamp = on# For bigger clusters you may want to decrease shared buffers or the# OS may complain you are using too much shared memory.shared_buffers = 1MB# These depend on the size of the cluster.max_worker_processes = 12max_wal_senders = 6max_replication_slots = 6" | tee -a var/lib/postgresql/pg14/postgresql.conf
4.3 启动 Postgres 14 数据库
在端口 8014 上启动 Postgres 14 数据库:
postgres@localhost $ usr/lib/postgresql/14/bin/pg_ctl -o "-p 8014" -D var/lib/postgresql/pg14 -l tmp/logfile14 startwaiting for server to start.... doneserver started
4.4 创建 Postgres 15 数据库
创建并启动 Postgres 15 数据库:
postgres@localhost $ rm -rf var/lib/postgresql/15postgres@localhost $ usr/lib/postgresql/15/bin/initdb var/lib/postgresql/pg15The files belonging to this database system will be owned by user "postgres".This user must also own the server process.The database cluster will be initialized with locale "C.UTF-8".The default database encoding has accordingly been set to "UTF8".The default text search configuration will be set to "english".Data page checksums are disabled.creating directory var/lib/postgresql/pg15 ... okcreating subdirectories ... okselecting dynamic shared memory implementation ... posixselecting default max_connections ... 100selecting default shared_buffers ... 128MBselecting default time zone ... Etc/UTCcreating configuration files ... okrunning bootstrap script ... okperforming post-bootstrap initialization ... oksyncing data to disk ... okinitdb: warning: enabling "trust" authentication for local connectionsinitdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.Success. You can now start the database server using:/usr/lib/postgresql/15/bin/pg_ctl -D var/lib/postgresql/pg15 -l logfile start
4.5 为 PGD 配置PG15的postgresql.conf
postgres@localhost $ echo "shared_preload_libraries = 'bdr'wal_level = 'logical'track_commit_timestamp = on# For bigger clusters you may want to decrease shared buffers or the# OS may complain you are using too much shared memory.shared_buffers = 1MB# These depend on the size of the cluster.max_worker_processes = 12max_wal_senders = 6max_replication_slots = 6" | tee -a /var/lib/postgresql/pg15/postgresql.conf
4.6 启动 Postgres 15 数据库
启动 Postgres 15 数据库,在端口 8015 上运行:
postgres@localhost $ /usr/lib/postgresql/15/bin/pg_ctl -o "-p 8015" -D /var/lib/postgresql/pg15 -l /tmp/logfile15 startwaiting for server to start.... doneserver started
4.7 创建 Postgres 16 数据库
创建并启动Postgres 16 数据库:
postgres@localhost $ rm -rf /var/lib/postgresql/16postgres@localhost $ /usr/lib/postgresql/16/bin/initdb /var/lib/postgresql/pg16The files belonging to this database system will be owned by user "postgres".This user must also own the server process.The database cluster will be initialized with locale "C.UTF-8".The default database encoding has accordingly been set to "UTF8".The default text search configuration will be set to "english".Data page checksums are disabled.creating directory /var/lib/postgresql/pg15 ... okcreating subdirectories ... okselecting dynamic shared memory implementation ... posixselecting default max_connections ... 100selecting default shared_buffers ... 128MBselecting default time zone ... Etc/UTCcreating configuration files ... okrunning bootstrap script ... okperforming post-bootstrap initialization ... oksyncing data to disk ... okinitdb: warning: enabling "trust" authentication for local connectionsinitdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.Success. You can now start the database server using:/usr/lib/postgresql/16/bin/pg_ctl -D /var/lib/postgresql/pg16 -l logfile start
4.8 为 PGD 配置PG16的 postgresql.conf
为 PGD 配置 Postgres 16 数据库:
postgres@localhost $ echo "shared_preload_libraries = 'bdr'wal_level = 'logical'track_commit_timestamp = on# For bigger clusters you may want to decrease shared buffers or the# OS may complain you are using too much shared memory.shared_buffers = 1MB# These depend on the size of the cluster.max_worker_processes = 12max_wal_senders = 6max_replication_slots = 6" | tee -a /var/lib/postgresql/pg16/postgresql.conf
4.9 启动 Postgres 16 数据库
启动 Postgres 16 数据库,监听端口 8016:
postgres@localhost $ /usr/lib/postgresql/16/bin/pg_ctl -o "-p 8016" -D /var/lib/postgresql/pg16 -l /tmp/logfile16 startwaiting for server to start.... done
五.将三个数据库变成一个PGD集群
我们已经设置了三个节点,它们正在运行PGD 扩展,但它们尚未相互连接。下一步是将这些节点互连。首先,验证每个正在运行的数据库版本,以确保已正确设置:
postgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 -c 'select version()'version-----------------------------------------------------------------------------------------------------------------------PostgreSQL 14.12 (Debian 14.12-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit(1 row)postgres@localhost $ /usr/lib/postgresql/15/bin/psql -p 8015 -c 'select version()'version---------------------------------------------------------------------------------------------------------------------PostgreSQL 15.7 (Debian 15.7-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit(1 row)postgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 -c 'select version()'version---------------------------------------------------------------------------------------------------------------------PostgreSQL 16.3 (Debian 16.3-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit(1 row)
5.1 构建PGD集群
要构建PGD集群,对每个节点执行以下步骤:
创建 BDR 扩展:运行 CREATE EXTENSION bdr CASCADE;。
创建PGD节点:在每个节点上使用bdr.create_node将其注册为PGD节点。
创建节点组:选择一个节点,创建节点组。
加入节点:对于其他两个节点,提供加入创建的节点组的详细信息。
在 Postgres 14 服务器上,做如下步骤:创建用于表复制的数据库、设置扩展、创建 PGD 节点并形成 PGD 节点组。
postgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 postgres -c "CREATE DATABASE pgdtest;"CREATE DATABASEpostgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 pgdtest -c "CREATE EXTENSION bdr CASCADE;"CREATE EXTENSIONpostgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 pgdtest -c "SELECT bdr.create_node(node_name := 'pg14', local_dsn := 'port=8014 dbname=pgdtest host=localhost user=postgres');"create_node-------------1151355342(1 row)postgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 pgdtest -c "SELECT bdr.create_node_group(node_group_name := 'pgdtest-group');"create_node_group-------------------117160161(1 row)
上面步骤创建了一个 PGD 节点和一个 PGD 节点组。现在,可以对 Postgres 15 节点执行相同的操作。加入上面现有的节点组,而不是创建新的节点组。
postgres@localhost $ /usr/lib/postgresql/15/bin/psql -p 8015 postgres -c "CREATE DATABASE pgdtest;"CREATE DATABASEpostgres@localhost $ /usr/lib/postgresql/15/bin/psql -p 8015 pgdtest -c "CREATE EXTENSION bdr CASCADE;"CREATE EXTENSIONpostgres@localhost $ /usr/lib/postgresql/15/bin/psql -p 8015 pgdtest -c "SELECT bdr.create_node(node_name := 'pg15', local_dsn := 'port=8015 dbname=pgdtest host=localhost user=postgres');"create_node-------------2481762504(1 row)postgres@localhost $ /usr/lib/postgresql/15/bin/psql -p 8015 pgdtest -c "SELECT bdr.join_node_group(join_target_dsn := 'port=8014 dbname=pgdtest host=localhost user=postgres');"join_node_group-----------------(1 row)
接下来对PG16做相同的事情,加入现有的节点组。
postgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 postgres -c "CREATE DATABASE pgdtest;"CREATE DATABASEpostgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 pgdtest -c "CREATE EXTENSION bdr CASCADE;"CREATE EXTENSIONpostgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 pgdtest -c "SELECT bdr.create_node(node_name := 'pg16', local_dsn := 'port=8016 dbname=pgdtest host=localhost user=postgres');"create_node-------------1945575858(1 row)postgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 pgdtest -c "SELECT bdr.join_node_group(join_target_dsn := 'port=8014 dbname=pgdtest host=localhost user=postgres');"join_node_group-----------------(1 row)
5.2 测试和验证
通过上面的设置,实现了使用多个版本的 Postgres 设置了一个PGD集群,支持跨不同节点的数据复制并且能够在集群内复制数据定义语言(DDL)和数据操作语言(DML)操作。通常,在实践中,最好指定单个节点作为写入领导者,以避免跨节点混合写入发生冲突。
首先在 Postgres 14 节点上创建一个表并向其中插入数据:
postgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 pgdtest -c "CREATE TABLE x (a int primary key);"CREATE TABLEpostgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 pgdtest -c "INSERT INTO x VALUES (1), (32), (19), (0);"INSERT 0 4
查询:
postgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 pgdtest -c "SELECT * FROM x;"a----132190(4 rows)
接着,从 Postgres 15 节点访问此数据以查看复制操作:
postgres@localhost $ /usr/lib/postgresql/15/bin/psql -p 8015 pgdtest -c "SELECT * FROM x;"a----132190(4 rows)
可以看到,来自 Postgres 14 节点的数据可在 Postgres 15 节点上无缝使用,展示了成功的数据复制。接着,再检查 Postgres 16 节点:
postgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 pgdtest -c "SELECT * FROM x;"a----132190(4 rows)
输出可以看到,也成功复制。
最后,测试跨节点更新,在 Postgres 16 节点上添加一个新条目并从 Postgres 14 检索更新的列表:
postgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 pgdtest -c "INSERT INTO x VALUES (10000);"INSERT 0 1
postgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 pgdtest -c "SELECT * FROM x;"a-------13219010000(5 rows)
在Postgres16上进行的数据输入在 Postgres 14 上也成功复制。这种无缝复制展示了多版本 Postgres 构建PGD集群是没有问题的。
本例只是为了验证不同版PG可以构建PGD集群功能,至于冲突解决及写入领导者的配置相关内容可以查看往期的文章。
六.总结
PG复制的挑战主要包括管理滚动升级、确保节点之间的数据一致性、处理DDL更改以及在集群中正确配置节点以避免冲突并确保平稳运行。PGD完美支持并解决这些挑战。
本文展示了PGD支持运行不同PG版本,从而可以实现滚动升级。在生产环境中还是不建议在同一个PGD集群运行不同的PG版本。
PGD 通过支持事务性 DDL 复制和 DML 来增强 Postgres,从而实现跨混合版本集群的无缝数据复制。它还有助于滚动升级和地理分布式数据管理,同时保持对数据治理策略的合规性。

扫码进 EDB 微信群

发现“分享”和“赞”了吗,戳我看看吧




