PG 16.4 流复制

  • 流复制也成物理流复制
    • 通过 TCP 流的方式,将 WAL 日志以 record 为单位传输到从库
    • 从库接收到 WAL 日志后,通过 startup 进程回放 WAL 日志
  • 提供实例级复制,核心原理是主库将预写日志WAL日志流发送给备库,备库接收到WAL日志流后进行重做
  • 流复制要求PG大版本必须一致
  • 基于 16.4 部署,服务器信息如下
hostname IP port
db1 172.17.191.109 5432
db2 172.17.191.111 5432

操作系统配置

  • db1/db2 均配置

配置 hosts 和时间同步

  • db1/db2 增加 hosts 配置
1
2
3
$ vim /etc/hosts
172.17.191.109 db1
172.17.191.111 db2
  • 配置 chrony(云厂商ecs默认已配置,可以不处理)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 安装包
$ apt -y update && apt -y install chrony
# 配置 
$ vi /etc/chrony/chrony.conf
server s1a.time.edu.cn iburst
server ntp.aliyun.com iburst
driftfile /var/lib/chrony/drift
rtcsync
makestep 10 3
# 启动服务
$ systemctl start chronyd 
$ systemctl enable chronyd 
$ systemctl status chronyd 
# 写入硬件时间
$ hwclock –w

关闭防火墙/selinux

更改操作系统配置

/etc/sysctl.conf

  • 待完善

/etc/security/limits.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ vim /etc/security/limits.conf 
postgres soft nproc unlimited
postgres hard nproc unlimited
postgres soft nofile 100000
postgres hard nofile 100000
postgres soft stack unlimited
postgres hard stack unlimited
postgres soft core unlimited
postgres hard core unlimited
postgres soft memlock unlimited
postgres hard memlock unlimited

配置用户及目录

  • 创建用户
1
2
3
4
# 创建用户
useradd -m -r -s /bin/bash postgres
# 设置密码
passwd postgres
  • 创建目录
1
2
3
4
5
6
mkdir -p /pgdata/pg16
mkdir -p /pgdata/pgwal/archive_wals
mkdir -p /pg/{pghome,patroni}
chown -R postgres:postgres /{pg,pgdata}
chown -R postgres:postgres /pgdata/pgwal
chmod -R 700 /{pg,pgdata}
  • 配置环境变量
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 切换至 pg 用户
$ su - postgres 
$ vi ~/.bashrc
export PGHOME=/pg/pghome
export PGDATA=/pgdata/pg16
export PGPORT=5432
export PGDATABASE=postgres
export LD_LIBRARY_PATH=$PGHOME/lib:$LD_LIBRARY_PATH
export PATH=$PGHOME/bin:$PATH

# apply 变量
source .bashrc
  • 安装依赖的包

    • Debian12 on ali
    1
    
    apt -y install libicu-dev pkgconf libreadline-dev
    

编译安装

  • 下载
1
wget https://ftp.postgresql.org/pub/source/v16.4/postgresql-16.4.tar.gz
  • 编译安装
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
tar -zxvf postgresql-16.4.tar.gz
cd postgresql-16.4/
./configure --prefix=/pg/pghome --with-pgport=5432
# 编译
gmake world -j
# 安装
gmake install
# 编译插件
cd contrib 
make && make install
  • 初始化数据库(仅主库初始化数据,从库保持数据目录为空)
1
initdb -D /pgdata/pg16 -E UTF8 --locale=en_US.UTF-8

更改主库配置

  • $PGDATA/postgresql.conf
  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
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
# 备份
$ mv postgresql.conf postgresql.bk
# 重新写入
$ vi $PGDATA/postgresql.conf

listen_addresses = '0.0.0.0'
port = '5432'
########################
#### 此部分为网站生成推荐参数
max_connections = 1500
shared_buffers = 3GB
effective_cache_size = 9GB
maintenance_work_mem = 768MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 524kB
huge_pages = off
min_wal_size = 1GB
max_wal_size = 4GB
# 允许的最大工作进程数量,8 适合于核心数一致
max_worker_processes = 8
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
max_parallel_maintenance_workers = 4
##############################
# 保留给超级用户的连接数,确保在负载高时超级用户仍然能够连接。
superuser_reserved_connections=10
# 每个事物可以持有的最大锁数量,64通常够用
max_locks_per_transaction = '64'
# 允许的最大准备事务数量,0 表示禁用准备事务
# 0 意味着禁用此功能,适用于不需要分布式事务的场景
# 如果需要支持分布式事务,建议将其设置为大于 0 的值,通常设置为 2 倍于预期最大连接数
max_prepared_transactions='0'
# 最多可以有 10 个复制槽
max_replication_slots = '10'
# 允许的最大 WAL 发送器数量,适用于流复制环境
max_wal_senders = '50'
# 禁用提交时间戳跟踪,默认是关闭的,可以减少性能开销
track_commit_timestamp = 'off'

####################################
# 日志相关
# 开启日志收集
logging_collector = on
# 指定日志输出格式为 CSV
log_destination=csvlog
# 日志文件的名称格式,其中 %a 表示星期
log_filename = 'postgresql-%a.log'
# 记录所有连接到数据库的日志
log_connections = on
# 记录所有断开连接的日
log_disconnections = on
# 记录检查点事件的日志,有助于性能调优
log_checkpoints = on
# 记录锁等待事件的日志
log_lock_waits = on
# 仅记录 DDL 语句(数据定义语言,如 CREATE、ALTER、DROP)
log_statement = ddl
# 日志轮转
log_truncate_on_rotation = on
# 日志文件的最大存活时间,单位为分钟,1440 分钟即 24 小时
log_rotation_age = 1440
####################################

###########################
# war log 相关配置
# 设置 WAL 日志级别为 "replica",支持流复
wal_level = 'replica'
# 启用 WAL 日志提示,允许在某些情况下的优化
wal_log_hints = 'on'
# 启用归档模式,允许归档 WAL 日志
archive_mode = 'on'
# 指定归档命令,将 WAL 日志复制到指定路径
archive_command = 'cp %p /pgdata/pgwal/archive_wals/%f'
# 归档的超时时间,单位为秒,1800 秒即 30 分钟
archive_timeout = '1800s'
###############################

# 指定集群的名称,便于标识
cluster_name = 'PGCluster'
# 启用热备用,允许在备份服务器上执行只读查询
hot_standby = 'on'
# 设置同步提交模式,确保远程写入完成后再确认事务
synchronous_commit = remote_write
# 指定主机身份验证文件的路径
hba_file = '/pgdata/pg16/pg_hba.conf'
# 指定用户身份验证文件的路径
ident_file = '/pgdata/pg16/pg_ident.conf'
# 指定恢复命令,从归档中恢复 WAL 文件
restore_command = 'cp /pgdata/pgwal/archive_wals/%f %p'
# 指定恢复目标时间线为最新的
recovery_target_timeline = 'latest'


###################################
# 配置文件自带
# 设置日志记录的时区
log_timezone = 'Asia/Shanghai'
# 配置日期和时间的显示格式,此设置影响查询结果中的日期格式。
# so 表示采用 ISO 8601 标准(如 YYYY-MM-DD)
# mdy 表示月份、日期和年份的顺序(如 MM/DD/YYYY)。
datestyle = 'iso, mdy'
# 设置数据库的默认时区。所有时间戳数据类型
timezone = 'Asia/Shanghai'
# 设置默认的文本搜索配置,影响文本搜索的行为和结果
default_text_search_config = 'pg_catalog.english'
#####################################
  • $PGDATA/pg_hba.conf
1
2
3
4
5
vi $PGDATA/pg_hba.conf
# 内网网段内允许从库连接
host replication replicator 172.17.191.0/24 md5
# 所有网段允许连接
host all all 0.0.0.0/0 md5

配置流复制

  • 启动主库
1
pg_ctl start
  • 创建流复制用户
1
psql -U postgres -c "CREATE USER replicator REPLICATION ENCRYPTED PASSWORD 'replicator';"
  • 创建测试用户,利用存储过程生成测试数据

    • 创建测试用户和测试库
    1
    2
    
    CREATE USER tuser  PASSWORD '000000';
    CREATE DATABASE tdb OWNER tuser ;
    
    • 使用 tuser 用户连接
    1
    
    psql -h 127.0.0.1 -p 5432 -U tuser -d tdb -W
    
    • 创建测试表
    1
    2
    3
    4
    5
    6
    
    CREATE TABLE test_table (
      id SERIAL PRIMARY KEY,
      name VARCHAR(100),
      age INT,
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
    
    • 创建存储过程
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    CREATE OR REPLACE FUNCTION generate_test_data(num_records INT) 
    RETURNS VOID AS $$
    DECLARE
        i INT;
    BEGIN
        FOR i IN 1..num_records LOOP
            INSERT INTO test_table (name, age)
            VALUES (
                'Name_' || i,
                (SELECT FLOOR(RANDOM() * 100) + 1)  -- 随机年龄 1-100
            );
        END LOOP;
    END;
    $$ LANGUAGE plpgsql;
    
    • 调用存储过程生成数据
    1
    
    SELECT generate_test_data(50000);
    
    • 查看数据量
    1
    
    select count(*) from test_table;
    
  • db2 直接拉取 db1 数据

1
pg_basebackup -D $PGDATA -Fp -Xs -v -P -R -h 172.17.191.109 -p 5432 -U replicator
  • 更改备库配置
1
2
3
4
$ vi $PGDATA/postgresql.conf
max_standby_streaming_delay = 30s
wal_receiver_status_interval = 10s
hot_standby_feedback = on
1
2
$ vi $PGDATA/standby.signal
standby_mode = on
1
2
3
$ cat $PGDATA/postgresql.auto.conf
# 检查 pg_basebackup -R 参数自动生成的配置是否有问题
primary_conninfo = 'user=replicator password=replicator channel_binding=disable host=172.17.191.109 port=5432 sslmode=disable sslcompression=0 sslcertmode=disable sslsni=1 ssl_min_protocol_version=TLSv1.2 gssencmode=disable krbsrvname=postgres gssdelegation=0 target_session_attrs=any load_balance_hosts=disable'
  • 启动备库
1
2
chmod -R 700 /{pg,pgdata}
pg_ctl start

验证

  • 主库调用存储过程,生成数据
1
SELECT generate_test_data(300000);
  • 从库查看
1
2
tdb=# select count(*) from test_table;
 350000

参考