复制位点与延迟与读写一致性

共 19 题
📑 题目列表 19 题
#
★★★

1. MySQL 中 Seconds_Behind_Master 的局限?

MySQL 中用于衡量主从复制延迟的指标 Seconds_Behind_Master 存在哪些局限?为什么它不能精确反映从库落后主库的真实延迟?

  • Seconds_Behind_Master 的计算方式与原理
  • 该指标在从库空闲、时钟不同步、多线程复制等场景下的失真
  • 更精确的延迟测量手段(如 pt-heartbeat)

Seconds_Behind_Master 是 SHOW SLAVE STATUS 输出的字段,其值由 SQL 线程执行时间戳与 I/O 线程获取的事件时间戳之差计算所得。它存在多个局限:其一,当从库没有事务正在回放时,该值会变为 0,即使从库其实落后主库(只要没有新事件进来,它就无法反映真实差距);其二,它依赖主从两端的系统时钟,若时钟不同步,计算出的值会虚高或虚低;其三,在多线程复制(MTS)下,不同 worker 的进度不一致,该字段只反映一个整体近似值;其四,它只能反映"当前正在执行的事务"的相对时间差,无法给出绝对落后字节数或落后事务数。

Seconds_Behind_Master 本质上是"SQL 线程最近处理的 binlog 事件时间戳与当前系统时间之差",一旦 SQL 线程空闲(追上主库),差值自然归零。因此它更适合作为粗粒度告警,而非精确的延迟度量。要精确测量,常用 pt-heartbeat 在主库周期写入带时间戳的心跳行,从库读取该行计算与本地时间的差值,从而得到不受时钟漂移影响的精确延迟。

SHOW SLAVE STATUS\G;
-- 查看字段 Seconds_Behind_Master
#
★★★

2. PostgreSQL 中 replication lag 的监控,pg_stat_replication?

在 PostgreSQL 中如何通过 pg_stat_replication 视图监控复制延迟?有哪些关键字段?

  • pg_stat_replication 视图的字段含义
  • write_lag、flush_lag、replay_lag 的区分
  • 与 pg_wal_lsn_diff 的配合使用

PostgreSQL 通过 pg_stat_replication 系统视图提供复制状态监控。关键字段包括:client_addr(从库地址)、state(如 streaming、catchup)、sync_state(同步/异步状态)、write_lag(发送位置与从库已写入 WAL 的差距)、flush_lag(发送位置与从库已 flush 的差距)、replay_lag(发送位置与从库已回放的差距)。这三个 lag 分别反映 WAL 在从库写入、刷盘、回放三个阶段的延迟。此外可用 pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) 计算主库当前 WAL 与从库回放位置的差值。

与 MySQL 的 Seconds_Behind_Master 不同,PG 的 replication lag 是基于 WAL 位点(LSN)计算的,不依赖时钟,因此更精确。三个 lag 字段分别对应 WAL 在不同阶段的推进情况,其中 replay_lag 最接近业务可见的延迟。配合 pg_stat_wal_receiverpg_stat_subscription 可全面监控。

SELECT client_addr, state, sync_state,
       write_lag, flush_lag, replay_lag
FROM pg_stat_replication;
#
★★★

3. 主从复制的实现,WAL 归档(PG)、binlog 复制(MySQL)?

主从复制的底层实现机制是什么?PostgreSQL 的 WAL 归档/流复制与 MySQL 的 binlog 复制有何异同?

  • MySQL binlog 复制的 I/O 线程与中继日志
  • PostgreSQL WAL 流复制与归档
  • 两者事件格式与复制原理的差异

MySQL 主从复制基于 binlog:主库将变更写入 binlog,I/O 线程把 binlog 事件拉取到从库的 relay log(中继日志),SQL 线程读取并回放 relay log 中的事件。复制可以是基于语句(statement)、基于行(row)或混合(mixed)。PostgreSQL 采用 WAL 流复制:主库将 WAL(Write-Ahead Log)记录,从库通过流复制协议实时接收并重放;同时可用 archive_mode 开启 WAL 归档,将 WAL 段归档到异地存储作为补充。两者都是"先写日志、再重放"的日志驱动复制,但 PG 的 WAL 是物理日志(记录页面的变更),MySQL 的 row binlog 是逻辑日志(记录行的变更)。

物理日志(PG WAL)重放成本低、字段级差异少,但依赖日志格式版本严格一致;逻辑日志(MySQL row binlog)可跨版本、跨引擎,且方便用于 CDC 和数据同步。理解两者的差异对于选择复制方案和排查复制问题很重要。

#
★★★

4. 复制延迟(Replication Lag)的成因,大事务、长 DDL、网络?

复制延迟(Replication Lag)的主要成因有哪些?大事务、长 DDL、网络等因素如何导致从库回放落后?

  • 大事务与长 DDL 导致的单点回放阻塞
  • 网络带宽与延迟对 binlog/WAL 传输的影响
  • 主库并发写入与从库单线程回放的吞吐差

复制延迟的主要成因包括:其一,大事务(一次更新大量行)在从库需要逐行回放,耗时远超主库应用写入,导致从库阶段性落后;其二,长 DDL(如 ALTER TABLE 重建表)在从库可能阻塞后续事件回放;其三,网络带宽/延迟不足导致 binlog/WAL 传输滞后,尤其在跨地域复制时显著;其四,主库多线程并发写入推送,而从库回放线程(尤其是旧版单线程)吞吐不足,形成回放瓶颈;其五,从库承载了只读查询,与回放线程争抢 CPU/IO。

从根因看,复制延迟本质是"主库写吞吐 > 从库回放吞吐"或"传输吞吐不足"造成的积压。应对手段包括:开启并行复制(MTS)、减少大事务、拆分长 DDL、提升网络带宽、将从库只读负载分流到独立只读实例。诊断时先看 I/O 线程和 SQL 线程状态,判断积压在传输环节还是回放环节。

#
★★★

5. 逻辑复制槽(Replication Slot)的作用与失效风险?

PostgreSQL 中逻辑复制槽(Replication Slot)的作用是什么?它存在哪些失效风险?

  • 复制槽对 WAL 保留的机制
  • 从库长时间离线导致 WAL 堆积
  • 复制槽失效(slot 被删或 WAL 被回收)带来的数据丢失

PostgreSQL 的复制槽(Replication Slot)用于在主库上为某个订阅者保留必要的 WAL 日志,防止 WAL 被提前回收,从而保证从库断开后仍能追平。它分为物理复制槽(用于流复制)和逻辑复制槽(用于逻辑解码/逻辑复制)。失效风险在于:若从库长期离线,主库会持续堆积 WAL 直到磁盘写满,造成数据库故障;若槽被删除或 WAL 因磁盘压力被强制回收,则从库会丢失追平所需日志,只能通过重新全量同步恢复。

复制槽本质是"主库为下游保留日志的承诺",其取舍在"数据安全"与"磁盘空间"之间。运维上要监控 slot 的 pg_current_wal_lsn()retained_lsn 之间的差距,及时告警;对长时间不消费的订阅者,必要时禁用其槽并安排重新同步。MySQL 的同类风险是 binlog 过期策略导致从库无法追平。

#
★★★

6. 半同步复制在从库不可用时的降级(rpl_semi_sync_master_timeout)与数据丢失窗口

MySQL 半同步复制在从库不可用时的降级机制是什么?rpl_semi_sync_master_timeout 的作用与数据丢失窗口如何理解?

  • 半同步复制的基本流程
  • rpl_semi_sync_master_timeout 超时降级为异步
  • 降级期间与极值下的数据丢失窗口

半同步复制要求主库在提交事务前,至少等待一个从库确认收到并落盘(flush)了对应的 binlog,然后才向客户端返回成功。当从库不可用或应答超时,主库会等待 rpl_semi_sync_master_timeout(默认 10000ms)后降级为异步复制继续服务,从而保证主库可用性。这一降级过程留下了数据丢失窗口:在降级发生前,主库可能已提交了事务但未获得从库确认,此时若主库崩溃,这些已提交事务可能未传达到从库而丢失。此外,若主库在"写 binlog 但未传达"之间崩溃,也会丢失。

半同步复制本质是在"可用性"与"数据可靠性"之间做权衡:它在正常情况降低 RPO 到接近零(至少一个从库确认),但在从库故障时通过超时降级保证主库可用。需要清楚半同步并不能保证 100% 零丢失,尤其在降级窗口和主库崩溃瞬间的极端时序下。真正的零丢失需配合组复制(MGR)的多数派确认等机制。

#
★★★

7. GTID 与 binlog 位点(file:pos)在故障恢复上有何本质差异?为什么 GTID 模式能避免找错位点或重复执行?

GTID 与 binlog 位点(file:pos)在故障恢复上有何本质差异?为什么 GTID 模式能避免找错位点或重复执行?

  • 位点(file:pos)复制的精确性与易错性
  • GTID 的全局唯一标识与自动定位
  • 重复执行防护与幂等性

位点(file:pos)复制依赖"从哪个 binlog 文件的哪个 event 位置继续",需要运维手动确认精确位点,一旦找错会导致重复执行或跳过事务,且拓扑变化后位点维护困难。GTID(全局事务标识符)为每个提交事务分配一个全局唯一标识(server_uuid:transaction_id),从库通过 GTID 集合自动判断已执行哪些事务、需要从哪补发,无需手动指定位点。GTID 模式天然具备幂等性:从库会跳过已存在于其 GTID 集合中的事务,避免重复执行,因此在故障切换、从库重挂、拓扑重构时更安全稳定。

位点模式的问题是"状态是相对且易错"的——位点随拓扑、切换而变化,操作失误概率高;GTID 模式把复制状态变成"全局绝对、可自动推导",从库只需维护已执行的事务集合,即可自动对齐。这就是 GTID 在故障恢复中能避免找错位点或重复执行的根本原因。切换后新主通过 GTID 集合并集自动补拉缺失事务。

#
★★★

8. MySQL 并行复制(MTS)如何通过事务依赖分析(writeset)提升从库回放吞吐?相比单线程 SQL 线程延迟降低的原理是什么?

MySQL 并行复制(MTS)如何通过事务依赖分析(writeset)提升从库回放吞吐?相比单线程 SQL 线程延迟降低的原理是什么?

  • 并行复制的两种粒度:按库(database)与按事务(writeset)
  • writeset 基于事务写集合的冲突判断
  • 并行回放减少延迟的原理

MySQL 5.7 的并行复制(MTS)默认可开启按库并行,但按库并行度受库数量限制。8.0 支持基于 writeset 的依赖分析:主库为每个事务记录其写集合(事务修改的行/主键集合),从库根据事务的 writeset 是否相交来判断两个事务能否并行回放——若事务写集合不相交(无冲突),则可在不同 worker 上并发执行;若相交则需串行。相比单线程 SQL 线程,MTS 通过让无冲突事务并发回放,显著提升从库吞吐、降低回放积压,从而降低复制延迟。

单线程回放的瓶颈是"串行执行吞吐上限";并行复制利用写事务之间的无冲突性并行化。writeset 依赖判断比单纯按库更精细,能在一个库里也并行处理无冲突事务。开启方式为 slave_parallel_type=LOGICAL_CLOCKslave_parallel_workers>0。其代价是依赖主库事务分组和写集合,对高冲突负载收益有限。

#
★★

9. 会话亲和性(Session Affinity),同一会话路由同一从库?

什么是会话亲和性(Session Affinity)?为什么读写分离中要保证同一会话路由到同一从库?

  • 会话亲和性的定义
  • 避免同一会话在不同从库间漂移导致读不一致
  • 与连接池、中间件的配合

会话亲和性(Session Affinity,又称粘性会话)指在读写分离或负载均衡场景中,将同一会话(同一客户端连接)的所有请求都路由到同一个后端实例(同一从库),而不是每次请求轮询到不同实例。其目的是避免同一逻辑会话内的多次读操作落在复制进度不同的从库上,从而出现"上一次读到数据、下一次读不到"的不一致观感。会话亲和性通常通过连接池(如基于客户端 IP 或会话 Cookie 的哈希)或代理中间件(如 ProxySQL、MyCat)实现。

复制延迟导致不同从库之间数据进度存在差异,若同一会话的读请求被分散到不同从库,用户可能观察到不一致的结果。会话亲和性把会话固定到单一从库,保证会话内读到一致的进度,是"读最终一致但会话内一致"的常用折中。它无法解决跨会话的延迟问题,但能显著改善用户体验。

#
★★

10. 复制延迟超过业务容忍阈值时的路由降级(读主)与告警设计?

当复制延迟超过业务容忍阈值时,读写分离的路由应如何降级(读主)?告警设计应如何实现?

  • 延迟阈值检测与动态路由
  • 读主降级策略
  • 告警的指标与分级

当从库复制延迟超过业务容忍阈值时,读写分离中间件(如 ProxySQL、ShardingSphere)应将该从库标记为"不健康",停止向其路由读请求,并临时把高危读请求降级到主库(读主)以保证强一致。实现上:代理周期探测从库的复制延迟(如 Seconds_Behind_Master、pt-heartbeat 值、GTID 差),高于阈值就将其移出读路由池;告警设计上,按延迟分级给不同告警(如延迟>1s 提示、>5s 告警、>30s 页面告警),同时记录延迟趋势以辅助定位。降级到主库需注意主库读压力,避免主库被拖垮。

路由降级是"一致性优先"的兜底策略:在延迟超标时宁可牺牲读扩展性读主,也不让业务读到过期数据。告警要可观测、可分级、可追溯,配合自动降级与人工恢复机制。关键是把"延迟阈值"与"业务容忍度"绑定,避免所有读都读主导致主库过载。

#
★★

11. 强制读主(Read Master)的应用,支付、库存强一致?

强制读主(Read Master)适用于哪些场景?支付、库存等强一致场景为什么要强制读主?

  • 强一致读的需求
  • 读主与读从库的取舍
  • 读写分离的一致性盲区

强制读主是指在读写分离架构中,对某些要求强一致性的关键操作(如支付、库存扣减、下单)强制路由到主库读取,以避免读到从库的过期数据。例如支付回查订单状态、库存超卖判断、余额扣减等,若读到延迟的从库数据,可能导致重复支付、超卖等严重业务错误。这类操作通常与写操作同事务或紧接着写,必须读到最新已提交的数据。

异步复制下,从库数据存在短暂滞后,读从库可能读到旧值。强一致读场景必须"读主",保证读到主库最新提交的状态。代价是增加主库读压力,因此通常只对关键路径强制读主,普通查询仍走从库。这本质是"一致性优先于读扩展性"的取舍。

#
★★

12. 读写分离(Read-Write Splitting)的路由策略?

读写分离(Read-Write Splitting)的路由策略有哪些?如何实现读写分离?

  • 读写分离的架构与代理/驱动
  • 多种路由策略(客户端、代理、必读主)
  • 延迟与一致性权衡

读写分离的路由策略包括:其一,按 SQL 类型路由——写操作(INSERT/UPDATE/DELETE)路由到主库,读操作(SELECT)路由到从库;其二,按业务语义路由——关键强一致读强制读主,普通读走从库;其三,按一致性要求路由——允许最终一致的读走从库,需要强一致的读走主库;其四,按事务路由——事务内读写都必须走主库,避免事务内读到不一致数据。实现方式主要有客户端驱动(如 ShardingSphere 的 Sharding-JDBC)、代理中间件(如 ProxySQL、MaxScale)、以及应用层自行封装。

读写分离的核心是把读压力分散到从库、主库只承担写,从而提升整体吞吐。但异步复制下必须处理一致性问题:事务内读主、强一致读主、会话亲和性等策略都是为了规避读到过期数据。路由正确性是基础,读写分离的收益取决于从库数量与读占比。

#
★★

13. 读写分离的延迟应对,等 GTID、读已提交延迟窗口?

读写分离中如何应对复制延迟?等 GTID、延迟窗口等方法如何实现?

  • 等 GTID(wait_for_executed_gtid_set)机制
  • 延迟窗口读
  • 与强一致读的配合

应对复制延迟的常用手段包括:其一,等 GTID——在 MySQL 中,写操作完成后从库通过 WAIT_FOR_EXECUTED_GTID_SET 等待该事务的 GTID 在从库执行完毕,再返回读结果,从而保证"读必读到刚写的数据";其二,延迟窗口读——对时效性要求高的读,设置一个合理的延迟容忍窗口,在窗口内允许读从库,超窗则读主;其三,读主兜底——对强一致关键读直接读主;其四,会话亲和性——把同一会话固定到同一从库。这些策略通常由读写分离中间件封装。

等 GTID 是"读己之写"(read-your-writes)的精确实现,代价是每个强一致读都要等待从库追平,可能增加延迟;延迟窗口是折中,兼顾性能与一致性。选择哪种策略取决于业务对"读到刚写数据"的容忍度。理解这些机制才能设计合适的读写分离一致性方案。

#
★★

14. 半同步复制,after_commit 与 after_sync 的区别?

MySQL 半同步复制中 after_commit 与 after_sync 两种模式的区别是什么?

  • 两种模式的差别
  • after_sync 对数据丢失窗口的改善
  • 与 MySQL 8.0 的默认值

after_commit 模式(旧版默认)的流程是:主库先写 binlog 并提交事务(存储引擎 commit),然后等待从库 ACK,最后才向客户端返回成功。其缺陷是存在一个时序窗口:主库已 commit 但尚未收到从库 ACK 时若崩溃,该事务可能已返回给客户端(或已提交但未同步),从而丢失。after_sync 模式(MySQL 5.7 起为默认)的流程是:主库先写 binlog,等待从库 ACK 之后才提交事务,再向客户端返回成功。这样保证"返回成功"的事务必然已经被至少一个从库确认收到,从而消除主库崩溃时丢失已确认事务的窗口。

两者的核心区别是"提交"与"等待 ACK"的先后顺序。after_commit 在 commit 之后才等 ACK,存在丢失窗口;after_sync 在 commit 之前等 ACK,把数据丢失窗口压缩到最小。因此 after_sync 能提供更接近零丢失的保障,代价是延迟略高(提交晚于 ACK)。这是半同步复制演进的关键改进。

#
★★

15. 复制中断的常见原因与恢复(SQL 线程报错、跳过事务的风险、GTID 模式下的处理)

复制中断的常见原因有哪些?如何恢复?SQL 线程报错、跳过事务的风险、GTID 模式下的处理分别是什么?

  • 复制中断的原因分类
  • SQL 线程报错的常见类型
  • 跳过事务的风险与 GTID 模式的处理

复制中断的常见原因包括:网络中断导致 I/O 线程断开、binlog 已被回收导致位点失效、SQL 线程执行出错(如表中无该行、主键冲突、无权限、存储过程中依赖对象缺失)、GTID 模式下从库事务缺失导致追平失败。恢复时先分别查看 I/O 线程和 SQL 线程状态定位环节。对于 SQL 线程报错,常见做法是分析错误后修正数据再继续;"跳过事务"(如 SET GLOBAL sql_slave_skip_counter=1 或 GTID 模式下注入空事务)有一定风险,因为会跳过整个事务,若该事务对数据有影响会造成主从不一致,只应在确认该事务可安全忽略时使用。GTID 模式下通常用 gtid_executed 集合核对,或注入空事务跳过。

复制中断的恢复原则是"先判断能否安全追平,再决定是否跳过"。跳过事务是危险的,可能造成数据丢失或不一致,必须人工确认。GTID 模式相比位点模式增强了可追溯性,但 GTID 缺失(如主库 binlog 被清理)时只能重新全量同步。稳妥的恢复路径是:定位错误 → 修正 → 继续复制;无法修复时才跳过并补做数据补偿。

#
★★

16. Seconds_Behind_Master 在从库空闲或时钟不同步时为何不准?pt-heartbeat 如何用心跳表实现精确延迟测量?

Seconds_Behind_Master 在从库空闲或时钟不同步时为何不准?pt-heartbeat 如何用心跳表实现精确延迟测量?

  • Seconds_Behind_Master 失真的原因
  • pt-heartbeat 的原理
  • 与时钟无关的精确测量

Seconds_Behind_Master 是通过"SQL 线程当前执行事件的时间戳"与"本地系统时间"之差计算。当从库空闲(没有新事件回放)时,该值归零,即使主库有未同步的积压也无法反映;当主从时钟不同步时,差值会被时钟偏差污染。pt-heartbeat 则通过心跳表实现精确测量:它周期性地在主库执行 UPDATE heartbeat SET ts=NOW(),并在心跳表中记录写入时间戳;从库读取该行并与其本地时间比较,得到从库追平主库的精确延迟。因为心跳表行本身是被复制的,其时间戳记录了主库的写入时刻,从库读取时与本地时间差即真实延迟,且不依赖主从时钟同步(只要测量端时钟准确)。

pt-heartbeat 利用了"复制系统本身在传输心跳行"这一事实,把测量锚点放在被复制数据的来源时间上,从根本上规避了 SQL 线程空闲和时钟漂移的问题。它是最常用的精确复制延迟测量工具,精度可达毫秒级。注意心跳表本身也可能被延迟复制,但其专门用于测量,不受业务负载影响。

#
★★

17. 级联复制(A→B→C)为何会放大延迟?中间节点故障或重启对下游复制位点与数据追平的影响是什么?

级联复制(A→B→C)为何会放大延迟?中间节点故障或重启对下游复制位点与数据追平的影响是什么?

  • 级联复制的拓扑结构
  • 延迟逐级放大的原因
  • 中间节点故障对下游的影响

级联复制(A→B→C,B 同时作为 A 的从库和 C 的主库)中,C 的延迟 = B 接收 A 的延迟 + C 接收 B 的延迟,且每一级都经过一次"接收—写入—再发送"的完整链路,延迟会逐级叠加放大。此外,B 同时承担从库回放和主库发送双重 IO 负载,进一步加大延迟。若中间节点 B 故障或重启,B 的复制位点会中断,C 也因 B 中断而暂停追平;B 恢复后需先从 A 追平,再继续向 C 下发,期间 C 的延迟显著增大。若 B 在重启时丢失了部分已接收但未转发的 binlog,C 可能需要从更早位点重新追平,甚至需要重新切换拓扑。

级联复制降低了对主库 A 的连接压力(B 只需连接 A),但以延迟放大和故障传播为代价。中间节点故障会同时影响下游所有从库,因此级联拓扑适合"拓展开读规模、减轻主库压力"的场景,但对延迟敏感业务需谨慎。实际运维中,可考虑让 C 直接连接 A 或采用多级组网以平衡。

#

18. 主从数据一致性校验(pt-table-checksum 等)如何发现复制漂移并修复?

主从数据一致性校验(pt-table-checksum 等)是如何发现复制漂移并修复的?

  • pt-table-checksum 的原理
  • 校验与修复的流程
  • 复制漂移的检测与修复工具

pt-table-checksum 通过在主库和从库分别计算表的校验和(checksum)并对比,来发现复制漂移。它把表按主键切分块(chunk),对每个 chunk 在主库计算校验和值,复制到从库后同样计算,再比较主从两端的校验和结果,不一致的 chunk 即被标记为漂移位置。执行时用 --replicate 参数把校验结果写到指定表,供对比。发现漂移后,用 pt-table-sync 修复:它对比主从数据,生成差异行的 UPDATE/INSERT/DELETE 语句,在主库执行以纠正从库数据。修复通常在低峰执行,并需注意避免影响在线业务。

校验-修复的核心思路是"用幂等的校验和比对,精确定位差异,再以主库为基准修正从库"。pt-table-checksum 通过 chunk 化避免大表全表锁和长事务,减少对在线影响。注意校验本身也需要从库追平,因此校验前应确认延迟较低。修复方向是主->从,从库以主库数据为准。

#

19. 在从库执行备份(逻辑/物理)的 IO 影响与调度

在从库执行备份(逻辑/物理)的 IO 影响与调度策略是什么?

  • 从库备份的优势
  • 备份对 IO 的影响
  • 备份调度与错峰

在从库执行备份(相比主库)能避免备份对主库的 IO 和读写压力,是常见的备份策略。但备份仍会对从库产生显著 IO 影响:物理备份(如 xtrabackup)会大量读取数据文件,逻辑备份(mysqldump)会扫描表并可能产生临时表波动,都会与从库的复制回放、查询争抢磁盘 IO,可能放大复制延迟。因此备份调度应考虑:在业务低峰执行、错峰(避免与慢查询、批量任务重叠)、限制 IO 速率(如 --throttle)、暂停备份期间的读者告警。备份完成后需校验备份可用性(恢复演练)。

从库备份的取舍是"避免主库压力" vs "加剧从库回放延迟"。通过错峰与限速可以平衡。备份类型的选型同样重要:物理备份快但占空间,逻辑备份可移植但慢。备份的可恢复性校验应纳入日常运维,否则备份可能形同虚设。