Theory · MySQL · Replication & HA

主从复制与高可用

三线程 × binlog 格式 × 并行回放 × GTID × 异步 / 半同步 / 组复制 —— 复制是 binlog 的下一站

复制原理

主库 dump 线程推送 binlog → 从库 receiver 写 relay log → applier(coordinator + workers)并行回放

延迟与一致性

延迟从哪来、Seconds_Behind_Master 为什么不准、写后读不一致的三种工程解法

三种复制模式

异步(默认)会丢尾部事务;半同步 AFTER_SYNC 基本不丢;MGR 多数派共识自动选主

复制是三大日志 deck 的直接续集:binlog 生成之后如何流向从库、如何回放、如何保一致。这 deck 主线:三线程原理、binlog 格式对复制的影响、并行回放演进、主从延迟的工程治理、GTID、三种复制模式的取舍,最后是丢事务推演和选型。8.0 到 8.4 的版本变更都按官方发布注记核过,特别是依赖追踪变量 8.0.35 弃用、8.4 移除这个升级坑。

Why Replication

为什么要主从:三个理由与常见拓扑

① 读写分离

读多写少是绝大多数业务的形状:主库承担写,多个从库分摊读流量——读能力横向扩展的最低成本方案(代价:延迟带来的不一致,见第 8 页)。

② 备份与灾备

备份在从库做(mysqldump / 快照),不阻塞主库;全量备份 + binlog 可做按时间点恢复 PITR(见 三大日志 deck)。机房级灾备也靠跨机房复制。

③ 高可用

主库故障时提升从库接管(failover)。复制的"追平程度"直接决定 RTO 与 RPO——这也是异步 / 半同步 / MGR 分级的根源(第 13 页推演)。

拓扑形态适用与代价
一主多从1 主 N 从,从库可读可备份最常见;主库 dump 线程随从库数线性增加(级联可缓解)
级联复制主 → 中间从 → 下级从减轻主库推送压力;代价:中间层挂了下游全断、延迟叠加
双主(主主)两主互推,单边写或分片写图省事的高可用;注意自增 id 偏移、写冲突、循环复制(server_id 过滤)
组复制 MGR多节点多数派共识真正的分布式高可用(第 12 页);限制最多,运维要求最高
前置条件三件套:主库开 binlog(log_bin=ON)、全部节点 server_id 唯一、复制账号带 REPLICATION SLAVE 权限。搭建入口(8.0.22+ 新语法):CHANGE REPLICATION SOURCE TO ... SOURCE_AUTO_POSITION=1; START REPLICA;
主从的三个理由按业务语言说:读写分离扩读、从库做备份、故障切换保可用。拓扑表里级联和双主要能说出各自的坑:级联是延迟叠加加单点,双主是自增冲突和循环复制。最后的三件套和两句新语法命令记一下,8.0.22 起 master slave 术语全换成了 source replica,命令跟着改名,答的时候用新术语显得专业。

Core Slide · Three Threads · §19.2.3

复制三线程:dump → receiver → applier

主从复制三线程流程:binlog dump、receiver、applier 主库为每个从库连接开一个 binlog dump(sender)线程,从 binlog 文件读取事件经 TCP 推送;从库 receiver 线程接收并写入 relay log;applier 由 coordinator 读取 relay log 并分发给多个 worker 并行回放到数据文件。 主库 Source(8.0.22 前称 Master) binlog 文件 GTID → QUERY/ROWS → XID 追加写 · 事务提交后产生 见三大日志 deck binlog dump 线程 8.0.22+ 又名 sender 每个从库连接各一个 从 binlog 读事件 → 推送 从库 Replica(8.0.22 前称 Slave) receiver 线程 8.0.22 前称 IO thread 接收事件 → 写 relay log 半同步 ack 发生在这一步 relay log 中转日志 · 落盘 回放后自动清理 applier(回放) 8.0.22 前称 SQL thread coordinator 读 relay log 按依赖分发 worker 并行 worker 1 ┐ worker 2 ├→ 回放 worker …┘ replica_parallel_workers 默认 4(8.0.27+) TCP 推送 events 术语速记:master→source · slave→replica · IO thread→receiver · SQL thread→applier(8.0.22 起改名)· 一推一写一回放:延迟就产生在"推送"与"回放"两段
这是复制 deck 的核心图。主库侧:binlog 文件加 dump 线程,每个从库连接各有一个 dump,从 binlog 读事件通过 TCP 推送。从库侧三步走:receiver 线程收事件写 relay log;relay log 是落盘的中转日志;applier 由 coordinator 读 relay log、按依赖分发给多个 worker 并行回放。半同步的 ack 就发生在 receiver 写完 relay log 这一步,不等回放。底部术语对照要提,8.0.22 起全改名了。

Format Impact · §19.2.1 / §19.2.1.3

binlog 三格式在复制里的真实风险清单

格式复制语义体积 / 回放开销风险
STATEMENT从库重放语句(与主库各自执行一遍)最小;批量操作只记一条不确定语句主从结果可能不同(见下);上下文(时区/字符集/系统变量)差异放大风险
ROW(8.0 默认)从库重放行变更(主库执行的结果直接照搬)最大;binlog_row_image=FULL 默认记全行前后镜像语义最安全;代价是写放大与从库回放逐行开销(并行回放缓解)
MIXED默认 statement,不安全语句自动切 row介于两者折中;"何时切换"由实现判定,边界不透明
statement "陷阱"真实清单(§19.2.1.3)官方判定
NOW() / CURRENT_TIMESTAMP()safe——被特判处理:随语句写入时间上下文,从库重放取同值。网上"NOW() 导致不一致"是流传最广的讹传
RAND() / UUID() / SYSDATE() / USER() 等unsafe——每次执行结果不同,从库重放必然偏差
带 LIMIT 的 UPDATE / DELETE(无确定 ORDER BY)unsafe——命中哪些行取决于执行计划,主从可能选到不同行
INSERT ... SELECT 等混合语句 + 上述函数unsafe;MIXED 模式下自动转 row

版本口径

8.0 默认 binlog_format=ROW;手册 §19.2.1 注明 binlog_format 设置自 8.0.34 起弃用——官方方向是 row-only。RC 隔离级别下只允许 row(见 MVCC deck)。

答题句式:"statement 的风险本质是'从库重跑语句':任何不确定性都会被重放放大。ROW 记录的是主库执行后的既成事实,复制只做搬运——所以默认与趋势都在 ROW。"
格式影响页要先给结论再纠错。结论:row 是默认与趋势,binlog_format 设置本身 8.0.34 起弃用。纠错点最有价值:NOW 和 CURRENT_TIMESTAMP 其实是 safe 的,官方特判处理,网上流传的 NOW 陷阱是讹传;真正 unsafe 的是 RAND、UUID、SYSDATE 这类每次执行结果不同的函数,以及没有确定 ORDER BY 的 LIMIT 更新。能现场纠正这个讹传,是读过手册的直接证据。

Parallel Applier · Evolution & Versions

并行复制演进:从库级到 WRITESET 到默认多线程

版本机制局限 / 说明
≤ 5.5单线程 SQL 线程回放主库并发写入,从库单线程追赶——延迟的结构性根源
5.6库级并行(schema-based,replica_parallel_type=DATABASE不同库的事务可并行;单库热点业务几乎无效
5.7组级并行 LOGICAL_CLOCK:同主库组提交(group commit)的事务并行回放粒度取决于主库组提交规模;依赖主库保持组间不重叠
8.0WRITESET:主库按"行哈希集合"计算事务依赖(binlog_transaction_dependency_tracking=WRITESET),无行冲突即可并行跨库、细粒度;写入集合需开启 transaction_write_set_extraction
8.0.27+默认多线程replica_parallel_workers 默认 0→4,MTA 开箱即用;replica_preserve_commit_order=ON 默认保证提交序0 值自 8.0.30 起弃用;默认机制下多数场景无需再手工调 WRITESET
8.0.35 / 8.4.0依赖追踪变量弃用(8.0.35)→ 移除(8.4.0)升级坑:my.cnf 里残留 binlog_transaction_dependency_tracking=WRITESET 会导致 8.4 无法启动,升级前必须清理配置
为什么需要 preserve_commit_order:多 worker 并行回放时,从库上的提交顺序可能与主库不同——从库读会看到"乱序历史"。默认 ON:并行执行、按主库顺序提交,从库只读一致性有保障(代价是并行度略降)。
并行复制是一条版本演进线:5.5 单线程、5.6 库级、5.7 组级 LOGICAL_CLOCK、8.0 行级 WRITESET、8.0.27 起默认四个 worker。两个必答点:一是 preserve_commit_order 的作用,并行执行但按主库顺序提交,否则从库读会乱序;二是版本坑,依赖追踪变量 8.0.35 弃用、8.4.0 直接移除,带着 WRITESET 配置升级 8.4 会起不来,这是很真实的运维事故素材。

Replication Lag

主从延迟:六个来源与对应的缓解手段

来源机理缓解
① 从库回放单点主库写是并发的,从库回放曾是单线程(或并行度不足)——结构性差距MTA(workers≥4 默认)+ WRITESET 依赖;仍单库热点则有限
② 大事务主库执行 1 小时的事务,binlog 整块传输,从库也要回放近 1 小时,且期间该事务"钉住"回放进度拆小事务;批处理分批提交
③ DDL大表 DDL 无法并行、锁表时间长;statement 格式回放时同样全量执行gh-ost / pt-osc 在线改表、低峰执行
④ 从库自身压力从库承载读流量,CPU/IO 被查询抢占,回放资源不足从库降载、延迟超阈值把从库摘出读池
⑤ 网络跨机房/跨地域 RTT 与带宽不足,推送慢就近部署、压缩协议 replica_compressed_protocol
⑥ 从库规格弱从库机器配置低于主库(省钱后遗症)从库规格对齐主库——最朴素也最常被忽视

观测:SHOW REPLICA STATUS 要看哪几列

Replica_IO_Running / Replica_SQL_Running(两条链路健康)、Seconds_Behind_Master(粗估,见下页)、Retrieved_Gtid_Set vs Executed_Gtid_Set(收到 vs 回放的差值——更可靠的积压度量)。跨库精准监控可用 pt-heartbeat。

心态:延迟是常态,设计要兜住

复制是物理上的异步流水线,延迟不可能为零。正确的做法不是追求消灭延迟,而是:读侧容忍(第 8 页策略)+ 写侧兜底(半同步)+ 监控告警(阈值摘除)。

延迟来源按重要度排:回放单点是结构性瓶颈,大事务和 DDL 是典型人祸,从库压力和网络是环境因素。缓解手段要和来源一一对应地答,显得有体系。观测上强调 Retrieved 与 Executed 两个 GTID 集合的差值比 SBM 可靠。最后的心态话术很重要:延迟不可能为零,工程上做的是容忍、兜底和告警。

Seconds_Behind_Master · Read-Your-Writes

Seconds_Behind_Master 为什么不准,写后读怎么办

SBM 的三大缺陷

① 基于事件时间戳与从库当前时间的差——主从时钟偏差直接污染数值;② 大事务回放期间不更新:一个回放 1 小时的事务,SBM 长期显示接近 0,结束后瞬间跳变;③ IO 断开时显示 0:relay log 被回放追平后 SBM=0,但主库新事务根本没传过来——"假追平"。生产建议 pt-heartbeat 或 GTID 差值。

写后读不一致的经典场景

用户改头像(写主库)→ 立刻刷新页面(读从库)→ 头像还是旧的。写操作到从库回放之间存在秒级窗口,任何"写后立刻读"打到从库都会踩中。

策略做法代价 / 适用
强制读主写后 N 秒内(或按用户/会话标记)的读固定走主库简单可靠;主库读压力回升,窗口期靠拍脑袋
GTID 等待写事务后取 GTID(session_track_gtids=OWN_GTID);读从库前 SELECT WAIT_FOR_EXECUTED_GTID_SET(gtid, timeout) 等该事务回放完成精确的"读到自己的写";超时则回退读主;实现稍复杂
会话粘性同一用户会话固定路由到主库(粘性时间窗)与强制读主同族;中间件层(ProxySQL/ShardingSphere)实现
半同步兜底写等"至少一台从库收到 binlog"再返回只保证不丢,不保证已回放可读——不能单独解决写后读
面试加分:主动区分"不丢"与"可读"两个保证级别——半同步保证不丢(binlog 已到从库),GTID 等待保证可读(事务已回放)。很多候选人在这两者上混淆丢分。
SBM 三大缺陷里最狠的是 IO 断开时的假追平:relay log 回放完了显示零,其实主库新数据根本没传过来。写后读的三种解法要能比较:强制读主最简单,GTID 等待最精确,会话粘性是工程折中。最后的加分句式要背:半同步保证不丢、GTID 等待保证可读,两个保证级别不要混。这题和 Go 后端的一致性话题天然能接上。

GTID · §19.1.3

GTID:全局事务标识与自动定位

-- GTID = source_id : transaction_id
3E11FA47-71CA-11E1-9E33-C80AA9429562:23
└─ server_uuid(实例唯一)┘        └ 序号 ┘

-- 关键集合变量
gtid_executed   已执行的全部 GTID
gtid_purged     已执行但 binlog 已被清掉
Retrieved_Gtid_Set 从库已收到(relay log)
Executed_Gtid_Set  从库已回放

-- gtid_mode 四态灰度
OFF → OFF_PERMISSIVE
    → ON_PERMISSIVE → ON
(前提 enforce_gtid_consistency=ON)
维度file + positionGTID(AUTO_POSITION=1)
定位方式手工记录/计算 binlog 文件名与偏移从库上报 gtid_executed 集合,主库自动发送缺失事务
故障切换提升新主后,各从库要逐个"找位点",找错即丢数据/重复CHANGE REPLICATION SOURCE TO ... AUTO_POSITION=1,自动对齐
幂等性位点回拨会重复执行事务执行过的事务天然不重复(集合判定)
运维成本位点是黑盒,靠脚本管理集合可读可算(集合差 = 积压),迁移/搭建即声明状态
自动定位原理一句话:从库每次握手把 gtid_executed 报给主库,主库对比自己 binlog 中已含的全部 GTID,补发差集——所以切换主库后从库"自愈",不需要任何手工位点。
GTID 先讲格式:server_uuid 冒号序号。核心是三个集合:gtid_executed 全局已执行、Retrieved 已收到、Executed 已回放,集合差就是积压,这也是比 SBM 可靠的监控口径。对比表四行里幂等性最容易被追问:GTID 天然不重复执行,file+pos 位点回拨会重复。自动定位原理一句话收尾:从库报集合、主库补差集。

Async · The Default Mode

异步复制:性能最好,语义是"最终一致"

时序语义

主库提交事务(binlog 落盘)→ 立即返回客户端 OK,不等任何从库;binlog 由 dump 线程异步推送,从库异步回放。主从之间是最终一致:延迟窗口内从库读旧值。

推还是拉?

从库 receiver 主动连接主库发起复制(拉的姿态),主库为该连接起 dump 线程持续推送事件(推的行为)——"从库拉起连接、主库推数据"。主库不关心从库是否收到,这就是异步。

维度表现
性能最优:提交路径零跨网络等待,吞吐不受从库数量影响
数据安全主库宕机可丢尾部事务(客户端已收到 OK、binlog 未送达从库)——第 13 页完整推演
故障切换需要人工/脚本选新主、对齐位点或 GTID;丢多少取决于"追平程度"
适用绝大多数业务:能容忍极小概率尾部丢失、用性能换 SLA;配合"备份 + binlog"兜底恢复
与 2PC 的关系:主库自身的 crash-safe 由 redo 两阶段提交保证(三大日志 deck);但"主库不丢"≠"从库有"——从库视角的一致性由复制模式决定,这就是下面两种模式的出发点。
异步复制抓住两个点:时序上主库提交完立刻返回不等从库;方向上是从库拉起连接、主库推数据。性能最优的代价是主库宕机可能丢尾部事务。最重要的辨析放在右下角:主库 crash-safe 和从库一致性是两个独立保证,2PC 管前者,复制模式管后者——这个分层讲清楚,半同步和 MGR 的出场就顺理成章。

Semisync · AFTER_SYNC vs AFTER_COMMIT · §19.4.10

半同步:等几个 ack、在哪一步等,差别巨大

半同步复制两种等待点对比:AFTER_SYNC 与 AFTER_COMMIT AFTER_SYNC(默认):binlog 落盘后先发送从库并等待 ack(relay log 落盘),再执行 InnoDB commit,崩溃窗口内事务已到达从库不丢失。AFTER_COMMIT:先 commit(其他会话已可见)再等 ack,若此时崩溃切换,事务在主库可见却未到达从库,切换后"消失"。 AFTER_SYNC(默认 · lossless) ① binlog write + fsync 主库日志落盘 ② 发送从库 · 等 ack receiver 写入 relay log 并落盘后 ack ③ InnoDB commit 此时其他会话才可见 ④ 返回客户端 OK 此间崩溃→切换:binlog 已在从库,事务不丢 AFTER_COMMIT(旧行为,可选) ① binlog write + fsync 主库日志落盘 ② InnoDB commit 其他会话此时已能读到该事务 ③ 发送从库 · 等 ack relay log 落盘后 ack ④ 返回客户端 OK 此间崩溃→切换:事务已可见却未到从库 → "消失" ack 条件:receiver 写入 relay log 并落盘(不等待回放)· 参数:rpl_semi_sync_source_wait_point / 旧名 rpl_semi_sync_master_wait_point
半同步两条泳道对比。默认 AFTER_SYNC:binlog 落盘后先发给从库等 ack,然后才 InnoDB commit——commit 前崩溃也没关系,binlog 已经在从库,切换后不丢,所以叫 lossless。可选 AFTER_COMMIT:先 commit 再等 ack,commit 后其他会话就能读到这个事务,此时崩溃切换,事务从未到过从库,切换后在主库"消失"——读过的数据凭空没了。ack 的条件是 relay log 落盘,不是回放完成,这句必须答准。

Semisync · Timeout & Degradation

半同步的工程细节:等待个数、超时退化、性能账

参数(8.0.26+ / 旧名)默认值说明
rpl_semi_sync_source_enabled
(rpl_semi_sync_master_enabled)
OFF总开关;需先安装插件 rpl_semi_sync_source(从库侧 rpl_semi_sync_replica
rpl_semi_sync_source_wait_pointAFTER_SYNC两种等待点(上页);旧名 rpl_semi_sync_master_wait_point
rpl_semi_sync_source_timeout10000 ms超时无 ack → 自动退化为异步(semisync 关闭态),从库追上后自动恢复——"半同步不保证永远半同步"
rpl_semi_sync_source_wait_for_replica_count1等几个从库 ack;设 N 提高不丢概率,也放大提交延迟

退化的含义(必考)

所有从库都慢/断时,主库等到超时(默认 10 秒)后切回异步继续提交——可用性优先。这意味着半同步的"不丢"承诺只在"至少一台从库在线"时成立;监控 Rpl_semi_sync_source_status / Rpl_semi_sync_master_status 判断当前是否处于异步态。

性能账

每事务多一次"发送 + 等 ack"的网络 RTT(外加从库 relay log 落盘时间)。跨机房部署时 RTT 直接加到每个写事务上——半同步从库要就近部署;等待个数从 1 调到 2,延迟再叠加。

答题三层:① ack 条件:relay log 落盘,不等于已回放可读;② 默认等待点 AFTER_SYNC,与 AFTER_COMMIT 的差异在"commit 前还是后等";③ 超时退化让"半同步"只在从库在线时兑现——说完这三层,半同步才算答完整。
半同步细节四参数:开关、等待点、超时、等待个数。最关键的是退化语义:默认十秒等不到 ack 就自动切回异步,从库追上再恢复,所以半同步的不丢承诺是有前提的,从库全挂时它就是异步。性能上每写多一次网络 RTT,跨机房部署时要就近。答题按三层说:ack 条件、等待点差异、超时退化,一层都不能少。

Group Replication · Chapter 20

组复制 MGR:Paxos 多数派,复制模式的"高可用形态"

共识与写入

事务在组内经 XCom(Paxos 变体)达成多数派共识、全局有序后提交:已提交事务必然被多数节点持有——少数节点宕机不丢数据。这是它区别于异步/半同步的根本:不是"等谁收到",而是"多数派说行才算"。

单主模式(默认)

group_replication_single_primary_mode=ON 默认:组内自动选主(primary),其余节点只读,主故障自动选新主;多主模式全员可写,靠 certification(基于 WRITESET 的写集冲突检测)仲裁,冲突方回滚。

要求 / 限制说明
表必须有主键certification 依赖主键计算写集冲突;无主键表无法入组
仅 ROW 格式 binlog + GTID ON写集提取与事务认证的前提
仅 InnoDB依赖事务引擎的隔离与回滚能力
建议 3–9 节点多数派容忍 (N−1)/2 故障:3 节点容忍 1 个;每写多一次组内通信开销
group_replication_consistency控制故障切换后读一致性(BEFORE / AFTER / BEFORE_AND_AFTER 等:等积压回放再放行读写)
与半同步的本质区别(面试高频):半同步保证"至少一台从库收到 binlog",但不保证切换正确——新主是谁、落后多少、能不能补齐都要外面兜;MGR 把选主、事务认证、故障转移全部内置在组内协议里。InnoDB Cluster = MGR + Shell + Router 的官方封装。
MGR 的关键词是多数派:事务经 XCom 即 Paxos 变体达成共识后提交,已提交事务必在多数节点上,所以少数宕机不丢。单主模式是默认,自动选主。限制表里主键和 ROW 格式是 certification 的前提。最后那段与半同步的对比是高频题:半同步只保证不丢、不保证切换正确;MGR 把选主和认证内置进协议。InnoDB Cluster 是官方全家桶封装,提一句即可。

Failover Walkthrough · Comparison

推演:异步切换怎么丢尾部事务;三种模式怎么选

-- 异步复制 + 主库断电,切换到从库

t1 T1 提交 → 主库 binlog 落盘
    → 客户端收到 OK(订单已确认)
t2 T2 提交 → 同上
t3 dump 线程只推到 T1 就断(延迟/断网)
t4 主库断电 → 提升从库为新主
t5 新主没有 T1 尾部之后的事务?
    —— 没有 T2:已确认的提交"消失"

老主恢复后:以新主为基准,GTID 自动补齐
(老主多出的 T2 属于"分叉",被覆盖/回滚)
模式丢失窗口切换适用
异步可能丢尾部事务(客户端已确认)人工/脚本,补齐靠 GTID性能优先、容忍极小概率丢失
半同步
(AFTER_SYNC)
基本不丢(binlog 已到 ≥1 从库);超时退化时回到异步半自动(配合 MHA/Orchestrator 等)金融级妥协方案:要"基本不丢"又要性能
MGR不丢(多数派已持有已提交事务)组内自动选主要求强一致与自动 HA;接受写放大与限制
答题材氪:推演时强调"客户端已收到 OK"这一句——丢的不是普通数据,是承诺过的事务,这就是 RPO 被击穿的时刻;三种模式本质是在 RPO × 性能 × 复杂度上排布。
丢事务推演要讲出戏剧性:客户端已经收到订单确认,主库断电提升从库,这笔事务在新主上不存在——承诺被击穿。老主恢复后以新主为基准补齐,老主多出的事务按分叉处理。选型表三行就是一条 RPO 光谱:异步可丢、半同步基本不丢但退化时回到异步、MGR 多数派不丢,代价依次上升。答题时把"客户端已确认"这五个字说出来,冲击力最强。

Interview QA · 1/2

原理 8 连问

1 · 主从复制的原理?涉及哪些线程?

dumpreceiverapplier

主库为每个从库连接开 dump(sender)线程推送 binlog 事件;从库 receiver(原 IO)线程接收写 relay log;applier(原 SQL 线程,8.0 为 coordinator + workers)读取 relay log 并行回放。核心:一推、一写、一回放。

2 · file+pos 和 GTID 复制有什么区别?

手工位点集合自动定位

file+pos 手工指定 binlog 文件与偏移,切换要逐个找位点、易错;GTID 以 server_uuid:seqno 标识事务,从库上报 gtid_executed,主库自动补发差集(AUTO_POSITION=1),且执行过的事务天然不重复。

3 · NOW() 会导致 statement 复制不一致吗?

safe(特判)真正 unsafe 是谁

不会。手册把 NOW()/CURRENT_TIMESTAMP() 特判为 safe:时间上下文随语句写入 binlog,从库取同值。真正 unsafe 的是 RAND()/UUID()/SYSDATE() 等每次结果不同的函数,以及无确定 ORDER BY 的 LIMIT 更新。

4 · 主从延迟的原因和缓解?

回放单点大事务/DDL从库压力

来源:回放并行度不足、大事务、DDL、从库读负载抢占、网络、从库规格。缓解:默认 MTA(workers=4)+ WRITESET、拆大事务、gh-ost 改表、延迟超阈值摘除从库、从库规格对齐。

5 · Seconds_Behind_Master 为什么不准?

时间戳估算假追平

它是基于事件时间戳的估算:①主从时钟偏差直接污染;②大事务回放期间不更新,结束瞬间跳变;③IO 断开时 relay log 追平即显示 0,真实积压不可见。更可靠:GTID 集合差(Retrieved vs Executed)或 pt-heartbeat。

6 · 写后读不一致怎么解决?

读主GTID 等待会话粘性

①写后 N 秒强制读主;②session_track_gtids=OWN_GTID 拿 GTID,读从库前 WAIT_FOR_EXECUTED_GTID_SET 等回放,超时回退读主;③会话粘性路由。注意半同步只保证"不丢",不保证"已回放可读"。

7 · 并行复制怎么一步步演进?

库级LOGICAL_CLOCKWRITESET默认 MTA

5.6 库级并行(不同库)→ 5.7 LOGICAL_CLOCK 组级(同组提交并行)→ 8.0 WRITESET 行级依赖 → 8.0.27 起 replica_parallel_workers 默认 4,MTA 开箱即用;8.0.35 依赖追踪变量弃用、8.4.0 移除。

8 · replica_preserve_commit_order 是干嘛的?

并行执行按序提交

多 worker 并行回放时提交顺序可能与主库不同,从库只读会看到乱序历史。设为 ON:按主库提交顺序落库(并行执行、顺序提交),从库只读一致性有保障——8.0.27 起默认 ON。

原理八连问。第三题的 NOW 纠错是最亮眼的差异化点,官方口径 safe,别背博客讹传;第五题假追平场景要能举例;第七题演进线要能一口气从 5.6 报到 8.0.27 默认值;第八题把并行执行和顺序提交分开说,一句话点透。

Interview QA · 2/2

进阶 8 连问

9 · AFTER_SYNC 和 AFTER_COMMIT 区别?

commit 前等 vs 后等lossless

AFTER_SYNC(默认):binlog 落盘 → 等从库 ack → InnoDB commit → 返回;崩溃窗口内 binlog 已到从库,切换不丢(lossless)。AFTER_COMMIT:先 commit(其他会话已可见)再等 ack;此时崩溃切换,已可见的事务在从库上"消失"。

10 · 半同步的 ack 到底等什么?

relay log 落盘≠ 已回放

等 receiver 把事件写入 relay log 并落盘即 ack,不等 SQL 回放。所以半同步保证"从库有这笔 binlog(不丢)",不保证"从库已可读到"。要可读需 GTID 等待或应用层校验。

11 · 半同步会不会退化?

超时 10s自动切异步

会。rpl_semi_sync_source_timeout 默认 10000ms:超时无 ack 自动转异步继续提交(可用性优先),从库追上后自动恢复半同步。所以"半同步不丢"的前提是至少一台从库在线;用 Rpl_semi_sync_source_status 监控当前状态。

12 · 异步复制故障切换怎么丢数据?推演一下。

尾部事务客户端已确认

T1、T2 已提交且客户端收到 OK,但 dump 只推到 T1 主库就断电;提升从库为新主 → T2 消失。这是 RPO 被击穿。缓解:半同步(AFTER_SYNC)或 MGR;老主恢复后以新主为基准,GTID 自动补齐/裁剪分叉。

13 · MGR 和半同步的本质区别?

多数派共识内置选主

半同步只保证"≥1 从库收到 binlog",切换正确性靠外部工具兜;MGR 用 XCom(Paxos 变体)多数派共识全局定序,已提交事务必被多数节点持有,主故障组内自动选主、certification 冲突检测。一句话:半同步是"搬运保证",MGR 是"共识保证"。

14 · MGR 为什么强制主键和 ROW 格式?

写集认证

certification 靠提取事务的写集(涉及行的主键集合)判断并发冲突:无主键无法唯一标识行、statement 格式拿不到行级写集——两者都让冲突检测无从做起。因此 MGR 只收 InnoDB + 主键 + ROW + GTID 的负载。

15 · GTID 的 gtid_purged 是什么?

已执行但 binlog 已清理

已执行、但对应 binlog 已被 expire 清掉的那部分 GTID。新从库靠全量备份 + SET GLOBAL gtid_purged 声明"这段历史我有备份、不用 binlog 补",主库从 purged 之后的位点发事务——声明错会导致缺事务或重复报错。

16 · 从 8.0 升级到 8.4,复制上有什么坑?

btdt 移除术语/默认值

①binlog_transaction_dependency_tracking 8.0.35 弃用、8.4.0 移除——配置残留直接无法启动(WRITESET 用户升级前必须清理);②术语与参数以 source/replica 命名为准;③8.4 同时翻转了一批 InnoDB 默认值(如 change_buffering=none),从库与主库参数要一起看齐,避免主从行为差异。

进阶组的重心在第 9 到 13 题的一致性链条:等待点语义、ack 条件、超时退化、丢事务推演、MGR 共识,五题连起来就是完整的"不丢数据"论证链。第 15 题 gtid_purged 是稀缺细节,能说清新从库搭建时声明历史的作用。第 16 题版本坑贴运维实战,8.4 移除依赖追踪变量是最典型的事故源。

Related Decks

相关知识点

MySQL 领域 · 交叉链接

三大日志与 crash-safe —— binlog 的生成与组提交(复制的内容从哪来)
事务基础 —— 隔离级别与复制语义的边界
LRU 缓存(手撕实现) —— 哈希 + 双链表的 O(1) 结构与手撕
MVCC —— RC 仅 row binlog 的隔离级联动
InnoDB 锁体系 —— 从库回放的事务冲突与主库写入同源

答题串联 · 一图流

数据流 = dump 推 → receiver 写 relay log → applier 并行回放
定位 = file+pos(手工)vs GTID(集合自动补差)
一致 = 不丢(半同步)× 可读(GTID 等待)两层保证
模式 = 异步(可丢)→ 半同步(退化风险)→ MGR(多数派)
版本 = 8.0.22 术语改名 · 8.0.27 默认 MTA · 8.0.35 弃用 / 8.4 移除

收尾第一页给出交叉链接与答题串联:数据流、定位、一致性、模式、版本五条线。参考出处单独放下一页。

References

参考来源

本 deck 全部版本敏感结论可溯源至下列一手材料——复习时回到手册原文,别背二手结论。

dev.mysql.com/doc/refman/8.0/en/replication-threads.html§19.2.3 Replication Threads:dump/sender、receiver、applier(coordinator+workers)与术语改名
dev.mysql.com/doc/refman/8.0/en/replication-formats.html§19.2.1 Replication Formats:默认 ROW、MIXED 自动切换、binlog_format 8.0.34 弃用
dev.mysql.com/doc/refman/8.0/en/replication-rbr-safe-unsafe.html§19.2.1.3:safe/unsafe 判定——NOW() 特判 safe;RAND/UUID/LIMIT 为 unsafe
dev.mysql.com/doc/refman/8.0/en/replication-semisync.html§19.4.10:默认 AFTER_SYNC、ack=relay log 落盘、AFTER_COMMIT 对比、超时降级
dev.mysql.com/doc/refman/8.0/en/replication-gtids-concepts.html§19.1.3.1 GTID Format and Storage:uuid:seqno、gtid_executed/purged、自动定位
dev.mysql.com/doc/refman/8.0/en/group-replication.html 及 Chapter 20Group Replication:XCom(Paxos)、single-primary 默认、certification、一致性保证
dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-27.html · news-8-0-35.html · /8.4/en/news-8-4-0.html8.0.27 workers 默认 4;8.0.35 btdt 弃用;8.4.0 btdt 移除
所有版本敏感结论都有出处:三线程与术语出自 19.2.3,格式与安全语句出自 19.2.1 和 19.2.1.3,半同步语义出自 19.4.10,GTID 出自 19.1.3,MGR 出自第 20 章,三个版本变更点出自对应发布注记。