PostgreSQL 流复制(Streaming Replication)是实现高可用性、负载均衡和灾难恢复的核心技术。它允许一个主服务器(Primary/Master)将一个或多个备用服务器(Standby/Replica)保持为实时更新状态。
以下为从零开始用pg_basebackup物理备份搭建 PostgreSQL 流复制(异步/同步)的详细步骤。
架构概述
- 主服务器 (Primary):接受读写操作的数据库服务器。
- 备服务器 (Standby):接收并应用主服务器的 WAL (Write-Ahead Logging) 数据,通常只读。
- 流复制:备服务器通过一个普通的 PostgreSQL 连接,实时地、流式地从主服务器接收 WAL 记录,并在备服务器上重放。
- 同步与异步 :
- 异步(默认):主服务器提交事务后,无需等待备服务器确认即向客户端返回成功。性能好,但有少量数据丢失风险。
- 同步:主服务器提交事务后,必须等待至少一个备服务器确认收到WAL数据后才向客户端返回成功。数据安全性高,但会增加事务延迟。
本指南以异步流复制为例。
详细步骤
假设我们有两台服务器:
- 主服务器 :
192.168.1.10
, 端口5432
- 备服务器 :
192.168.1.11
, 端口5432
第一部分:主服务器配置
-
创建复制专用用户
在主服务器上,创建一个专门用于流复制的用户。这个用户需要有
REPLICATION
权限。sqlpsql -U postgres -d postgres
sqlCREATE ROLE rep WITH LOGIN REPLICATION PASSWORD 'rep123';
-
配置 pg_hba.conf
修改 PostgreSQL 的主机基于认证配置文件 (
pg_hba.conf
),允许备服务器以repl_user
用户连接进行复制。bash# 找到你的 pg_hba.conf 位置 # 通常位于 $PGDATA/pg_hba.conf 或 /etc/postgresql/版本/主目录/pg_hba.conf sudo vi $PGDATA/pg_hba.conf
在文件末尾添加一行:
# TYPE DATABASE USER ADDRESS METHOD host replication repl_user 192.168.1.11/32 md5
replication
: 特殊的伪数据库名,表示此规则用于流复制连接。repl_user
: 我们刚刚创建的复制用户。192.168.1.11/32
: 备服务器的 IP 地址,/32
表示一个主机。md5
: 要求密码认证。
-
配置 postgresql.conf
修改 PostgreSQL 的主配置文件 (
postgresql.conf
)。bashsudo vi $PGDATA/postgresql.conf
修改或确保以下参数已设置:
properties# 监听所有连接 listen_addresses = '*' # 服务端口 port = 5432 # 开启 WAL 归档(虽然不是流复制必需,但强烈建议) archive_mode = on archive_command = 'test ! -f /path/to/archive/%f && cp %p /path/to/archive/%f' # 设置 Wal Level 为 replica 或更高级别,这是流复制的必要条件 wal_level = replica # 设置最大 WAL 发送进程数,至少大于等于备服务器数量 max_wal_senders = 10 # 设置保留在 pg_wal 目录中的 WAL 段文件的最小数量,防止主服务器在备服务器追上之前删除需要的 WAL wal_keep_size = 1GB # 在同步复制中设置备服务器名称,异步复制可先忽略 # synchronous_standby_names = 'FIRST 1 (standby1)'
-
重启主服务器
使配置生效。
bashsudo systemctl restart postgresql 或 pg_ctl -D $PGDATA restart
第二部分:备服务器配置
-
停止 PostgreSQL 服务
bashsudo systemctl stop postgresql 或 pg_ctl -D $PGDATA stop
-
清空数据目录
确保备服务器的 PostgreSQL 数据目录(例如
/var/lib/postgresql/版本/main
)是空的。(操作前请务必备份原有数据!)bashsudo su - postgres cd $PGDATA rm -rf *
-
使用 pg_basebackup 进行基础备份
这是最关键的一步。它从主服务器获取一个完整的数据快照,并自动配置
standby.signal
文件。bash# 以 postgres 用户执行 pg_basebackup -h 192.168.1.10 -D $PGDATA -U repl_user -P -v -R -W
-h 192.168.1.10
: 主服务器的 IP 地址。-D $PGDATA
: 指定备服务器的数据目录,将备份文件存储于此。-U repl_user
: 使用之前创建的复制用户。-P
: 显示进度。-v
: 详细模式。-R
: (重要) 自动创建standby.signal
文件并在postgresql.auto.conf
中写入连接信息。这大大简化了配置。-W
: 在执行前提示输入密码(repl_user
的密码)。
执行成功后,你会在备服务器的
$PGDATA
目录下发现一个standby.signal
文件,并且postgresql.auto.conf
文件中包含了主服务器的连接信息。 -
(可选)手动配置备服务器(如果未使用 -R 参数)
如果你没有使用
-R
参数,需要手动执行以下步骤:a. 创建
standby.signal
文件:bashtouch $PGDATA/standby.signal
b. 在
postgresql.auto.conf
或postgresql.conf
中添加:propertiesprimary_conninfo = 'host=192.168.1.10 port=5432 user=repl_user password=rep123'
注意 :在生产环境中,建议将密码存储在
~/.pgpass
文件中,而不是直接写在配置文件中。【~/.pgpass配置方法见博客:https://blog.csdn.net/liumangtuzi888/article/details/152603650?spm=1011.2124.3001.6209】
第三部分:启动与验证
-
启动备服务器
bashsudo systemctl start postgresql 或 pg_ctl -D $PGDATA start
-
检查备服务器日志
启动后,立即检查备服务器的日志文件,查看是否有错误。
bashtail -f $PGDATA/log/postgresql-Mon.log
你应该能看到类似以下的信息,表明流复制已经开始:
LOG: database system is ready to accept read-only connections LOG: started streaming WAL from primary at 0/3000000 on timeline 1
-
在主服务器上验证复制状态
连接到主服务器,查询复制状态。
sqlpsql -U postgres -d postgres
sql-- 查看发送进程状态 SELECT application_name, client_addr, state, sync_state, sync_priority FROM pg_stat_replication;
预期结果 :你应该能看到一行记录,其中
application_name
通常是walreceiver
,client_addr
是备服务器的 IP (192.168.1.11
),state
为streaming
,sync_state
为async
(对于异步复制)。这表明流复制正在正常运行。 -
在备服务器上测试
在备库上查询主从流复制状态:
psql -p 5432 -c "SELECT pg_is_in_recovery();"
-- 结果应为 t (true)
psql -p 5432 -c "SELECT * FROM pg_stat_wal_receiver;"
连接到备服务器,尝试执行写操作,应该会被拒绝。
```sql
psql -U postgres -d postgres
```
```sql
-- 这应该成功,因为备服务器是只读的
SELECT count(*) FROM your_table_name;
-- 这应该失败,并提示数据库是只读的
INSERT INTO your_table_name VALUES (...);
```
故障排查
- 连接失败 :检查主备服务器之间的网络、防火墙设置,以及
pg_hba.conf
中的配置。 - 认证失败 :确认
repl_user
的密码是否正确,以及pg_hba.conf
中的md5
方法。 - WAL 相关错误 :检查主服务器上的
wal_level
、max_wal_senders
和wal_keep_size
设置是否足够。 - 始终查看日志:主备服务器的日志是解决问题的第一手资料。
升级到同步复制
如果你想配置同步复制,只需修改主服务器 的 postgresql.conf
:
properties
synchronous_standby_names = 'FIRST 1 (standby1)'
并在备服务器的 primary_conninfo
中设置一个 application_name
(如果使用 -R
参数,它可能已经自动设置了,检查 postgresql.auto.conf
)。
properties
primary_conninfo = 'host=192.168.1.10 port=5432 user=repl_user password=YourSecurePassword123 application_name=standby1'
然后重新加载主、备服务器配置:pg_ctl reload
。
完成以上步骤,分别成功搭建了一个 PostgreSQL 异步和同步流复制环境。