3.4 流复制与逻辑复制:两套日志两种世界观


3.4 流复制与逻辑复制:两套日志两种世界观

本节摘要:物理流复制传输原始 WAL 字节流,备库按字节重放,与主库逐块一致,适合高可用与读写分离;逻辑复制先由发布端把 WAL 解码成"INSERT/UPDATE/DELETE"级别的逻辑变更再传输,订阅端自行执行,可跨大版本、可挑表、可双向。两套体系吃的是同一条日志流,服务的是不同的问题。

物理流复制:字节级克隆

主库启动 WAL 发送进程,备库以 WAL 接收进程连上来,日志字节流实时推送,备库持续按 WAL 重放——本质上是永不停止的崩溃恢复。

-- 备库侧的连接配置示意 -- primary_conninfo = '主库地址与复制账号' -- 备库查询复制延迟 SELECT now() - pg_last_xact_replay_timestamp() AS lag;

三种角色由参数决定:

模式 行为 典型用途
异步流复制 日志发出即算完,不等备库 读写分离、容灾
同步复制 主库提交要等至少一个备库落盘 零丢失要求
级联复制 备库再向下游分发 多机房减少主库负担

代价是整个集群共享一个世界观:备库与主库物理一致,所以备库只读、不能跨大版本、也不能只要其中几张表。

逻辑复制:把日志翻译回 SQL

逻辑复用在 WAL 上加了一层"逻辑解码":发布端的解码插件读出 WAL,还原成行级变更事件,按发布定义过滤后传给订阅端,订阅端像执行普通 SQL 一样应用它们。

-- 发布端:只发布两张表 CREATE PUBLICATION sales_pub FOR TABLE orders, order_item; -- 订阅端(可以是另一套库、另一个大版本) CREATE SUBSCRIPTION sales_sub CONNECTION '发布端连接串' PUBLICATION sales_pub;

因为传输的是逻辑变更而非页面字节,约束彻底改变:

  • 订阅端可写,可以有自己的索引、自己的表结构(列可以不同名、部分列)
  • 跨大版本没问题——升级常用它做灰度切换
  • 只同步表级数据,不含 DDL:发布端加列,订阅端要手动跟上

一次对比就看懂选型

需求 选谁 原因
高可用、自动故障切换 物理流复制 逐块一致,切换零解释成本
跨版本滚动升级 逻辑复制 字节格式随版本变化,逻辑层免疫
只同步部分业务表到报表库 逻辑复制 物理复制是全有或全无
多主/双向写入 逻辑复制(谨慎设计) 物理复制不支持两方向

图:同一条日志流的两种消费方式

💡 关键直觉:物理复制的单位是"页面怎么变",逻辑复制的单位是"这行数据怎么变"。前者的世界必须一模一样,后者的世界只需要表结构能对上。

复制槽:日志保留的记账员

物理复制的账本由复制槽管理。备库断线期间,主库必须保留未发送的 WAL——复制槽就是这份"欠条"的登记处:

-- 主库上看槽位与积压 SELECT slot_name, active, restart_lsn, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained FROM pg_replication_slots;
slot_name | active | restart_lsn | retained -----------+--------+-------------+---------- standby1 | t | 0/4A100000 | 12 MB

retained 列是关键读数:备库健康时它就是正常延迟;备库长时间下线而槽未删,它会无限增长,直到主库日志盘被占满、整库停摆——这是流复制最经典的自杀路径。配套的保险丝是 max_slot_wal_keep_size:给每个槽设保留上限,超限后废弃该槽的保留承诺(代价是依赖它的备库需要重建)。生产配置应当显式设置这个上限,而不是赌备库永远健康。

延迟监控的三层读数

复制延迟不是一个数,是三个。发送延迟(主库已写、未发)、落盘延迟(备库已收、未刷)、重放延迟(备库已刷、未应用),分别对应 pg_stat_replication 的 write_lag、flush_lag、replay_lag:

SELECT application_name, state, sync_state, write_lag, flush_lag, replay_lag FROM pg_stat_replication;

区分它们在排障时有实际意义:发送延迟大查网络与主库负载;落盘延迟大查备库磁盘;重放延迟大查备库上的重放单线程瓶颈(大事务在备库重放时无法并行,主库跑十分钟的批量更新,备库也要重放约十分钟)。读写分离的业务读到的是重放完成的数据,因此对一致性敏感的读必须以 replay_lag 为准,必要时用同步级别或应用层粘主库解决。

逻辑复制的三个工程暗礁

暗礁一:初始数据同步期间发布端持锁。CREATE SUBSCRIPTION 默认先做一次全量拷贝,大表拷贝期间会在发布端拿表锁,生产表上要错峰或用 schema 与数据分步的方式做。暗礁二:约束冲突即停。订阅端应用变更遇到唯一键冲突,复制立刻停摆等人工介入——订阅端表如果有业务同时在写,冲突几乎必然发生,所以订阅端表通常要对业务侧禁写。暗礁三:大事务同步放大。发布端一个千万行的大事务,解码后作为单事务传给订阅端,订阅端整事务应用;主库跑两小时的批量任务,订阅端可能跟随卡两小时。批量迁移类任务在逻辑复制链路上要拆小事务提交。

这三条暗礁共同指向一个结论:逻辑复制是灵活的数据分发工具,不是即插即用的镜像;它的每一分灵活性都以"两端各自承担工程责任"为代价。

本节要点回顾

  • 物理复制搬字节:备库是永不结束的崩溃恢复,逐块一致但只读
  • 同步与异步:一致性与写入延迟的直接交易
  • 逻辑复制搬语义:解码 WAL 为行级事件,可挑表、可跨版本、可写
  • DDL 不随逻辑复制走:结构变更要两端同步操作

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U