暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

用三个不同版本PG构建一个PGD集群

新智锦绣 2024-10-10
48

点击蓝字关注我们


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-certificates
    sudo install -d usr/share/postgresql-common/pgdg
    sudo 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-16
      sudo apt install -y postgresql-15 postgresql-client-15
      sudo 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-pg14
            sudo apt install -y edb-bdr5-pg15
            sudo apt install -y edb-bdr5-pg16


            四.启动三个 Postgres 实例



            在本地安装了三个不同版本的 Postgres 后,就可以创建和启动数据库。在启动每个数据库之前,编辑数据库的postgresql.conf 以加载 PGD 扩展(称为 bdr)。


            4.1 创建 Postgres 14 数据库

            创建一个干净的初始环境:

              admin@localhost $ sudo su postgres
              postgres@localhost $ rm -rf var/lib/postgresql/14
              postgres@localhost $ usr/lib/postgresql/14/bin/initdb var/lib/postgresql/pg14
              The 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 ... ok
              creating subdirectories ... ok
              selecting dynamic shared memory implementation ... posix
              selecting default max_connections ... 100
              selecting default shared_buffers ... 128MB
              selecting default time zone ... Etc/UTC
              creating configuration files ... ok
              running bootstrap script ... ok
              performing post-bootstrap initialization ... ok
              syncing data to disk ... ok


              initdb: warning: enabling "trust" authentication for local connections
              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/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 = 12
                max_wal_senders = 6
                max_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 start
                  waiting for server to start.... done
                  server started


                  4.4 创建 Postgres 15 数据库

                  创建并启动 Postgres 15 数据库:

                    postgres@localhost $ rm -rf var/lib/postgresql/15
                    postgres@localhost $ usr/lib/postgresql/15/bin/initdb var/lib/postgresql/pg15
                    The 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 ... ok
                    creating subdirectories ... ok
                    selecting dynamic shared memory implementation ... posix
                    selecting default max_connections ... 100
                    selecting default shared_buffers ... 128MB
                    selecting default time zone ... Etc/UTC
                    creating configuration files ... ok
                    running bootstrap script ... ok
                    performing post-bootstrap initialization ... ok
                    syncing data to disk ... ok


                    initdb: warning: enabling "trust" authentication for local connections
                    initdb: 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 = 12
                      max_wal_senders = 6
                      max_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 start
                        waiting for server to start.... done
                        server started


                        4.7 创建 Postgres 16 数据库

                        创建并启动Postgres 16 数据库:

                          postgres@localhost $ rm -rf /var/lib/postgresql/16
                          postgres@localhost $ /usr/lib/postgresql/16/bin/initdb /var/lib/postgresql/pg16
                          The 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 ... ok
                          creating subdirectories ... ok
                          selecting dynamic shared memory implementation ... posix
                          selecting default max_connections ... 100
                          selecting default shared_buffers ... 128MB
                          selecting default time zone ... Etc/UTC
                          creating configuration files ... ok
                          running bootstrap script ... ok
                          performing post-bootstrap initialization ... ok
                          syncing data to disk ... ok


                          initdb: warning: enabling "trust" authentication for local connections
                          initdb: 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 = 12
                            max_wal_senders = 6
                            max_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 start
                              waiting 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 DATABASE
                                  postgres@localhost $ /usr/lib/postgresql/14/bin/psql -p 8014 pgdtest -c "CREATE EXTENSION bdr CASCADE;"
                                  CREATE EXTENSION
                                  postgres@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 DATABASE
                                    postgres@localhost $ /usr/lib/postgresql/15/bin/psql -p 8015 pgdtest -c "CREATE EXTENSION bdr CASCADE;"
                                    CREATE EXTENSION
                                    postgres@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 DATABASE
                                      postgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 pgdtest -c "CREATE EXTENSION bdr CASCADE;"
                                      CREATE EXTENSION
                                      postgres@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 TABLE
                                        postgres@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
                                          ----
                                           1
                                          32
                                          19
                                           0
                                          (4 rows)

                                          接着,从 Postgres 15 节点访问此数据以查看复制操作:

                                            postgres@localhost $ /usr/lib/postgresql/15/bin/psql -p 8015 pgdtest -c "SELECT * FROM x;"
                                            a
                                            ----
                                             1
                                            32
                                            19
                                             0
                                            (4 rows)

                                            可以看到,来自 Postgres 14 节点的数据可在 Postgres 15 节点上无缝使用,展示了成功的数据复制。接着,再检查 Postgres 16 节点:

                                              postgres@localhost $ /usr/lib/postgresql/16/bin/psql -p 8016 pgdtest -c "SELECT * FROM x;"
                                              a
                                              ----
                                               1
                                              32
                                              19
                                               0
                                              (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
                                                  -------
                                                      1
                                                     32
                                                     19
                                                      0
                                                  10000
                                                  (5 rows)

                                                  在Postgres16上进行的数据输入在 Postgres 14 上也成功复制。这种无缝复制展示了多版本 Postgres 构建PGD集群是没有问题的。

                                                  本例只是为了验证不同版PG可以构建PGD集群功能,至于冲突解决及写入领导者的配置相关内容可以查看往期的文章。


                                                  六.总结



                                                  PG复制的挑战主要包括管理滚动升级、确保节点之间的数据一致性、处理DDL更改以及在集群中正确配置节点以避免冲突并确保平稳运行。PGD完美支持并解决这些挑战。

                                                  本文展示了PGD支持运行不同PG版本,从而可以实现滚动升级。在生产环境中还是不建议在同一个PGD集群运行不同的PG版本。

                                                  PGD 通过支持事务性 DDL 复制和 DML 来增强 Postgres,从而实现跨混合版本集群的无缝数据复制。它还有助于滚动升级和地理分布式数据管理,同时保持对数据治理策略的合规性。





                                                  扫码进 EDB 微信群

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


                                                  文章转载自新智锦绣,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                                  评论