【应用】PostgreSQL 流复制配置

PostgreSQL 流复制配置

  • centos7 安装 postgresql
    • 时序库 timescaleDB 的安装
  • postgresql-14 主从流复制
    • 主库配置
    • 从库配置
    • 同步流复制与异步流复制
      • 异步流复制转换为同步流复制
    • 流复制的相关参数
  • 主从流复制原理
    • PostgreSQL WAL 日志
    • 主从流复制架构
    • 主从流复制的过程
  • 基于 docker swarm 的主从流复制配置
    • 配置前准备
    • 主库配置
    • 从库配置
    • 测试同步状态
    • 异步流复制转换为同步流复制

centos7 安装 postgresql

下载安装 postgresql-14

# 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 postgresql14-server

# Optionally initialize the database and enable automatic start:
sudo /usr/pgsql-14/bin/postgresql-14-setup initdb

修改配置文件

"/var/lib/pgsql/14/data/postgresql.conf"

listen_addresses = '*'        # what IP address(es) to listen on;
                    # comma-separated list of addresses;
                    # defaults to 'localhost'; use '*' for all
                    # (change requires restart)
port = 5432                # (change requires restart)

"/var/lib/pgsql/14/data/pg_hba.conf"

# IPv4 local connections:
host    all             all             127.0.0.1/32            scram-sha-256
host    all             all             0.0.0.0/0               md5

启动 postgresql-14 服务

启动命令:systemctl start postgresql-14
重启命令:systemctl restart postgresql-14
停止命令:systemctl stop postgresql-14

切换到安装自动创建的 postgres 用户,修改密码(默认无密码)

[root@localhost ~]# su - postgres
-bash-4.2$ psql
psql (14.5)
输入 "help" 来获取帮助信息.

postgres=# ALTER USER postgres ENCRYPTED PASSWORD '961231zqf';
ALTER ROLE
postgres=# exit
-bash-4.2$ exit
登出

使用连接工具 navicat 进行测试,注意关闭防火墙

systemctl stop firewalld.service
systemctl disable firewalld.service

时序库 timescaleDB 的安装

执行安装,centOS 中没有对应的安装包,需进行配置

在 root 用户下输入下列命令并执行

yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{centos})-x86_64/pgdg-redhat-repo-latest.noarch.rpm

配置 timescaledb 仓库

tee /etc/yum.repos.d/timescale_timescaledb.repo <<EOL
[timescale_timescaledb]
name=timescale_timescaledb
baseurl=https://packagecloud.io/timescale/timescaledb/el/$(rpm -E %{rhel})/\$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/timescale/timescaledb/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
EOL

更新本地仓库列表

yum update

执行安装

yum install timescaledb-2-postgresql-14

修改配置文件/var/lib/pgsql/14/data/postgresql.conf,配置时序库

shared_preload_libraries = 'timescaledb'    # (change requires restart)

创建目录,并将修改后的配置文件复制到该目录下

mkdir -p /etc/postgresql/14/main/
cp /var/lib/pgsql/14/data/postgresql.conf /etc/postgresql/14/main/

使用 navicat 连接数据库,首先创建新的数据库 timescaledb

CREATE DATABASE timescaledb;

连接到新创建的数据库,进行扩展

CREATE EXTENSION IF NOT EXISTS timescaledb;

postgresql-14 主从流复制

主库 从库
192.168.86.133 192.168.86.131

主库配置

修改配置文件:"/var/lib/pgsql/14/data/postgresql.conf",主要关注wal_level属性

wal_level = replica            # minimal, replica, or logical
                               # (change requires restart)

在主库中创建一个用于复制的账号,用户名密码均为 repl

[root@localhost ~]# su - postgres
上一次登录:四 113 17:11:18 CST 2022pts/1 上
-bash-4.2$ psql
psql (14.5)
输入 "help" 来获取帮助信息.

postgres=# create role repl login replication encrypted password 'repl';
CREATE ROLE
postgres=# exit
-bash-4.2$ exit
登出

修改配置文件:"/var/lib/pgsql/14/data/pg_hba.conf",添加下列配置

host    replication     repl      192.168.86.131/32       md5

重启主库服务

systemctl restart postgresql-14

至此主库配置完毕

从库配置

首先停止从库服务

systemctl stop postgresql-14

删除数据库主目录 data

[root@localhost ~]# cd /var/lib/pgsql/14
[root@localhost 14]# rm -rf data

使用pg_basebackup命令同步数据库

[root@localhost 14]# pg_basebackup -h 192.168.86.133 -p 5432 -U repl -R -F p -P -D data

参数说明:
选项    说明
-p    主库数据库端口
-U    流复制用户
-W    使用密码验证,要用replica的密码
-Fp   备份输出正常的数据库目录
-Xs   使用流复制的方式进行复制
-Pv   输出复制过程的详细信息
-R    为备库创建recovery.conf文件。但是pgsql 10以后的新版本的pgsql不需要这个文件了。
-D    指定创建的备库的数据库目录

重新启动从库数据库服务

systemctl restart postgresql-14

若存在启动失败问题,则可能是权限问题导致

[root@localhost 14]# systemctl restart postgresql-14
Job for postgresql-14.service failed because the control process exited with error code. See "systemctl status postgresql-14.service" and "journalctl -xe" for details.
[root@localhost 14]# systemctl status postgresql-14
● postgresql-14.service - PostgreSQL 14 database server
   Loaded: loaded (/usr/lib/systemd/system/postgresql-14.service; disabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since 五 2022-11-04 08:37:21 CST; 35s ago
     Docs: https://www.postgresql.org/docs/14/static/
  Process: 1392 ExecStartPre=/usr/pgsql-14/bin/postgresql-14-check-db-dir ${PGDATA} (code=exited, status=1/FAILURE)

11月 04 08:37:21 localhost.localdomain systemd[1]: Starting PostgreSQL 14 database server...
11月 04 08:37:21 localhost.localdomain systemd[1]: postgresql-14.service: control process exited, code=exited status=1
11月 04 08:37:21 localhost.localdomain systemd[1]: Failed to start PostgreSQL 14 database server.
11月 04 08:37:21 localhost.localdomain systemd[1]: Unit postgresql-14.service entered failed state.
11月 04 08:37:21 localhost.localdomain systemd[1]: postgresql-14.service failed.

重新为 postgres 用户授权,启动服务成功

[root@localhost 14]# chown -R  postgres:postgres /var/lib/pgsql/14/data
[root@localhost 14]# systemctl start postgresql-14

至此简单的主从流复制配置完成,可连接数据库进行操作进行检验,从库为只读库,可以在主库执行下列命令查询从库相关信息

select pid,state,client_addr,sync_priority,sync_state,sent_lsn,write_lsn from pg_stat_replication;

同步流复制与异步流复制

流复制分为同步流复制和异步流复制:

  • 同步流复制:可以在主库故障时确保数据的一致,但是当网络或者备库出现问题时,会导致主库的事务 hang 住;

  • 异步流复制:不会影响主库的性能,但是在主库故障时,可能会丢掉小部分数据;

异步流复制转换为同步流复制

上述的流复制配置过程为异步流复制的配置过程,可以通过指令查看当前的数据库状态

使用 postgres 用户登录数据库,执行查询,可以看到sync_state对应的值为async

select * from pg_stat_replication;

修改主库配置文件/var/lib/pgsql/14/data/postgresql.conf,配置ynchronous_standby_names属性

synchronous_standby_names = 'slave'

重新启动主数据库

cd /usr/pgsql-14/bin/
./pg_ctl restart

使用 postgres 用户登录备用数据库,查询备库状态,保存conninfo字段的信息

select * from pg_stat_wal_receiver;

修改备库的系统设置,新值为上一步保存的conninfo字段信息加上application_name=slave

alter system set primary_conninfo = 'application_name=slave user=repl password=repl channel_binding=disable host=192.168.86.133 port=5432 sslmode=disable sslcompression=0 ssl_min_protocol_version=TLSv1.2 gssencmode=disable krbsrvname=postgres target_session_attrs=any';

重新启动从数据库

cd /usr/pgsql-14/bin/
./pg_ctl restart

重新查看主库状态

postgres=# select * from pg_stat_replication ;
 pid  | usesysid | usename | application_name |  client_addr   | client_hostname | client_port |         backend_start         | backend_xmin |   state   |  sent_lsn  | write_lsn
| flush_lsn  | replay_lsn |    write_lag    |    flush_lag    |   replay_lag    | sync_priority | sync_state |          reply_time
------+----------+---------+------------------+----------------+-----------------+-------------+-------------------------------+--------------+-----------+------------+------------
+------------+------------+-----------------+-----------------+-----------------+---------------+------------+-------------------------------
 1915 |    24577 | repl    | slave            | 192.168.86.131 |                 |       47664 | 2022-11-09 09:52:11.088431+08 |              | streaming | 0/DD99DFA8 | 0/DD99DFA8
| 0/DD99DFA8 | 0/DD99DFA8 | 00:00:00.001495 | 00:00:00.002756 | 00:00:00.003071 |             1 | sync       | 2022-11-09 09:52:11.469006+08
(1 行记录)

重新查看备库状态

postgres=# select * from pg_stat_wal_receiver ;
 pid  |  status   | receive_start_lsn | receive_start_tli | written_lsn | flushed_lsn | received_tli |      last_msg_send_time       |     last_msg_receipt_time     | latest_end_ls
n |       latest_end_time       | slot_name |  sender_host   | sender_port |
                                           conninfo

------+-----------+-------------------+-------------------+-------------+-------------+--------------+-------------------------------+-------------------------------+--------------
--+-----------------------------+-----------+----------------+-------------+--------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------
 1626 | streaming | 0/DD000000        |                 1 | 0/DD99DFA8  | 0/DD99DFA8  |            1 | 2022-11-09 09:52:41.495931+08 | 2022-11-09 09:52:41.491104+08 | 0/DD99DFA8
  | 2022-11-09 09:52:11.4719+08 |           | 192.168.86.133 |        5432 | user=repl password=******** channel_binding=disable dbname=replication host=192.168.86.133 port=5432 ap
plication_name=slave fallback_application_name=walreceiver sslmode=disable sslcompression=0 sslsni=1 ssl_min_protocol_version=TLSv1.2 gssencmode=disable krbsrvname=postgres target_
session_attrs=any
(1 行记录)

至此异步流复制切换同步流复制完成,可以使用客户端连接进行验证测试。

流复制的相关参数

  • 日志级别wal_level:该参数决定了有多少信息写入 WAL 日志

    • 默认值replica,该模式支持流复制与归档,同时支持备库的只读查询;

    • minimal:对实例 crash 恢复所需要的进行记录,其余不记录日志,该模式记录的日志信息不足以支撑 WAL 的流复制与归档;

    • logic:在 replica 的基础上增加一些信息以支持逻辑解码,该模式会增大 WAL 日志,尤其是大量 update、delete 的库;

  • 同步模式synchronous_commit:该参数决定数据同步的模式

    • off:对于本机的 WAL 日志不需要写入到磁盘就可以提交,是一种异步模式,存在数据丢失的风险;

    • local:不管有没有从库,只需要保证本机的 WAL 日志写入到磁盘就可以提交;

    • remote_write:等待主库的日志写入到磁盘,同时日志传送到从库的缓存当中才能提交,生产环境下一般选择该模式;

    • on:若不存在从库,则需要本机 WAL 写入磁盘后才能提交;若存在同步从库,则需要等待远程从库的 WAL 也写入到磁盘后才能提交;

    • remote_apply:PG 高版本的功能,需要从库将更改写入磁盘并回放日志成功,用于负载均衡、读写分离等;

  • 从机复制列表synchronous_standby_names:该参数用于在主机上配置从机的复制列表

    • synchronous_standby_names=‘s1’代表 s1 备机返回就可以提交(s1 为备机名);

    • synchronous_standby_names=’*’代表匹配任意主机,也就是任意主机返回就可以提交;

  • max_wal_senders:指定 WAL 日志发送进程的最大并发连接数,设置为 0 表示禁用 replication;

  • checkpoint_timeout:自动 WAL 检查点之间的最长时间,合理值为 30s 到 1day 之间,默认值 5min。增加这个参数的值会增加崩溃恢复所需的时间。

  • checkpoint_completion_target:指定检查点完成的目标,该值在 0 - 1 之间。假如我的 checkpoint_timeout 设置是 30min,而 WAL 日志生成了10G,那么设置成 0.5 就允许在 15min 内完成 checkpoint,调大这个值就可以降低c heckpoint 对性能的影响,但是万一数据库出现故障,那么这个值设置越大数据就越危险。

  • max_wal_size:在自动检查点之间允许 WAL 日志的最大容量,默认为 1 GB,增加这个参数的值会增加崩溃恢复所需的时间。

主从流复制原理

在 PostgreSQL 9.1 版本之前,主从复制以 WAL 日志为基本单位,主库写完一个 WAL 日志后才传送到备库,这导致主备数据库之间的延迟很大。

PostgreSQL 9.1 引入了主备流复制,传输的单位时 WAL 日志的 record,备库不断从主库同步相应的数据。

PostgreSQL WAL 日志

PostgreSQL 的流复制实际上就是通过 WAL 日志进行数据同步的过程。WAL 全称 Write Ahead Log,即预写式日志。

WAL 日志十分重要,其核心思想就是:先写入日志文件,再写入数据。

当数据库中的数据发生变更时,主要存在下列几个重要的节点:

  • change 发生时:数据库首先将变更的内容计入 wal buffer,再将变更后的数据写入 data buffer;

  • commit 发生时:数据库将 wal buffer 中的数据刷新到磁盘;

  • checkpoint 发生时:数据库将所有的 data buffer 刷新到磁盘;

主从流复制架构

PostgreSQL 主从流复制的核心主要包括三个进程:

  • walsender:用于主库发送 WAL 日志到从库;

  • walreceiver:用于从库接收主库的 WAL 日志;

  • startup:用于从库 apply 日志;
    【应用】PostgreSQL 流复制配置_第1张图片

主从流复制的过程

  1. 主从数据库启动后,备库启动 walreceiver 进程,向主库发送请求连接;

  2. 主库接收到请求后,启动 walsender 进程,与 walreceiver 建立 TCP 连接;

  3. 从库发送最新的 WAL LSN 给主库(LSN 可以理解为日志的偏移量);

  4. 主库进行 LSN 对比,同时定期向从库发送心跳信息来确认备库的可用性,并将没有传递的 WAL 日志发送;

  5. 从库调用函数将 WAL 写入缓存,然后将 WAL 刷新到磁盘;

基于 docker swarm 的主从流复制配置

docker swarm 集群的搭建过程参照:docker swarm 集群搭建

配置前准备

编写 docker compose 模板文件,对服务进行配置。本配置启动一主一从两个数据库,直接使用时序库官方提供的 timescaledb 镜像

version: "3"
services:
# postgres-1 服务
  postgres-1:
    image: timescale/timescaledb:latest-pg14
    networks:
      - my-multi-host-network
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=961231zqf
    volumes:
      - /root/postgresql/data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    deploy:
      placement:
        constraints:
          - node.hostname == node01


# postgres-2 服务
  postgres-2:
    image: timescale/timescaledb:latest-pg14
    networks:
      - my-multi-host-network
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=961231zqf
    volumes:
      - /root/postgresql/data:/var/lib/postgresql/data
    ports:
      - 5433:5432
    deploy:
      placement:
        constraints:
          - node.hostname == node02

# 网络配置
networks:
  my-multi-host-network:
    driver: overlay

分别在 node 1 节点与 node 2 节点新建映射卷文件夹,映射路径需要与配置文件中路径相对应,同时在两个节点新建名为 postgres 的用户

mkdir -p /root/postgres/data
useradd postgres

在主节点 master 按照上述 compose 文件启动服务

docker stack deploy -c docker_postgres.yml postgres

使用下列命令可以查看服务的运行情况

docker service ls

主库配置

在主数据库节点 node 1 进行配置,使用下列指令查询当前节点正在运行的容器

docker ps

以 postgres 用户进入 timescale/timescaledb:latest-pg14 容器,其中e052dfa54dbf为容器的 CONTAINER ID

docker exec -it -u postgres e052dfa54dbf /bin/bash

进入/var/lib/postgresql/data/,修改配置文件postgresql.conf

cd /var/lib/postgresql/data/
vi postgresql.conf

主要修改wal_level属性,取消对应行前面的注释

wal_level = replica                     # minimal, replica, or logical
                                        # (change requires restart)

进入/var/lib/postgresql/data/,修改配置文件pg_hba.conf

cd /var/lib/postgresql/data/
vi postgresql.conf

在文件末尾添加如下配置

host    replication     repl      0.0.0.0/0       md5

登录数据库,创建用于复制的账号,用户名与密码均为 repl

bash-5.1$ psql
psql (14.1)
Type "help" for help.

postgres=# create role repl login replication encrypted password 'repl';
CREATE ROLE
postgres=# exit

在容器内重新启动主数据库

pg_ctl restart

重新查看 node 1 的服务,查看数据库是否启动成功,若启动成功则主库配置完毕

从库配置

在从数据库节点 node 2 进行配置,使用下列指令查询当前节点正在运行的容器

docker ps

以 postgres 用户进入容器

docker exec -it -u postgres d853cdb73a76 /bin/bash

进入/var//lib/postgresql/,清空 data 文件夹中的所有数据

cd /var/lib/postgresql/
rm -rf data/*

利用pg_basebackup指令从主数据库将数据复制到从库,使用 repl 账号,密码为 repl

pg_basebackup -h 192.168.86.131 -p 5432 -U repl -R -F p -P -D data

执行完成后,等待容器自动重启,重启时将会退出容器。退出容器后查看 node 2 节点运行的容器状态,此时容器 ID 将会变换,若容器正常运行则主从异步流复制配置完毕

测试同步状态

使用 navicat 连接两个数据库,在主库中使用下列语句查询主从配置信息

select * from pg_stat_replication;

在主库中执行相应的增删改语句,查看从库的复制情况,从库为只读库

CREATE TABLE test(id INT);

DROP TABLE test;

异步流复制转换为同步流复制

在主库节点 node 1 查询当前数据库的主从复制状态,此时sync_state字段值为async

select usename, application_name, client_addr, state, sync_state from pg_stat_replication;

使用 postgres 用户进入主库节点 node 1 的 pg 库容器内部进行配置

docker ps
docker exec -it -u postgres 01e4813649de /bin/bash

修改配置文件postgresql.conf

cd /var/lib/postgresql/data/
vi postgresql.conf

配置属性synchronous_standby_names

synchronous_standby_names = 'slave'     # standby servers that provide sync rep
                                # method to choose sync standbys, number of sync standbys,
                                # and comma-separated list of application_name
                                # from standby(s); '*' = all

配置完成后重新启动主数据库并查看容器运行情况,主库配置完成

使用 navicat 等工具连接从库,使用下列语句查询复制信息

select * from pg_stat_wal_receiver;

记录查询结果中connifo字段值,并在原始值字段前添加application_name=slave,然后执行系统变量的更新(application_name属性的值为之前设置的synchronous_standby_names属性值)

alter system set primary_conninfo = 'application_name=slave user=repl password=repl channel_binding=prefer dbname=replication host=192.168.86.131 port=5432 fallback_application_name=walreceiver sslmode=prefer sslcompression=0 sslsni=1 ssl_min_protocol_version=TLSv1.2 gssencmode=prefer krbsrvname=postgres target_session_attrs=any';

使用 postgres 用户进入从库容器内部,重新启动数据库

docker ps
docker exec -it -u postgres b4bff118dae5 /bin/bash
pg_ctl restart

重新查询从库节点 node 2 容器运行状态,若正常运行则从库配置完毕

在主库中重新查询数据库复制信息,此时sync_state字段值变为sync,配置成功

select usename, application_name, client_addr, state, sync_state from pg_stat_replication;

你可能感兴趣的:(数据库,docker,postgresql,数据库)