• PostgreSQL - 基于pg_basebackup实现主从流复制


    1 数据库节点

    节点ip节点角色
    192.168.163.133主节点
    192.168.163.134从节点

    2 安装PostgreSQL

    2.1 创建postgres用户

    PostgreSQL不允许使用linux root用户进行操作,所以需要为其创建一个postgres用户。这一步不是必须的,如果不创建,在安装PostgreSQL时,会自动创建一个名为 postgres 的用户出来,不过建议自己创建一个。

    [postgres@n1 12]$ groupadd postgres
    [postgres@n1 12]$ useradd postgres -g postgres
    
    • 1
    • 2

    2.2 安装PostgreSQL

    进入PostgreSQL官网下载页面PostgreSQL下载地址
    选择相应的操作系统,PostgreSQL版本后,会出现一个安装脚本。
    在这里插入图片描述
    在这里插入图片描述
    如下就是上面截图中的安装shell脚本

    # Install the repository RPM:
    sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
    
    # Install PostgreSQL:
    sudo yum install -y postgresql12-server
    
    # Optionally initialize the database and enable automatic start:
    sudo /usr/pgsql-12/bin/postgresql-12-setup initdb
    sudo systemctl enable postgresql-12
    sudo systemctl start postgresql-12
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    不过后面三行脚本可以不执行,sudo /usr/pgsql-12/bin/postgresql-12-setup initdb是初始化一个数据库实例;后面两句就开机启动跟启动当前实例。我们后续在安装完后自己初始化一个实例出来,所以后面三行可以注释掉。

    主从两个节点上都安装上PostgreSQL。

    3 配置主节点

    初始化一个实例出来,作为主节点。
    切换到postgres用户,初始化一个节点

    [postgres@n1 12]$ su - postgres
    [postgres@n1 12]$ /usr/pgsql-12/bin/pg_ctl initdb -D /home/app/pgsql/12/stream-test
    
    • 1
    • 2

    上面命令在/home/app/pgsql/12/目录下创建了一个PostgreSQL实例,当执行完上面命令后,会在stream-test目录下生成PostgreSQL相应的实例文件及文件夹。如图
    在这里插入图片描述
    初始化好主节点后,可以进行相应的配置

    [postgres@n1 stream-test]$ vim postgresql.conf
    
    listen_addresses = '*'          # 这一行一定要改,默认是localhost,如果是localhost,则不能进行远程登陆;
    port = 5443                     # 建议修改一下端口号
    
    • 1
    • 2
    • 3
    • 4

    其它的可以暂时不用配置了。下面配置pg_hba.conf

    vim pg_hba.conf
    
    # "local" is for Unix domain socket connections only
    local   all             all                                     trust
    # IPv4 local connections:
    host    all             all             127.0.0.1/32            trust
    ##### 这行配置是我自己添加的  192.168.163.0/24  表示在192.168.163这个网段下的所有机器都允许以任务用户访问任何数据库,其它的配置都是自己带的,不用修改。
    ##### 当前也可以更精确的配置,比如 192.168.163.134/32,意味着只允许192.168.163.134进行远程访问
    host    all             all             192.168.163.0/24            trust
    # IPv6 local connections:
    host    all             all             ::1/128                 trust
    # Allow replication connections from localhost, by a user with the
    # replication privilege.
    local   replication     all                                     trust
    host    replication     all             127.0.0.1/32            trust
    ##### 这行配置是我自己添加的
    host    replication     all             192.168.163.0/24                 trust
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    使用四个#号进行注释的部分是需要配置的,其它的不用修改。
    配置完成后,启动主节点。

    [postgres@n1 stream-test]$ /usr/pgsql-12/bin/pg_ctl start -D /home/app/pgsql/12/stream-test/
    
    • 1

    -D 表示启动PostgreSQL进程时,使用我们上面初始化出来的实例。有点像redis的意思。
    现在主节点就配置完成了,下面来配置从节点。

    4 配置从节点

    从节点就简单一些,在安装了PostgreSQL后,只需要执行一条命令就OKAY了。
    强烈建议,从节点与主节点的实例所在的目录都是相同的。

    [root@n2 ~]# mkdir -p /home/app/pgsql/12/stream-test
    [root@n2 ~]# cd /home/app/pgsql/12/
    [root@n2 12]# chown -R postgres:postgres stream-test/
    [root@n2 12]# chmod 700 stream-test/
    [root@n2 12]# su - postgres
    
    • 1
    • 2
    • 3
    • 4
    • 5

    直接切换到postgres用户去创建目录好像用更好一些。
    然后从主节点拉取数据过来,主节点上就不需要执行实例初始化的过程了,从节点的数据应该是从主节点那边拉取过来的,所以从节点不应该有自己的初始化数据。

    pg_basebackup -D /home/app/pgsql/12/stream-test/ -h 192.168.163.133 -p 5443 -U postgres -Fp -R -X s -P -v
    
    • 1

    上面命令即完成了数据同步,-R 参数表示以从replication的方式进行数据同步,可以认为是以从从节点的身份进行数据同步。-X s表示同步方式是流式数据同步。查看同步的数据目录
    在这里插入图片描述
    跟主节点的目录结构不同,这里多了一个standby.signal文件,这默认是一个空文件,其实是一个标识文件。
    也是因为使用了-R参数,所以在同步的数据里,所以会在postgresql.auto.conf里配置上 primary_conninfo信息。

    [postgres@n2 stream-test]$ vim postgresql.auto.conf
    
    • 1

    在这里插入图片描述
    现在启动从节点

    [postgres@n2 12]$ /usr/pgsql-12/bin/pg_ctl start -D /home/app/pgsql/12/stream-test/
    
    waiting for server to start....2022-09-18 16:57:49.669 CST [44990] LOG:  starting PostgreSQL 12.12 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
    2022-09-18 16:57:49.669 CST [44990] LOG:  listening on IPv4 address "0.0.0.0", port 5443
    2022-09-18 16:57:49.669 CST [44990] LOG:  listening on IPv6 address "::", port 5443
    2022-09-18 16:57:49.669 CST [44990] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5443"
    2022-09-18 16:57:49.670 CST [44990] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5443"
    2022-09-18 16:57:49.677 CST [44990] LOG:  redirecting log output to logging collector process
    2022-09-18 16:57:49.677 CST [44990] HINT:  Future log output will appear in directory "log".
     done
    server started
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果此时观察一下启动日志,会发现从节点以只读形式启动的。

    [postgres@n2 stream-test]$ cd /home/app/pgsql/12/stream-test/log/
    [postgres@n2 log]$ vim postgresql-Sun.log
    
    • 1
    • 2

    在这里插入图片描述
    这样一个PostgreSQL的主从复制就搭建好的,其实就用了一个命令/usr/pgsql-12/bin/pg_ctl start -D /home/app/pgsql/12/stream-test/,感觉比mysql要方便很多。

    5 验证主从同步

    连接主节点PostgreSQL实例

    [postgres@n1 stream-test]$ psql -p 5443
    postgres=# \l
                                      List of databases
       Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
    -----------+----------+----------+-------------+-------------+-----------------------
     postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
     template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
               |          |          |             |             | postgres=CTc/postgres
     template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
               |          |          |             |             | postgres=CTc/postgres
    (3 rows)
    
    postgres=# create table t1(id int,name varchar(32),create_time timestamptz);
    CREATE TABLE
    postgres=# 
    postgres=# insert into t1 select generate_series(1,10), 'name1-10', now();
    INSERT 0 10
    postgres=# select * from t1;
     id |   name   |         create_time          
    ----+----------+------------------------------
      1 | name1-10 | 2022-09-18 17:04:12.39975+08
      2 | name1-10 | 2022-09-18 17:04:12.39975+08
      3 | name1-10 | 2022-09-18 17:04:12.39975+08
      4 | name1-10 | 2022-09-18 17:04:12.39975+08
      5 | name1-10 | 2022-09-18 17:04:12.39975+08
      6 | name1-10 | 2022-09-18 17:04:12.39975+08
      7 | name1-10 | 2022-09-18 17:04:12.39975+08
      8 | name1-10 | 2022-09-18 17:04:12.39975+08
      9 | name1-10 | 2022-09-18 17:04:12.39975+08
     10 | name1-10 | 2022-09-18 17:04:12.39975+08
    (10 rows)
    
    postgres=# 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    连接从节点PostgreSQL实例

    [postgres@n2 log]$ psql -p 5443
    psql (12.12)
    Type "help" for help.
    
    postgres=# \l
                                      List of databases
       Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
    -----------+----------+----------+-------------+-------------+-----------------------
     postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
     template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
               |          |          |             |             | postgres=CTc/postgres
     template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
               |          |          |             |             | postgres=CTc/postgres
    (3 rows)
    
    postgres=# \dt
            List of relations
     Schema | Name | Type  |  Owner   
    --------+------+-------+----------
     public | t1   | table | postgres
    (1 row)
    
    postgres=# select * from t1;
     id |   name   |         create_time          
    ----+----------+------------------------------
      1 | name1-10 | 2022-09-18 17:04:12.39975+08
      2 | name1-10 | 2022-09-18 17:04:12.39975+08
      3 | name1-10 | 2022-09-18 17:04:12.39975+08
      4 | name1-10 | 2022-09-18 17:04:12.39975+08
      5 | name1-10 | 2022-09-18 17:04:12.39975+08
      6 | name1-10 | 2022-09-18 17:04:12.39975+08
      7 | name1-10 | 2022-09-18 17:04:12.39975+08
      8 | name1-10 | 2022-09-18 17:04:12.39975+08
      9 | name1-10 | 2022-09-18 17:04:12.39975+08
     10 | name1-10 | 2022-09-18 17:04:12.39975+08
    (10 rows)
    
    postgres=#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    可以看到数据已成功同步到了从节点。

    6 手动实现主从切换

    6.1 将从节点升级为主节点

    停止在192.168.163.133节点上的主库。

    [postgres@n1 log]$ /usr/pgsql-12/bin/pg_ctl stop -D /home/app/pgsql/12/stream-test/
    
    • 1

    此时观察从节点的PostgreSQL日志,会发现

    2022-09-19 22:49:05.622 CST [60692] LOG:  invalid record length at 0/3013868: wanted 24, got 0
    2022-09-19 22:49:05.626 CST [61439] FATAL:  could not connect to the primary server: could not connect to server: Connection refused
    		Is the server running on host "192.168.163.133" and accepting
    		TCP/IP connections on port 5443?
    2022-09-19 22:49:10.628 CST [61460] FATAL:  could not connect to the primary server: could not connect to server: Connection refused
    		Is the server running on host "192.168.163.133" and accepting
    		TCP/IP connections on port 5443?
    2022-09-19 22:49:15.632 CST [61515] FATAL:  could not connect to the primary server: could not connect to server: Connection refused
    		Is the server running on host "192.168.163.133" and accepting
    		TCP/IP connections on port 5443?
    2022-09-19 22:49:20.637 CST [61537] FATAL:  could not connect to the primary server: could not connect to server: Connection refused
    		Is the server running on host "192.168.163.133" and accepting
    		TCP/IP connections on port 5443?
    2022-09-19 22:49:25.644 CST [61576] FATAL:  could not connect to the primary server: could not connect to server: Connection refused
    		Is the server running on host "192.168.163.133" and accepting
    		TCP/IP connections on port 5443?
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    表示从节点连接不上主节点了。此时将原来的从节点升级为主节点。
    在从节点上执行192.168.163.134节点上执行

    [postgres@n2 ~]$ /usr/pgsql-12/bin/pg_ctl promote -D /home/app/pgsql/12/stream-test/
    
    waiting for server to promote.... done
    server promoted
    
    • 1
    • 2
    • 3
    • 4

    此时已经将从节点升级为主节点,验证在新主节点进行写操作

    [postgres@n2 stream-test]$ psql -p 5443
    psql (12.12)
    Type "help" for help.
    
    postgres=# \dt
            List of relations
     Schema | Name | Type  |  Owner   
    --------+------+-------+----------
     public | t1   | table | postgres
    (1 row)
    
    postgres=# insert into t1 select generate_series(11, 20), 'name11-20', now();
    INSERT 0 10
    postgres=# select * from t1;
     id |   name    |          create_time          
    ----+-----------+-------------------------------
      1 | name1-10  | 2022-09-18 17:04:12.39975+08
      2 | name1-10  | 2022-09-18 17:04:12.39975+08
      3 | name1-10  | 2022-09-18 17:04:12.39975+08
      4 | name1-10  | 2022-09-18 17:04:12.39975+08
      5 | name1-10  | 2022-09-18 17:04:12.39975+08
      6 | name1-10  | 2022-09-18 17:04:12.39975+08
      7 | name1-10  | 2022-09-18 17:04:12.39975+08
      8 | name1-10  | 2022-09-18 17:04:12.39975+08
      9 | name1-10  | 2022-09-18 17:04:12.39975+08
     10 | name1-10  | 2022-09-18 17:04:12.39975+08
     11 | name11-20 | 2022-09-19 22:55:48.871788+08
     12 | name11-20 | 2022-09-19 22:55:48.871788+08
     13 | name11-20 | 2022-09-19 22:55:48.871788+08
     14 | name11-20 | 2022-09-19 22:55:48.871788+08
     15 | name11-20 | 2022-09-19 22:55:48.871788+08
     16 | name11-20 | 2022-09-19 22:55:48.871788+08
     17 | name11-20 | 2022-09-19 22:55:48.871788+08
     18 | name11-20 | 2022-09-19 22:55:48.871788+08
     19 | name11-20 | 2022-09-19 22:55:48.871788+08
     20 | name11-20 | 2022-09-19 22:55:48.871788+08
    (20 rows)
    
    postgres=#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    可以进行写操作。

    6.2 原来的主节点以从节点的身份重新加入集群

    将原来的主节点以从节点的身份加入集群时,需要修改一下原来主节点的配置。
    以下操作都是在都是在原来的主节点(192.168.163.134)。
    修改postgresql.auto.conf文件,添加primary_conninfo配置项

    [postgres@n1 stream-test]$ vim /home/app/pgsql/12/stream-test/postgresql.auto.conf 
    
    # Do not edit this file manually!
    # It will be overwritten by the ALTER SYSTEM command.
    # 
    # 添加下面这行配置
    primary_conninfo = 'user=postgres passfile=''/home/postgres/.pgpass'' host=192.168.163.134 port=5443 sslmode=prefer sslcompression=0 gssencmode=prefer krbsrvname=postgres target_session_attrs=any'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    配置完成后,在数据目录下创建一个标识文件 standby.signal

    [postgres@n1 stream-test]$ touch /home/app/pgsql/12/stream-test/standby.signal
    
    • 1

    之后启动数据库

    [postgres@n1 stream-test]$ /usr/pgsql-12/bin/pg_ctl start -D /home/app/pgsql/12/stream-test/
    
    • 1

    验证新从节点

    [postgres@n1 log]$ psql -p 5443
    
    psql (12.12)
    Type "help" for help.
    
    postgres=# select pg_is_in
    
    postgres=# select pg_is_in_recovery();
     pg_is_in_recovery 
    -------------------
     t
    (1 row)
    
    postgres=# insert into t1 select generate_series(21, 30), 'name21-30', now();
    ERROR:  cannot execute INSERT in a read-only transaction
    postgres=#
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    可以看到节点是在以从节点身份运行。而且写操作报read-only。

  • 相关阅读:
    linux awk操作汇总(忘了来这里查)
    华为OD机试 - 数字排列(Java & JS & Python & C & C++)
    【论文阅读】MARS:用于自动驾驶的实例感知、模块化和现实模拟器
    Linux nohup bash cm_watch.sh >> run.log 2>&1 &
    新库上线 | CnOpenData中国各地区方言信息数据
    【算法刷题】第一篇——哈希
    vue3与vue2的区别
    【Android进阶】3、Activity 的生命周期
    python+django+vue房屋租赁系统 8gwmf
    基础算法之背包
  • 原文地址:https://blog.csdn.net/shangcunshanfu/article/details/126918761