pg_basebackup实现简单的异步流复制
进行本节实验前,请先配置好docker镜像源
实验目的
了解现代数据库系统(PG)如何实现高可用性的
- 高可用性:主库故障时备库可快速接管服务,减少业务中断时间。
- 数据冗余:通过实时同步机制(WAL日志)保障数据安全,避免单点故障导致数据丢失。
- 负载分担:备库可承担只读查询,分担主库压力(需配置
hot_standby = on
)。 - 灾难恢复:异地部署备库可应对物理环境故障(如机房断电、网络中断)。
Docker环境下
下载Postgres的Docker Image镜像
在终端输入以下指令,下载最新的postgresql的docker镜像:
docker pull postgres
如果遇到连接超时等错误,尝试换一下docker-hub的镜像源(教程网上有)。
创建PG专属数据卷
docker volume create postgre-data
在 Docker 中,挂载数据卷(Volume Mounting)是一种非常重要的机制,用于在容器和宿主机之间或者容器与容器之间共享和持久化数据。(来源:豆包AI)
作用
1.持久化
当容器被删除时,容器内部产生的数据也会随之丢失。通过挂载数据卷,可以将数据存储在宿主机或 Docker 管理的卷中,即使容器被删除,数据仍然可以保留下来。
2. 数据共享
可以在多个容器之间共享同一个数据卷,实现容器间的数据交互。比如,一个 Web 应用容器和一个日志处理容器可以共享同一个日志数据卷,Web 应用将日志写入数据卷,日志处理容器从该数据卷读取日志进行分析。
3. 方便开发和调试
在开发过程中,可以将宿主机上的代码目录挂载到容器内部,这样在宿主机上修改代码后,容器内的代码也会同步更新,无需重新构建和启动容器,提高开发效率。
这里就是让容器内部的数据同步到宿主机,不会丢失数据。
创建并运行容器pg1(作为主库)
docker run -id --name=pg1 -v postgre-data:/var/lib/postgresql/data -p 5432:5432 -e POSTGRES_PASSWORD=123456 -e LANG=C.UTF-8 postgres
在挂载的数据卷内配置(推荐)
找到外置数据卷的文件夹位置,Ubuntu1604的文件夹位置为/var/lib/docker/volumes/postgre-data/_data
在docker外部(宿主机)执行命令(需要超级用户):
vim /var/lib/docker/volumes/postgre-data/_data/postgresql.conf
在最后加入以下配置:
x wal_level = replica # 启用WAL日志归档
max_wal_senders = 3 # 允许最多3个复制连接
hot_standby = on # 备库可提供读服务(需重启生效)
通过命令hostname -i
查看本机ip,并将本机ip加入pg_hba.conf文件:
vim /var/lib/docker/volumes/postgre-data/_data/pg_hba.conf
host replication all <your-hostname>/16 md5 # 允许Docker网络内的复制连接
直接在容器里修改配置(不推荐)
进入容器pg1,切换到用户postgres
su postgres
cd ~
cd data
编辑data文件夹下,PG的配置文件postgresql.conf,加入以下配置:
wal_level = replica # 启用WAL日志归档
max_wal_senders = 3 # 允许最多3个复制连接
hot_standby = on # 备库可提供读服务(需重启生效)
通过命令hostname -i
查看本机ip,并将本机ip加入pg_hba.conf文件:
host replication all <your-hostname>/16 md5 # 允许Docker网络内的复制连接
更新配置
重启容器pg1
sudo docker restart pg1
或者使用pg_ctl
sudo pg_ctl restart
在容器pg1中建立新的数据库和数据表用于验证备库是否成功复制
-- 创建数据库
CREATE DATABASE student_db;-- 连接到新创建的数据库
\c student_db;-- 创建学生表
CREATE TABLE students (student_id SERIAL PRIMARY KEY,name VARCHAR(100) NOT NULL,age INT,gender CHAR(1),enrollment_date DATE
);-- 插入示例数据
INSERT INTO students (name, age, gender, enrollment_date)
VALUES ('张三', 20, 'M', '2024-09-01'),('李四', 21, 'F', '2023-09-01'),('王五', 22, 'M', '2022-09-01'),('赵六', 19, 'F', '2025-01-15'),('孙七', 23, 'M', '2022-03-20'),('周八', 20, 'F', '2024-07-10'),('吴九', 22, 'M', '2023-11-05'),('郑十', 21, 'F', '2024-04-25'),('王十一', 18, 'M', '2025-02-01'),('李十二', 24, 'F', '2021-09-30'),('张十三', 20, 'M', '2024-09-12'),('刘十四', 22, 'F', '2023-06-18'),('陈十五', 19, 'M', '2025-03-08');
pg2备库搭建(关键步骤)
创建备库容器(不挂载数据卷,由pg_basebackup
初始化):
sudo docker run -d --name pg2 -e POSTGRES_PASSWORD=123456 postgres:latest bash -c "while true; do sleep 1; done"
"while true; do sleep 1; done"
这部分是为了阻止容器刚开启就关闭(因为没有挂载数据卷,pg服务无法启动)。
执行 pg_basebackup
:
sudo docker exec -it pg2 'pg_basebackup -h <pg1的host> -U postgres -D /var/lib/postgresql/data -P -R -X stream -v'
-R
:自动生成standby.signal
文件并配置primary_conninfo
-X stream
:实时传输未归档的WAL日志
或直接进入容器终端执行:
pg_basebackup -h <pg1的host> -U postgres -D /var/lib/postgresql/data -P -R -X stream -v
启动备库
sudo docker exec pg2 su postgres -c "pg_ctl start -D /var/lib/postgresql/data"
验证主备一致性
1. 主库检查
-
查看复制状态:
SELECT client_addr, state, sync_state, sent_lsn, write_lsn FROM pg_stat_replication;
- 正常输出应包含备库IP,
state = 'streaming'
,sync_state
表示同步模式。
- 正常输出应包含备库IP,
2. 备库检查
-
确认恢复模式:
SELECT pg_is_in_recovery(); -- 返回`t`表示处于备库模式
-
检查接收的WAL位置:
SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();
- 应与主库的
sent_lsn
和write_lsn
一致。
- 应与主库的
3. 数据一致性验证
-
主库写入测试数据:
CREATE TABLE test (id SERIAL PRIMARY KEY, data TEXT); INSERT INTO test (data) VALUES ('HA test');
-
备库查询验证:
SELECT * FROM test; -- 应返回与主库相同数据
4. 日志监控
- 主库日志:出现
streaming replication successfully connected to standby
- 备库日志:持续输出
started streaming WAL from primary
和consistent recovery state
其他
一般的postgreSQL镜像不包含vim,vi,netutils等常见工具,由于镜像是Debian系统,可以使用apt安装(需要超级用户权限):
apt-get update
apt-get install <tool-name>
docker 进入容器终端
docker exec -it <container-name> bash
退出容器/用户
exit
pg_basebackup运行后,可能会文件权限错误,可以在postgres用户下执行,将权限改为750或者700
sudo chmod -R <750/700> ~/data