Skip to content

PostgreSQL 主从复制(流复制)

核心概念

PostgreSQL主从复制是一种数据冗余机制,通过将主数据库(Master)的数据变更实时同步到一个或多个从数据库(Slave/Standby),实现数据备份、读写分离和高可用性。

流复制工作原理

流复制(Streaming Replication)是PostgreSQL 9.0引入的物理复制技术,其工作原理如下:

  1. 主库将事务写入WAL(Write-Ahead Log)日志
  2. 从库通过WAL接收器(walreceiver)连接到主库的WAL发送器(walsender)
  3. 主库实时将WAL记录流发送到从库
  4. 从库应用收到的WAL记录,保持与主库数据一致
  5. 从库可以处于两种模式:
    • 恢复模式(Recovery Mode):只读,不能接受写操作
    • 热备模式(Hot Standby):只读,可以接受查询操作

复制类型

复制类型描述适用场景
异步复制主库不等待从库确认收到WAL记录对数据一致性要求不高,追求高性能
同步复制主库等待从库确认收到并写入WAL记录对数据一致性要求高,如金融系统
半同步复制主库等待至少一个从库确认收到WAL记录平衡性能和一致性的场景

配置步骤

1. 环境准备

角色IP地址操作系统PostgreSQL版本数据目录
主库192.168.1.10CentOS 715/var/lib/pgsql/15/data
从库192.168.1.11CentOS 715/var/lib/pgsql/15/data

2. 主库配置

2.1 修改postgresql.conf

bash
# 启用WAL归档
archive_mode = on
archive_command = 'cp %p /var/lib/pgsql/15/archive/%f'

# 配置WAL级别(流复制需要replica或更高)
wal_level = replica

# 最大WAL发送进程数(建议与从库数量匹配)
max_wal_senders = 5

# 最大复制槽数量
max_replication_slots = 5

# 同步复制超时时间
wal_sender_timeout = 60s

# 启用热备(从库可以接受查询)
hot_standby = on

2.2 创建归档目录

bash
mkdir -p /var/lib/pgsql/15/archive
chown -R postgres:postgres /var/lib/pgsql/15/archive
chmod 700 /var/lib/pgsql/15/archive

2.3 修改pg_hba.conf

bash
# 允许从库连接进行复制
host    replication     replicauser     192.168.1.11/32         scram-sha-256
host    replication     replicauser     192.168.1.12/32         scram-sha-256

2.4 创建复制用户

sql
-- 以postgres用户身份连接到主库
psql -h localhost -U postgres

-- 创建复制用户
CREATE ROLE replicauser WITH REPLICATION LOGIN PASSWORD 'replicapass';

-- 重载配置
SELECT pg_reload_conf();

3. 从库配置

3.1 停止从库PostgreSQL服务

bash
systemctl stop postgresql-15

3.2 清空从库数据目录

bash
rm -rf /var/lib/pgsql/15/data/*

3.3 使用pg_basebackup初始化从库

bash
# 从主库复制基础备份到从库
pg_basebackup -h 192.168.1.10 -U replicauser -D /var/lib/pgsql/15/data -Fp -Xs -Pv

参数说明:

  • -h:主库IP地址
  • -U:复制用户
  • -D:从库数据目录
  • -Fp:使用普通文件格式
  • -Xs:流式传输WAL文件
  • -Pv:显示进度和详细信息

3.4 创建recovery.signal文件

bash
# 创建recovery.signal文件,指示从库处于恢复模式
touch /var/lib/pgsql/15/data/recovery.signal

3.5 创建standby.signal文件(PostgreSQL 12+)

bash
# 创建standby.signal文件,指示从库为备用节点
touch /var/lib/pgsql/15/data/standby.signal

3.6 配置recovery.conf(PostgreSQL 11及以下)或postgresql.auto.conf(PostgreSQL 12+)

对于PostgreSQL 12+,配置会自动写入postgresql.auto.conf。如果需要手动配置,可以创建primary_conninfo参数:

bash
# 编辑postgresql.auto.conf,添加主库连接信息
echo "primary_conninfo = 'host=192.168.1.10 port=5432 user=replicauser password=replicapass application_name=standby1'" >> /var/lib/pgsql/15/data/postgresql.auto.conf

# 配置从库为只读模式
echo "hot_standby = on" >> /var/lib/pgsql/15/data/postgresql.auto.conf

3.7 设置文件权限

bash
chown -R postgres:postgres /var/lib/pgsql/15/data
chmod 700 /var/lib/pgsql/15/data

3.8 启动从库PostgreSQL服务

bash
systemctl start postgresql-15

复制监控与管理

1. 监控复制状态

1.1 在主库上监控

sql
-- 查看WAL发送进程状态
SELECT * FROM pg_stat_replication;

-- 查看复制槽状态
SELECT * FROM pg_replication_slots;

-- 查看WAL归档状态
SELECT * FROM pg_stat_archiver;

1.2 在从库上监控

sql
-- 查看复制状态
SELECT * FROM pg_stat_wal_receiver;

-- 查看恢复状态
SELECT * FROM pg_stat_wal_receiver;

-- 查看复制延迟
SELECT now() - pg_last_xact_replay_timestamp() AS replication_delay;

-- 查看从库是否处于只读模式
SHOW transaction_read_only;

2. 常用管理命令

2.1 主库命令

sql
-- 手动切换WAL日志
SELECT pg_switch_wal();

-- 创建复制槽
SELECT * FROM pg_create_physical_replication_slot('slot_name');

-- 删除复制槽
SELECT * FROM pg_drop_replication_slot('slot_name');

2.2 从库命令

sql
-- 取消恢复模式(使从库变为独立数据库)
pg_ctl promote -D /var/lib/pgsql/15/data

-- 或在从库中执行
SELECT pg_promote();

3. 复制监控工具

3.1 pg_stat_replication视图详解

列名描述
pidWAL发送进程ID
usesysid复制用户ID
usename复制用户名
application_name从库应用名称
client_addr从库IP地址
client_hostname从库主机名
client_port从库端口
backend_start连接开始时间
backend_xmin从库最后接收的事务ID
state复制状态(streaming, catching up, etc.)
sent_lsn已发送的WAL位置
write_lsn从库已写入的WAL位置
flush_lsn从库已刷新到磁盘的WAL位置
replay_lsn从库已应用的WAL位置
write_lag写入延迟
flush_lag刷新延迟
replay_lag应用延迟
sync_priority同步优先级
sync_state同步状态(async, sync, quorum)

同步复制配置

1. 异步复制 vs 同步复制

特性异步复制同步复制
性能较低
数据一致性可能丢失数据数据不丢失
故障影响主库故障可能丢失最近事务主库故障不会丢失数据
配置复杂度

2. 配置同步复制

2.1 修改主库postgresql.conf

bash
# 配置同步复制模式
synchronous_commit = on

# 指定同步从库名称列表
synchronous_standby_names = 'standby1,standby2'

2.2 验证同步复制状态

sql
-- 在主库上查看同步状态
SELECT usename, application_name, state, sync_state FROM pg_stat_replication;

常见问题与故障排除

1. 从库连接失败

症状

FATAL:  could not connect to the primary server: FATAL:  no pg_hba.conf entry for replication connection from host "192.168.1.11", user "replicauser", SSL off

解决方法

  • 检查pg_hba.conf是否允许从库IP连接
  • 检查复制用户密码是否正确
  • 检查主库防火墙是否开放5432端口

2. 复制延迟过大

症状

replication_delay | 00:05:30.123456

解决方法

  • 检查网络带宽是否足够
  • 检查主库WAL生成速率是否过高
  • 检查从库IO性能是否瓶颈
  • 调整从库参数:hot_standby_feedback = on

3. WAL归档失败

症状

WARNING:  archive command failed with exit code 1
DETAIL:  The failed archive command was: cp pg_wal/000000010000000000000001 /var/lib/pgsql/15/archive/000000010000000000000001

解决方法

  • 检查归档目录权限
  • 检查归档目录磁盘空间
  • 检查归档命令语法

4. 从库无法启动

症状

FATAL:  database system identifier differs between the primary and standby

解决方法

  • 确保从库是使用pg_basebackup从主库初始化的
  • 检查从库数据目录是否正确清空
  • 重新执行pg_basebackup初始化从库

最佳实践

1. 硬件配置

  • 主从库使用相同或相似的硬件配置
  • 使用SSD存储提高IO性能
  • 确保主从库之间网络带宽充足(建议1Gbps以上)

2. 配置优化

  • 使用复制槽避免WAL日志丢失
  • 启用hot_standby_feedback避免查询冲突
  • 定期监控复制延迟,设置合理的告警阈值
  • 使用同步复制或半同步复制提高数据安全性

3. 监控与告警

  • 监控复制延迟,设置告警阈值(如>30秒)
  • 监控WAL发送和接收进程状态
  • 监控归档命令执行情况
  • 定期测试主从切换,确保故障切换可行

4. 安全配置

  • 为复制用户设置强密码
  • 限制复制连接的IP地址范围
  • 使用SSL加密复制连接
  • 定期轮换复制用户密码

5. 备份策略

  • 从库可以作为备份源,减少主库备份压力
  • 定期在从库上执行基础备份
  • 结合WAL归档实现PITR(Point-In-Time Recovery)

常见问题(FAQ)

Q1:如何检查主从复制是否正常工作?

A1:可以通过以下方法检查:

sql
-- 在主库上查看复制状态
SELECT * FROM pg_stat_replication;

-- 在从库上查看复制延迟
SELECT now() - pg_last_xact_replay_timestamp() AS replication_delay;

Q2:主从复制支持读写分离吗?

A2:是的,PostgreSQL主从复制天然支持读写分离:

  • 主库处理写操作和实时读操作
  • 从库处理报表查询、数据分析等只读操作

Q3:如何增加新的从库?

A3:增加新从库的步骤:

  1. 在主库的pg_hba.conf中添加新从库的IP地址
  2. 在主库上重载配置
  3. 在新从库上使用pg_basebackup从主库初始化
  4. 配置新从库的recovery.signal和postgresql.auto.conf
  5. 启动新从库

Q4:主库故障后如何将从库提升为主库?

A4:主库故障后提升从库的步骤:

  1. 停止主库(如果还在运行)
  2. 在从库上执行pg_ctl promote -D /var/lib/pgsql/15/data
  3. 修改应用连接字符串,指向新主库
  4. 重新配置其他从库连接到新主库

Q5:如何配置半同步复制?

A5:配置半同步复制的步骤:

  1. 安装半同步复制扩展
  2. 修改postgresql.conf启用半同步复制
  3. 配置同步 standby 名称
  4. 重载配置

Q6:复制槽有什么作用?

A6:复制槽的作用:

  • 确保主库保留从库需要的所有WAL日志
  • 防止主库过早删除从库尚未接收的WAL日志
  • 支持从库离线后重新连接时能够追上主库

Q7:如何监控复制性能?

A7:可以监控以下指标:

  • 复制延迟
  • WAL生成速率
  • WAL发送和接收速率
  • 从库IO利用率
  • 网络带宽使用率

Q8:主从复制会影响主库性能吗?

A8:主从复制对主库性能的影响:

  • 会增加主库的CPU和内存使用
  • 会增加主库的网络带宽消耗
  • 异步复制对主库性能影响较小
  • 同步复制会增加主库事务提交延迟

Q9:如何测试主从复制的可靠性?

A9:测试主从复制可靠性的方法:

  • 执行大量写操作,检查从库是否能及时同步
  • 模拟主库故障,测试从库提升流程
  • 测试从库故障恢复后能否重新连接主库
  • 测试网络中断后复制能否自动恢复

Q10:PostgreSQL 15有哪些复制新特性?

A10:PostgreSQL 15复制新特性:

  • 支持并行应用WAL日志,提高从库复制速度
  • 增强了复制槽管理功能
  • 改进了WAL发送和接收性能
  • 支持更灵活的同步复制配置

故障切换案例

场景:主库突然宕机

故障现象

  • 主库服务器断电
  • 应用连接失败
  • 从库复制中断

处理步骤

  1. 确认主库故障

    bash
    ping 192.168.1.10  # 检查网络连接
    ssh 192.168.1.10    # 尝试SSH登录
    systemctl status postgresql-15  # 检查PostgreSQL状态
  2. 提升从库为主库

    bash
    # 在从库上执行
    pg_ctl promote -D /var/lib/pgsql/15/data
  3. 验证新主库状态

    sql
    -- 检查是否已提升为主库
    SELECT pg_is_in_recovery();  -- 应返回false
    
    -- 检查是否可写
    SHOW transaction_read_only;  -- 应返回off
  4. 更新应用连接配置

    • 修改应用配置文件中的数据库连接地址为新主库IP
    • 重启应用或重载配置
  5. 重新配置其他从库

    • 停止其他从库
    • 清空数据目录
    • 使用pg_basebackup从新主库初始化
    • 重启从库
  6. 修复原主库

    • 修复硬件故障
    • 重新安装操作系统和PostgreSQL
    • 将原主库配置为新主库的从库