19 深入专题:高可用与流复制
流复制冲突、主从切换、脑裂预防与复制延迟诊断。
PG 增大字段长度会锁表吗,影响大吗?
增大字段长度(如 varchar(n) 调大)通常只修改 catalog 元数据,不重写表数据,加的锁级别较低(AccessExclusiveLock 但瞬时),对正常增删改查影响很小,一般很快完成。但如果是某些会重写表/改变物理存储的变更(如改类型、改精度导致重算),则可能锁表并重写数据,影响较大,需区分变更类型。
CTID 物理行号在并发 DML 时的隔离性问题是什么?
CTID 是堆表中行的物理位置(页号+偏移),不是稳定的行标识。并发 UPDATE 会导致行版本移动或产生新 CTID,VACUUM 会回收空间改变 CTID。用 CTID 做行定位(如两次 UPDATE 之间用 CTID 找行)在并发下可能指向错误行或失效,应用应使用主键/唯一键而非 CTID 定位行。
DB吐槽大会为何说 PG 不支持 update/delete skip locked, nowait 语法?
PG 的 SELECT 支持 FOR UPDATE SKIP LOCKED / NOWAIT,但 UPDATE、DELETE 本身长期不支持 SKIP LOCKED / NOWAIT 语法,导致在队列消费等场景下,想跳过已锁定的行只能绕道(如先用 SELECT … FOR UPDATE SKIP LOCKED 选出目标再更新)。这增加了并发消费场景的复杂度,是社区长期吐槽点。
DB吐槽大会为何说 PG 存储过程和函数内自治事务支持不完整?
PG 的 plpgsql 没有原生的自治事务(autonomous transaction),无法在函数/存储过程内部开启独立于外层的事务并独立提交/回滚。相比 Oracle 的自治事务,PG 只能用 dblink、临时表或模拟方式绕过,导致日志表写入、错误处理等场景不够优雅。
DB吐槽大会为何说 pg_stat_statements 缺乏 p99/p95 指标?
pg_stat_statements 只提供平均执行时间、总执行时间、次数等聚合指标,无法得到 p99、p95 等分位数延迟。这导致无法识别长尾慢查询(少数极慢请求拖垮体验),需要借助 pg_stat_statements + 额外采样或 pg_ash、pgpro_stats 等工具补充分位数分析。
Linux ftrace 如何用于 PG 性能分析和火焰图?
ftrace 是 Linux 内核跟踪工具,可记录函数调用和内核事件。对 PG 进程用 ftrace 采集函数级调用栈(配合 perf 等),再用 FlameGraph 脚本生成火焰图,可视化 CPU 热点和调用路径,定位内核态/用户态的性能瓶颈。是排查 PG 高 CPU、锁争用等问题的底层手段。
PG 流复制冲突有哪些分类,lock conflict(vacuum truncate)如何解决?
冲突分几类:lock conflict(vacuum truncate 表尾空页时与查询冲突)、buffer pin conflict、snapshot conflict 等。lock conflict 尤其指 vacuum 想 truncate 掉关系末尾空页,但查询正持有对这些页的 pin,导致回放被阻塞。解决:设置 hot_standby_feedback、调整 max_standby_*_delay 参数、缩短长查询、或临时关闭表的 autovacuum truncate。
PG12 把 recovery.conf 合并进 postgresql.conf 后,如何配置 standby 和恢复目标?
PG12 起不再使用 recovery.conf,standby 和恢复配置直接写进 postgresql.conf。创建 standby 时在数据目录放一个空文件 standby.signal 表示以 standby 模式启动,放 recovery.signal 表示进入恢复(PITR)。恢复目标参数如 restore_command、recovery_target_time、recovery_target_lsn 等也移入 postgresql.conf。recovery_target_action 控制到达还原点后的行为(pause/promote/shutdown)。
PG12 里在 standby 上 drop schema/drop database 为什么变快了,底层做了什么优化?
PG12 针对 standby 删除对象做了优化:主库释放被删对象的 shared buffer 用二分法查找,但从库此前每个对象删除都要遍历整个 shared buffer,非常慢,常导致从库延迟。PG12 把 smgrdounlink 优化为事务内删除多个对象时只扫描一次 shared buffer(smgrdounlinkall),大幅加速 standby 上 drop schema/database 的 WAL 回放。核心是避免对每个待删对象重复遍历整个 buffer pool。
PG13 如何在 standby 节点直接监控主从延迟(latest_end_lsn)?
PG13 在 pg_stat_wal_receiver 视图新增 latest_end_lsn 字段,记录 wal receiver 最近一次接收到的 WAL 结束位置。在 standby 上查询 pg_stat_wal_receiver 的 latest_end_lsn 与 pg_last_wal_replay_lsn()(本地回放位置)的差值,即可在从库侧直接算出复制延迟,无需回主库对比。
PG13 的 max_slot_wal_keep_size 参数是做什么的?
max_slot_wal_keep_size 用于限制复制槽保留 WAL 的上限。当某个复制槽需要的 WAL 超过该上限,PG 会主动 invalidate 该槽,避免 WAL 无限制膨胀撑爆磁盘。它是防止下游长期不消费导致 WAL 堆积的兜底参数,一旦槽被 invalidate 需重建才能继续复制。
PG14 优化了流复制中因 replay lag 导致的 WAL 接收延迟吗?
是。PG14 之前,当 standby 的 startup 进程 replay 落后时,wal receiver 可能被不必要地延迟,导致 WAL 接收也变慢。PG14 修复了因 replay lag 造成的 streaming replication 不必要延迟,让 WAL 接收不再需要等待 startup 进程 replay 结束才继续,提升复制吞吐、降低延迟。
PG14 如何为逻辑复制槽启用 two_phase(两阶段)提交?
PG14 的 pg_create_logical_replication_slot 新增 two_phase 选项(true/false),启用后逻辑解码会输出 PREPARE TRANSACTION / COMMIT PREPARED / ROLLBACK PREPARED 事件,使下游能按 2PC 边界处理事务。适合需要跨资源一致性的 XA/分布式事务复制场景,但会增加解码和订阅端复杂度。
PG14 把 pg_stat_activity 等统计信息从 pgstat 代码拆出有何意义?
PG14 将活跃会话 pg_stat_activity、进程进度条 pg_stat_progress*、等待事件 wait_event 等信息从核心 pgstat 代码中拆出,重构了统计收集架构。这降低了对性能关键路径的影响,使统计子系统更模块化、易维护,为后续增加更多统计视图奠定基础。
PG14 的 ALTER SYSTEM READ ONLY / READ WRITE 是什么?
PG14 支持 ALTER SYSTEM READ ONLY / ALTER SYSTEM READ WRITE 在运行时把整个实例切换为只读 barrier 模式或恢复可写,类似全局只读开关,比逐库设置 default_transaction_read_only 更彻底。适合维护窗口、备份、主从切换期间的全局只读控制,不需要重启。
PG14 的 pg_stat_progress_copy 增强监控什么?
PG14 的 pg_stat_progress_copy 增强,COPY 导入数据支持进度监控,可看到导入了多少行、排除了多少行(where filter 过滤掉的)。这让大文件 COPY 导入时能实时观察进度和过滤情况,便于估算完成时间和发现异常。
PG15 的 READ_REPLICATION_SLOT 流复制协议增强支持了什么?
PG15 增强流复制协议,READ_REPLICATION_SLOT 命令支持 physical slot(此前主要针对逻辑槽),同时 pg_receivewal 支持按 slot 位点拉取 WAL。这让物理复制工具(pg_receivewal)可以基于物理复制槽精确指定从哪个 LSN 开始接收,避免从 0 开始或只依赖 wal_keep_size。
PG15 逻辑复制错误信息增加 errcontext(含 LSN)有什么作用?
PG15 在逻辑复制/订阅的错误信息中增加 errcontext,包含出错的 WAL LSN 和 origin 信息。结合 pg_replication_origin_advance 可以跳过冲突的 WAL 回放,即在订阅端报错时精确知道冲突位置,跳过该 LSN 继续复制,避免一个坏事务卡死整条逻辑复制链路。
PG16 起 standby 支持逻辑复制,带来什么变化?
PG16 之前 standby 无法作为逻辑复制的发布端/订阅端(不能创建逻辑槽、不能应用逻辑变更),只读实例是孤岛。PG16 起 standby 支持逻辑复制,可以在从库上创建逻辑复制槽、作为 publisher 向下游输出逻辑变更,让只读实例也参与 CDC/逻辑复制链路,释放主库压力。
PG17 的 pg_createsubscriber 工具是做什么的?
pg_createsubscriber 用于把物理 standby 转换为逻辑复制订阅者(logical subscriber)。它基于物理从库已复制的数据,通过逻辑复制协议建立订阅关系,避免重新做全量逻辑初始化,是物理复制到逻辑复制平滑切换的工具,常用于大版本升级和零停机迁移场景。
PG17 的 pg_replication_slots.inactive_since 字段是什么?
inactive_since 记录复制槽从什么时候开始变为 inactive(断联)。物理/逻辑槽在下游断开连接后会变为 inactive,inactive_since 记录断联时间戳,用于监控哪些槽已长时间无人消费,辅助判断是否可以清理、评估 WAL 保留风险。
PG17 的逻辑复制槽 failover 和 standby_slot_names 是如何协同工作的?
PG17 支持逻辑复制槽 failover:创建槽时用 pg_create_logical_replication_slot(… failover=true) 标记该槽可随流复制同步到 standby,主从切换后 standby 上已同步的槽可继续被下游订阅。配套参数 standby_slot_names 指定一组 standby slot,主库保证这些 standby 已接收并 flush 所有逻辑槽发送逻辑数据对应的 WAL,从而在 failover 时逻辑槽安全可继续使用。
PG18 的 AIO 增强增加了哪些监控和诊断能力?
PG18 的 AIO(异步 IO)增强增加了监控工具、增强测试能力、清理代码、改进错误诊断。异步 IO 让 PG 的 IO 请求不阻塞进程,监控工具帮助观察 AIO 请求的排队、完成和错误情况,改进的诊断让 IO 问题更易定位。
PG18 的 max_active_replication_origins 参数是做什么的?
PG18 新增 max_active_replication_origins,在订阅端控制可同时跟踪的 replication origins 数量,从而限制可创建的逻辑订阅数量。此前 origins 数量受 max_replication_slots 控制,但订阅端可能不需要 slot(如级联复制)却一定需要 origin,独立参数提供了更灵活的下游配置。默认 10,需预留表同步的余量,设置低于当前数量会导致无法启动。
PG18 的逻辑订阅冲突统计是什么?
PG18 新增逻辑复制冲突统计,收集订阅端应用变更时发生的冲突(如 insert 时主键已存在、update 找不到目标行、delete 无对应行等)。DBA 可通过统计视图观察冲突数量,判断双向复制/异构复制中数据不一致情况,便于调整冲突处理策略。
PG19 如何修复 Standby 晋升时 Slot 同步 Worker 阻塞问题?
原实现用 SIGUSR1 通知 slotsync worker 退出,但 worker 阻塞在 WaitLatch/网络 I/O 时 SIGUSR1 无法保证立即中断,导致晋升被无限期阻塞。PG19 引入专用进程信号 PROCSIG_SLOTSYNC_MESSAGE,通过 HandleSlotSyncMessageInterrupt 设置中断标志、ProcessSlotSyncMessage 执行退出,使 slotsync worker 能从任意等待状态立即脱离,保证晋升在合理时间内完成。
PG19 对 pg_rewind 做了什么优化?
PG19 发了两个 pg_rewind 相关 patch 优化 WAL 拷贝量:一是把 isRelDataFile 重命名并扩展为 getFileContentType,能识别 WAL 文件;二是跳过分歧点之前生成的 WAL 段(要求双方同名段大小一致才跳过),只复制分歧点所在段及之后、以及 source 有而 target 无的段。这大幅降低 rewind 的 I/O 和网络传输,尤其当源库因 wal_keep_size/归档保留了大量历史 WAL 时。
PG19 的 WAIT FOR 优化如何避免 Hot Standby 恢复冲突?
WAIT FOR 用于等待 LSN 回放/刷新/写入。原实现构建返回元组描述符时用 TupleDescInitEntry 会访问 syscache,可能重新建立 catalog snapshot,在 standby 上引发 recovery conflict。PG19 改用 TupleDescInitBuiltinEntry(直接按内置类型 OID 查表,不碰 syscache),彻底消除该路径的 catalog 访问,避免 WAIT FOR 在热备上被取消或报错。
PG19 的 max_repack_replication_slots 参数解决什么问题?
REPACK CONCURRENTLY 底层依赖逻辑解码,执行时必须占用一个 replication slot,此前和逻辑复制订阅共用一个 max_replication_slots 池,容易耗尽报 all replication slots are in use。PG19 新增 max_repack_replication_slots(默认 5,PGC_POSTMASTER 级),在共享内存复制槽数组里逻辑上切出 REPACK 专用段,与普通槽独立计数、独立报错,实现槽资源按用途隔离。
PG19 的 pg_replication_slots.slotsync_skip_reason 是什么?
PG19 在物理 standby 的 pg_replication_slots 视图新增 slotsync_skip_reason 列,记录上一次槽同步被跳过的原因,主要针对 synced=true 的逻辑槽。取值有 wal_or_rows_removed、wal_not_flushed、no_consistent_snapshot、slot_invalidated,同步成功时为 NULL。持续非 NULL(尤其 wal_or_rows_removed、slot_invalidated)需 DBA 介入,否则 standby 提升后逻辑槽可能不可用。
PQTrace 是做什么的?
PQTrace 是 libpq 的协议层跟踪功能,可打印 frontend(客户端)和 backend(服务端)之间的协议交互内容(SQL 发送、结果返回、错误消息等)。用于调试客户端驱动、分析协议行为、定位应用与数据库交互问题。
Patroni 的 ttl/loop_wait/retry_timeout 三者约束关系是什么?
必须满足 loop_wait + 2 * retry_timeout <= ttl,默认 ttl=30、loop_wait=10、retry_timeout=10。loop_wait 决定 HA loop 频率(故障发现速度),retry_timeout 决定 DCS/PG 操作卡住时旧主停止写入的快慢,ttl 是 leader 租约时长。调小加快检测但放大误切,调大抗抖但延长故障窗口,本质在故障发现速度、误切概率、旧主停写窗口间取平衡。
Patroni 的 watchdog 和 failsafe 分别解决什么问题?
watchdog 解决本机不可信问题:Patroni 进程崩溃/OOM/高负载时,靠 OS/硬件设备在无 keepalive 时重置整机,避免 leader key 过期后旧主还继续写。failsafe 解决 DCS 暂时不可达但成员仍互通的窄场景:启用 failsafe_mode 后 primary 向 /failsafe 所有成员发 POST /failsafe,只有全部确认它仍是 primary 才允许继续写,否则 demote。两者都不能替代 DCS 共识。
Patroni 的六层架构和核心 HA 逻辑是什么?
Patroni 是 PG 高可用模板,六层架构:DCS 层(存 leader lock、成员状态、动态配置、同步状态)、HA 状态机(每周期决定 start/promote/demote/follow/rewind/noop)、PG 管理层(启停、写配置、promote/follow)、REST API(健康检查、管理、成员互探)、CLI 层(patronictl)、外部路由(HAProxy/K8s Service)。核心是 leader 是 DCS 中有 TTL 的租约,只有持有 /leader 并按时更新的节点才允许当 primary。
PostgreSQL 主从切换发生脑裂后如何处理与预防?
脑裂即旧主和新主同时接受写入。处理用 pg_rewind 把旧主回退到新主时间线后重新作为 standby。预防手段包括:用 DCS leader lock 作为集群裁判、watchdog(本机不可信时整机重置)、failsafe(DCS 不可达但成员互通的窄场景)、时间线检查,以及用同步复制降低分叉风险。核心目标是确保任意时刻只有一个节点对外承诺写入。
PostgreSQL 的 pg_stat_progress_copy 进度监控是什么?
pg_stat_progress_copy 是 COPY 操作进度监控视图,显示导入/导出的行数、排除的行数(WHERE 过滤掉的)、当前阶段等。PG14 增强支持,让大文件 COPY 导入时能实时观察进度,估算完成时间、发现异常。配合 pg_stat_progress_vacuum、pg_stat_progress_create_index 等构成进度监控体系。
libpq 如何配置连接在多个后端节点之间的读写倾向和 failover?
libpq 连接串支持 target_session_attrs 参数(read-write/read-only/any/prefer-standby 等),配合多 host 列表(host=host1,host2)实现读写倾向与 failover。例如 target_session_attrs=read-write 优先连主库,read-only 连从库。驱动层会依次尝试每个 host 直到找到匹配节点,实现透明的读写分离和故障转移。
pg-ferret 是什么?
pg-ferret 是基于 eBPF 的低 overhead 采样 All-in-one tracing toolkit,用于 PostgreSQL 的全链路追踪。利用 eBPF 在内核态低开销地采集 PG 的调用栈、等待、IO 等,避免传统插桩的性能损耗,适合生产环境做细粒度 tracing 和性能诊断。
pgCluu 是什么监控工具?
pgCluu 是 PostgreSQL 集群利用率(Cluster utilization)监控和审计工具,采集 PG 和系统指标,生成报告展示数据库集群的负载、连接、缓存、锁、vacuum、IO 等利用率情况,帮助 DBA 评估集群健康度和资源使用。
pgSCV 是什么?
pgSCV 是 PostgreSQL 的 metrics exporter(指标导出器),用于把 PG 的运行指标(监控图表、报告、日志、建议、推荐)导出给 Prometheus 等监控系统,类似 node_exporter 之于系统监控。它聚合多个 pg_stat* 视图的指标,提供查询建议和配置推荐,是 PG 监控体系的数据采集端。
pg_auto_failover 1.4 的 quorum based multi-standbys 是什么?
pg_auto_failover 1.4 支持 quorum(仲裁)based 多从库:通过复制仲裁决定哪些从库必须确认才算同步提交,并支持把一个节点从复制 quorum 中移除。它依赖一个 monitor 节点存储集群状态并决策 failover,运行时只依赖 PG(支持 PG10-13)。quorum 机制降低了单个慢副本对同步提交的影响。
pg_upgrade 升级会销毁所有 replication slot 吗?
会。pg_upgrade 在跨大版本升级时会销毁(不保留)所有 replication slots,因为 slot 依赖的 WAL 格式和状态无法跨版本迁移。升级前需记录并在升级后重新创建物理/逻辑复制槽,否则下游复制会中断。
pg_wait_sampling 插件记录什么?
pg_wait_sampling 是等待事件采样统计插件,记录等待事件的次数(calls),但不记录每次等待的时间。它周期性采样各进程的等待事件并聚合计数,可配合 powa 等展示等待事件维度的统计,帮助发现高频等待,但无法区分单次长等待还是多次短等待。
recovery_min_apply_delay 如何防止主从切换后下游时间线错乱?
recovery_min_apply_delay 让 standby 延迟应用 WAL,人为制造回放滞后窗口。这样在主从切换时,如果下游(级联 standby 或逻辑订阅)发现新主回放位置异常,可以靠这段延迟窗口留出纠错时间,避免下游立即跟随到错误时间线。它是一种防时间线错乱的缓冲手段,代价是引入可控的复制延迟。
savepoint 的内存开销和子事务溢出问题是什么?
大量使用 savepoint 会创建子事务,每个子事务消耗 XID 和内存,子事务过多时 PGPROC 缓存(默认最多 64 个)溢出,可见性检查会更多依赖 pg_subtrans 追溯顶层 XID,检查成本上升。PL/pgSQL 的 EXCEPTION 块在循环里隐式制造大量子事务,是常见性能杀手,应避免在一个大事务里创建成千上万个 savepoint。
standby 上的查询冲突有哪些典型来源,如何解决?
典型冲突:vacuum 清理正在回放事务可能要访问的旧版本、truncate 掉查询已 pin 的页、锁冲突、buffer pin 冲突、快照冲突等。解决手段:开启 hot_standby_feedback 让主库知道从库正在读的 xmin(会带来主库膨胀风险)、设置 max_standby_archive_delay/max_standby_streaming_delay 延长回放等待、或缩短长查询。核心是查询快照与回放清理之间的竞争。
为什么 PG 的 multi-master(多主)支持不友好?
PG 内置逻辑复制 pub/sub 对同一张表只能单向复制,双向复制会无限循环打环;且无法很好解决并发写同一行导致的数据冲突(如两边同时 update 同一条记录)。实现 multi-master 需业务自己开发同步工具加事务标记防打环,或用 krahodb、postgrespro postgres_cluster、pglogical 等第三方工具,但会引入复杂度、工具可靠性、复制冲突、全局序列等问题。
为什么会出现大量 idle in transaction 事务,有什么危害?
idle in transaction 是事务已开启(BEGIN 后)但客户端未继续提交/回滚、处于空闲的状态,常见于应用开启事务后长时间等待外部操作(人工审批、远程调用)或连接池泄漏。危害:持有快照和 xmin,阻止 vacuum 清理旧版本导致表膨胀;可能持有锁阻塞其他事务;长期占用连接资源。
为什么会发生死锁?
死锁是多个事务互相等待对方持有的锁形成的循环等待。典型如事务 A 持有行1锁等行2,事务 B 持有行2锁等行1。PG 有死锁检测器,检测到后回滚其中一个事务(报 deadlock detected)。避免死锁的方法:统一加锁顺序、缩短事务、使用 SKIP LOCKED/NOWAIT、减少事务内锁粒度。
同步复制配置变更后,walsender 如何立即释放等待者?
此前修改 synchronous_standby_names(如从 ANY 2 降级 ANY 1)后,已陷入等待的 backend 不会立即释放,要等从库下一条消息触发,甚至需手动 kill。新 commit 让 walsender 在检测到配置重载时立即调用 SyncRepReleaseWaiters(),一旦新配置满足当前已传输 LSN,就即时释放所有符合条件的等待进程,把切换时延从网络随机量变成指令执行常量,消除僵尸等待。
用 pg_basebackup 建异地 standby 的关键步骤和参数是什么?
核心是 pg_basebackup 加 -X stream(流式拉 WAL)、–write-recovery-conf(生成 primary_conninfo)生成 standby 配置,同时配置 primary_conninfo 指向主库,主库 pg_hba.conf 放行 replication。主库需创建物理复制槽(pg_create_physical_replication_slot)保证 WAL 不被清理。之后启动从库即可持续流复制。
逻辑复制槽的 restart_lsn 和 confirmed_flush_lsn 有什么区别?
confirmed_flush_lsn 是消费者已确认接收数据的 LSN(逻辑槽),重启后从此继续;restart_lsn 是消费者可能仍需要的最旧 WAL 位置,用于 WAL 保留边界。因事务按提交顺序发布、且并发事务可能乱序,restart_lsn 可能早于 confirmed_flush_lsn。大型或长时间运行的事务会卡住 restart_lsn 前进导致 WAL 膨胀,所以应尽量避免大事务。
逻辑复制的 row filter(行过滤)是什么,何时引入?
逻辑复制 row filter 允许在发布端只复制满足 WHERE 条件的行,用于选择性复制,减少下游数据量和网络开销。该功能在 PG15 正式引入(此前为 devel preview),配置在 publication 的表级 WITH (WHERE …) 子句上,被过滤掉的行不会发送到 subscriber。
阿里云 RDS PG 的 HA 保护模式(最大保护/最高可用/最大性能)分别是什么?
三种保护模式对应不同同步策略:最大保护(全同步)要求所有同步副本确认才提交,副本故障会阻塞写入,RPO=0;最高可用(半同步)至少一个同步副本确认,副本全挂时自动降级为异步保证可用;最大性能(异步)不等待副本确认,性能最好但可能丢数据。本质是同步复制强度在一致性与可用性之间的权衡。