【PostgreSQL】如何实现主从复制?

发布于:2025-09-07 ⋅ 阅读:(19) ⋅ 点赞:(0)

PostgreSQL 主从复制最简单、最常用、官方推荐的方法是流复制 (Streaming Replication)。它利用 PostgreSQL 的预写日志 (WAL, Write-Ahead Log) 进行数据同步。

这里介绍一个基于 pg_basebackupstandby.signal 的简单配置方法,适用于 PostgreSQL 12 及更高版本 (因为 standby.signal 和将 primary_conninfo 直接写入 postgresql.auto.conf 是其特点)。

核心思想:

  1. Primary (主库) 配置: 开启 WAL 日志发送功能,并允许副本连接。

  2. Replica (从库) 初始化: 使用 pg_basebackup 从主库获取一份基准备份,并自动配置为从库。

  3. Replica (从库) 启动: 启动从库服务,它会自动连接主库并开始接收 WAL 日志。


环境准备:

假设你有两台服务器(或虚拟机):

  • Primary (主库): 192.168.1.101

  • Replica (从库): 192.168.1.102

两台机器上都已安装 PostgreSQL,并且能够相互 ping 通。

第一步:Primary (主库) 配置

  1. 编辑 postgresql.conf 文件

找到你的 PostgreSQL 数据目录下的 postgresql.conf 文件 (通常在 /etc/postgresql/1X/main/postgresql.conf$PGDATA/postgresql.conf)。修改或添加以下参数:


# 允许所有IP连接(或者指定从库IP)

listen_addresses = '*'

# 开启WAL日志级别,`replica` 足够用于流复制

wal_level = replica

# 最大同时发送WAL日志的进程数(根据需要设置,一般5-10个足够)

max_wal_senders = 10

# 保持WAL日志文件大小,防止从库断开重连后找不到WAL日志

# 生产环境中建议设置大一些,如 1GB 或更多,具体取决于WAL生成速度和网络稳定性

wal_keep_size = 512MB # PostgreSQL 13及以前是 wal_keep_segments

# 如果是 PostgreSQL 13 以前的版本,可能需要设置 wal_keep_segments = 32 (每个16MB,总共512MB)

# 可选:开启WAL归档。对于生产环境非常重要,用于PITR (Point-In-Time Recovery) 和从库长时间掉线后的恢复。

# 如果只是简单的流复制测试,可以暂时不开启,但强烈建议开启。

# archive_mode = on

# archive_command = 'cp %p /mnt/pg_archive/%f' # 替换为你的归档目录

  1. 编辑 pg_hba.conf 文件

允许从库以复制用户身份连接。找到你的 pg_hba.conf 文件 (与 postgresql.conf 在同一目录下),添加以下一行:


# TYPE  DATABASE        USER            ADDRESS                 METHOD

host    replication     repuser         192.168.1.102/32        md5

# 或者允许所有IP进行复制连接,但不推荐用于生产环境

# host    replication     repuser         0.0.0.0/0               md5

  • replication 是一个特殊的“数据库”,表示复制连接。

  • repuser 是你将要创建的复制用户。

  • 192.168.1.102/32 是你的从库IP地址。

  1. 创建复制用户

postgres 用户身份连接到主库,创建用于复制的用户:


# 切换到postgres用户

sudo -i -u postgres

# 进入psql控制台

psql

# 创建复制用户

CREATE USER repuser REPLICATION LOGIN CONNECTION LIMIT -1 ENCRYPTED PASSWORD 'your_secure_password';

# 退出psql

\q

注意: 请将 your_secure_password 替换为强密码。

  1. 重启 Primary (主库) 服务

使配置生效:


sudo systemctl restart postgresql

# 或者根据你的系统和PostgreSQL版本使用相应的命令,例如:

# sudo /etc/init.d/postgresql restart


第二步:Replica (从库) 初始化

  1. 停止 Replica (从库) 服务 (如果正在运行)

如果你的从库上已经有 PostgreSQL 服务在运行,请先停止它。


sudo systemctl stop postgresql

  1. 清空从库数据目录 (重要!)

警告: 这会删除从库上所有现有的 PostgreSQL 数据。请确保你清楚自己在做什么!

找到从库的 PostgreSQL 数据目录 (例如 /var/lib/postgresql/1X/main/usr/local/pgsql/data)。


# 假设数据目录是 /var/lib/postgresql/14/main

sudo rm -rf /var/lib/postgresql/14/main/*

  1. 使用 pg_basebackup 获取基准备份

切换到能够访问到 PostgreSQL 数据目录的用户 (通常是 postgres 用户),然后执行以下命令:


sudo -i -u postgres

# 替换 primary_ip, repuser, your_secure_password, 和你的数据目录路径

# 例如:pg_basebackup -h 192.168.1.101 -U repuser -D /var/lib/postgresql/14/main -F p -X stream -P -v -R -w

pg_basebackup -h 192.168.1.101 \

-U repuser \

-D /var/lib/postgresql/14/main \

-F p \

-X stream \

-P \

-v \

-R \

-w

参数说明:

  • -h 192.168.1.101: 主库的IP地址。

  • -U repuser: 用于连接主库的复制用户。

  • -D /var/lib/postgresql/14/main: 从库的数据目录。

  • -F p: 输出格式为 “plain” (纯文件),而不是 “tar”。

  • -X stream: 在备份过程中同时流式传输 WAL 日志。

  • -P: 显示进度。

  • -v: 详细输出。

  • -R: 最重要! 自动创建 standby.signal 文件并在 postgresql.auto.conf 中添加 primary_conninfo。这是简化配置的关键!

  • -w: 提示输入密码(如果密码不在环境变量中)。

执行命令后会要求输入 repuser 的密码。

  1. 确认从库配置

pg_basebackup -R 已经帮你完成了大部分配置。你可以检查从库数据目录下是否生成了:

  • standby.signal 文件(这是一个空文件,PostgreSQL 启动时检测到它就会进入恢复模式)。

  • postgresql.auto.conf 文件中包含了 primary_conninfo 参数,类似这样:


# Do not edit this file manually!

# It will be overwritten by the ALTER SYSTEM command.

primary_conninfo = 'user=repuser password=your_secure_password host=192.168.1.101 port=5432 sslmode=prefer sslcompression=0 gsslib=0 channel_binding=prefer'

pg_basebackup 会自动将密码写入这个文件。在生产环境中,出于安全考虑,你可能需要手动修改 primary_conninfo,将密码从明文移除,并通过 .pgpass 文件或其他更安全的方式提供密码。但对于简单测试,这样是可以的。


第三步:启动 Replica (从库) 服务并验证

  1. 启动 Replica (从库) 服务

sudo systemctl start postgresql

  1. 验证复制状态
  • 在 Primary (主库) 上检查:

sudo -i -u postgres

psql -c "SELECT client_addr, state, sync_state, sync_priority FROM pg_stat_replication;"

你应该看到一行输出,其中 client_addr 是从库的IP,statestreamingsync_state 通常是 async (异步)。

  • 在 Replica (从库) 上检查:

sudo -i -u postgres

psql -c "SELECT pg_is_in_recovery();"

应该返回 t (true)。


psql -c "SELECT pg_last_wal_replay_lsn();"

# 记录这个LSN

# 在主库上运行以下命令,比较LSN,看是否接近或相同

psql -h 192.168.1.101 -U postgres -c "SELECT pg_current_wal_lsn();"

pg_last_wal_replay_lsn() (从库) 应该接近或等于 pg_current_wal_lsn() (主库)。

在主库上插入一些数据,然后在从库上查询,看看数据是否同步过来。

主库:


CREATE TABLE test_repl (id INT, name TEXT);

INSERT INTO test_repl VALUES (1, 'hello');

SELECT * FROM test_repl;

从库:


SELECT * FROM test_repl; -- 应该能看到 'hello'

-- 尝试插入数据会失败,因为从库是只读的

-- INSERT INTO test_repl VALUES (2, 'world');


重要注意事项:

  • 防火墙: 确保主库的 5432 端口对从库开放,反之亦然(如果需要从从库连接到主库)。

  • WAL Archiving (WAL 归档): 虽然不是流复制的硬性要求,但在生产环境中强烈建议开启。它能让你在从库长时间掉线后通过归档日志进行恢复,也方便进行 Point-in-Time Recovery (PITR)。

  • 安全:

  • repuser 应该使用强密码。

  • pg_hba.conf 中尽可能指定从库的精确 IP 地址,而不是 0.0.0.0/0

  • primary_conninfo 中的密码最好通过 .pgpass 文件或其他方式保护,而不是明文存储在 postgresql.auto.conf 中。

  • 同步 vs. 异步: 上述配置是异步复制。这意味着主库在写入数据后不需要等待从库确认就已经提交事务。这提供了更好的性能,但可能会在主库崩溃时导致少量数据丢失。同步复制可以防止数据丢失,但会增加主库的事务延迟。

  • 高可用性: 这个配置只是实现了主从复制,不包含自动故障转移。如果主库挂了,你需要手动提升从库为主库,并配置其他从库连接到新的主库。这通常需要使用像 Patroni、PgBouncer、repmgr 或 corosync/pacemaker 等工具来构建高可用集群。

  • 版本兼容性: 本指南主要针对 PostgreSQL 12 及更高版本。对于 PostgreSQL 11 及更早版本,recovery.conf 文件扮演了 standby.signalprimary_conninfo 的角色。

这个方法是搭建 PostgreSQL 流复制最简单、最快捷的方式,非常适合初次尝试或测试环境。


网站公告

今日签到

点亮在社区的每一天
去签到