基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

PostgreSQL的流复制(Streaming Replication)

知识点图片

PostgreSQL 的流复制(Streaming Replication)是 PostgreSQL 原生提供的一种物理复制技术。它是目前 PostgreSQL 实现高可用性(HA)、读写分离和灾难恢复的最核心、最常用的手段。

自 PostgreSQL 9.0 引入以来,流复制经过不断完善,已经非常稳定和高效。

以下是关于 PostgreSQL 流复制的全面解析:


1. 流复制的核心原理

流复制是基于 WAL(Write-Ahead Log,预写式日志) 实现的。它的本质是把主库(Primary)上产生的底层物理数据变更日志(WAL),源源不断地“流”向备库(Standby),备库接收到后重放(Replay)这些日志,从而保证主备数据一致。

工作流程及核心进程:

  1. 主库(Primary): 产生 WAL 日志。主库上会启动一个 walsender 进程。
  2. 备库(Standby): 启动一个 walreceiver 进程。它连接到主库的 walsender,请求获取 WAL 日志。
  3. 网络传输: walsender 通过 TCP 连接将 WAL 数据流式传输给 walreceiver
  4. 备库落盘与重放: walreceiver 将接收到的 WAL 写入备库的磁盘,然后备库的 startup(启动进程)读取这些 WAL 并应用到备库的数据文件中。

(注意:流复制是“物理复制”,即主备库在磁盘上的数据块(Block)是完全一模一样的。备库严格来说是一个处于“持续恢复状态”的只读副本。)


2. 复制模式:异步 vs 同步

流复制支持两种模式:

A. 异步复制(Asynchronous Replication)- 默认

  • 原理: 主库执行事务,将 WAL 写入本地磁盘后,直接向客户端返回“提交成功”,不等待备库接收 WAL。
  • 优点: 性能极高,主库的写入速度不受网络和备库性能的影响。
  • 缺点: 如果主库突然宕机,部分还未传输到备库的 WAL 会丢失,导致主备切换时丢失极少量数据

B. 同步复制(Synchronous Replication)

  • 原理: 主库执行事务,将 WAL 写入本地后,必须等待至少一个同步备库确认已经接收并写入了 WAL,主库才会向客户端返回“提交成功”。
  • 优点: 保证零数据丢失(RPO = 0)。
  • 缺点: 写性能下降。主库的提交延迟取决于网络延迟和备库的 I/O 速度;如果同步备库宕机,主库的写操作会被阻塞(可以配置多个备库或超时策略来缓解)。

3. 如何搭建流复制(以 PostgreSQL 12+ 为例)

注意:PostgreSQL 12 废弃了 recovery.conf 文件,相关配置合并到了 postgresql.conf,并使用 standby.signal 标识备库。

假设:主库 IP 192.168.1.100,备库 IP 192.168.1.101

第一步:配置主库 (Primary)

  1. 创建复制专属用户:
    sql
    CREATE ROLE repl_user WITH REPLICATION LOGIN PASSWORD 'YourPassword';
  2. 修改 pg_hba.conf 允许备库连接:
    plaintext
    # TYPE  DATABASE        USER            ADDRESS                 METHOD
    host    replication     repl_user       192.168.1.101/32        scram-sha-256
  3. 修改 postgresql.conf 参数:
    plaintext
    listen_addresses = '*'       # 监听所有IP
    wal_level = replica          # 必须是 replica 或 logical
    max_wal_senders = 10         # 允许的最大 walsender 进程数
    wal_keep_size = 1GB          # (PG13+) 保留的WAL大小,防止备库断开太久WAL被清理 (PG12及以前叫 wal_keep_segments)
  4. 重启主库: systemctl restart postgresql

第二步:配置备库 (Standby)

  1. 停止备库服务,并清空备库原有的数据目录(非常重要):
    bash
    systemctl stop postgresql
    rm -rf /var/lib/pgsql/data/*
  2. 使用 pg_basebackup 从主库克隆数据:
    bash
    pg_basebackup -h 192.168.1.100 -U repl_user -D /var/lib/pgsql/data -Fp -Xs -P -R
    参数解释:
    • -h 主库IP,-U 复制用户,-D 目标数据目录。
    • -Fp 纯文本格式输出。
    • -Xs 在备份过程中同时流式获取 WAL(保证备份的一致性)。
    • -P 显示进度。
    • -R(最关键):自动生成 standby.signal 文件,并在 postgresql.auto.conf 中自动写入 primary_conninfo(连接主库的配置)。
  3. 确保备库目录权限正确,启动备库:
    bash
    chown -R postgres:postgres /var/lib/pgsql/data
    systemctl start postgresql

第三步:验证状态

主库执行:

sql
SELECT * FROM pg_stat_replication;

如果能看到一条记录,且 statestreaming,说明流复制已经建立并正常运行。

备库执行:

sql
SELECT * FROM pg_stat_wal_receiver;

4. 主备切换与故障转移(Failover / Switchover)

由于流复制中备库是只读的,当主库宕机时,需要将备库提升(Promote) 为新的主库。

手动提升备库:
在备库服务器上执行:

bash
pg_ctl promote -D /var/lib/pgsql/data

或者在备库数据库内执行 SQL:

sql
SELECT pg_promote();

提升后,备库会解除只读状态,变为可读写的主库。

自动高可用(HA):
生产环境中,通常不会手动去 Promote 数据库。业界有成熟的第三方组件来监控主备状态,并在主库故障时自动进行切换(并管理虚拟 IP):

  • Patroni(目前最主流、最推荐的方案,依赖 etcd/Consul/ZooKeeper)
  • Repmgr
  • Pacemaker + Corosync
  • Keepalived (较老派,容易出现脑裂)

5. 常见问题与优化策略

  1. 主备延迟(Replication Lag):
    • 原因:网络带宽不足、备库 I/O 性能差、主库有大量写事务。
    • 监控:主库上的 pg_stat_replication 视图可以查看发送和重放的 LSN 差距。
  2. 流复制中断(WAL 被覆盖):
    • 如果备库断开连接太久,主库上旧的 WAL 被循环覆盖清理了,备库重连后会报错找不到 WAL。
    • 解决:
      1. 配置合理的 wal_keep_size
      2. 推荐方案: 使用 Replication Slots(复制槽)。主库会为存在复制槽的备库强制保留 WAL,直到备库消费它们。
  3. 读写分离与查询冲突:
    • 备库提供只读查询。但如果备库上一个耗时很长的查询锁定了某些数据,而主库刚好发来了删除/更新该数据的 WAL 操作,就会发生“复制冲突”。
    • 解决: 配置参数 max_standby_streaming_delay(允许备库延迟重放 WAL 的时间)或 hot_standby_feedback = on(备库告诉主库不要清理备库正在查询的死元组)。

6. 流复制 vs 逻辑复制 (Logical Replication)

特性 物理流复制 (Streaming Replication) 逻辑复制 (Logical Replication)
复制粒度 整个数据库集群(实例级) 表级、库级
底层原理 传输物理块的 WAL 解析 WAL 为逻辑 SQL (Insert/Update)
版本要求 主备大版本必须一致 支持跨版本(如 PG 11 复制到 PG 15)
备库状态 严格只读 目标端依然可读写
主要用途 高可用(HA)、灾备、全库读写分离 数据同步、汇总、跨版本升级、特定表分发
00:00
00:00