前面学完了理论知识,今天我们来实战学习下怎么配置这个流复制。为什么采用 docker 进行实验呢,原因很简单,非常方便。

#先设置目录
mkdir -p /data/postgres-replication
mkdir -p /data/postgres-replication/postgres-01
mkdir -p /data/postgres-replication/postgres-02
mkdir -p /data/postgres-replication/postgres-03
chmod 777 -R /data/postgres-replication/postgres-0*

vi /data/postgres-replication/docker-compose.yaml
version: '3.9'
services:
  # 写节点
  postgres-01:
    container_name: postgres-01
    hostname: postgres-01
    image: timescale/timescaledb-ha:pg15-all
    privileged: true
    environment:
      PGDATA: /home/postgres/db
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    volumes:
      - ./postgres-01:/home/postgres
    ports:
      - "5001:5432"
    networks:
      pg-net:
        ipv4_address: 10.20.0.5
  # 读节点一      
  postgres-02:
    container_name: postgres-02
    hostname: postgres-02
    image: timescale/timescaledb-ha:pg15-all
    privileged: true
    environment:
      PGDATA: /home/postgres/db
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    volumes:
      - ./postgres-02:/home/postgres
    ports:
      - "5002:5432"
    networks:
      pg-net:
        ipv4_address: 10.20.0.6
  # 读节点二      
  postgres-03:
    container_name: postgres-03
    hostname: postgres-03
    image: timescale/timescaledb-ha:pg15-all
    privileged: true
    environment:
      PGDATA: /home/postgres/db
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    volumes:
      - ./postgres-03:/home/postgres
    ports:
      - "5003:5432"
    networks:
      pg-net:
        ipv4_address: 10.20.0.7
networks:
  pg-net:
    ipam:
      config:
        - subnet: 10.20.0.0/16

接着启动容器:docker-compose up -d

先进入到主节点进行配置 docker exec -it postgres-01 /bin/bash

#进入容器内的/home/postgres/pgdata/data目录,修改 pg_hba.conf,在最下方新增:
host    replication     all             0.0.0.0/0               md5

接着配置 postgresql.conf(这些配置项默认是配置好的),检查一下就行

#设置以下
listen_addresses = '*' # 允许远程连接
hot_standby = on # 打开热备
wal_level = replica     # 设置 WAL 日志级别为 replica
max_wal_senders = 3     # 允许的 WAL 发送者数量,根据需要进行调整

创建流复制的账号

postgres=# create role replica with login replication encrypted password 'replica';

然后重启下postgres-01 容器,使配置生效 docker-compose restart postgres-01

到此主节点就配置好了,接下来我们来配置从节点

这个时候我们需要进入 postgres-02 的容器内:docker exec -it postgres-02 sh,同步主节点的数据。

su postgres
pg_basebackup -Fp --progress -D /home/postgres/pgdata/data -R -h 10.20.0.5 -p 5432 -U replica --password

执行成功后可以在备库的数据目录下看到复制过来的文件和配置文件

因为使用了 -R 参数,也会生成 standby.signal 文件,同时在 postgresql.auto.conf 中生成如下内容

[root@192 data]# ls
PG_VERSION        base          pg_dynshmem    pg_logical    pg_replslot   pg_stat      pg_tblspc    pg_xact               postmaster.opts
backup_label.old  global        pg_hba.conf    pg_multixact  pg_serial     pg_stat_tmp  pg_twophase  postgresql.auto.conf  postmaster.pid
backup_manifest   pg_commit_ts  pg_ident.conf  pg_notify     pg_snapshots  pg_subtrans  pg_wal       postgresql.conf       standby.signal
[root@192 data]# cat postgresql.auto.conf 
# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
primary_conninfo = 'user=replica password=replica channel_binding=prefer host=10.20.0.5 port=5432 sslmode=prefer sslcompression=0 sslcertmode=allow sslsni=1 ssl_min_protocol_version=TLSv1.2 gssencmode=prefer krbsrvname=postgres gssdelegation=0 target_session_attrs=any load_balance_hosts=disable'
[root@192 data]# 

因为我们一开始配置 postgres-02 的 PGDATA 为/home/postgres/db,我们需要修改这个同步过来的目录,然后重启。

将docker-compose.yaml 文件下的 postgres-02 的

PGDATA: /home/postgres/db 修改成 /home/postgres/pgdata/data

然后重启docker-compose restart postgres-02

postgres-03 也是重复该操作。

在主节点的 psql 中执行:SELECT * FROM pg_stat_replication;如下图所示,到此我们的同步搭建就成功了。

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           
-----+----------+---------+------------------+-------------+-----------------+-------------+-------------------------------+--------------+-----------+-----------+-----------+-----------+------------+-----------+-----------+------------+---------------+------------+-------------------------------
  38 |    16387 | replica | walreceiver      | 10.20.0.7   |                 |       42382 | 2025-07-06 08:14:59.685966+00 |              | streaming | 0/70001F8 | 0/70001F8 | 0/70001F8 | 0/70001F8  |           |           |            |             0 | async      | 2025-07-06 08:40:44.867142+00
  39 |    16387 | replica | walreceiver      | 10.20.0.6   |                 |       47500 | 2025-07-06 08:14:59.722339+00 |              | streaming | 0/70001F8 | 0/70001F8 | 0/70001F8 | 0/70001F8  |           |           |            |             0 | async      | 2025-07-06 08:40:44.827293+00
(2 rows)

测试验证

#在postgres-01执行
create table test(id int);
insert into test values (1),(2),(3);

#在postgres-02查询数据是否有同步过来
postgres=# select * from test;
 id 
----
  1
  2
  3
(3 rows)