InnoDB 锁、事务隔离与复制拓扑

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

1. InnoDB 死锁的检测与回滚?

InnoDB 如何检测死锁,检测到后如何回滚?

  • 死锁的产生:两个事务互相等待对方持有的锁
  • 死锁检测机制:等待图(wait-for graph)检测循环等待
  • 回滚策略:牺牲选择回滚代价较小的事务

死锁是多个事务因互相持有对方需要的锁而形成一个循环等待,导致谁都无法继续。InnoDB 通过检测"等待图"(wait-for graph,事务等待关系图)来检测死锁:每当事务等待一个被其他事务持有的锁时,系统检查该等待关系是否形成环,若形成环则发生死锁。检测到死锁后,InnoDB 会选择一个牺牲者(victim)回滚,通常是选择 undo 量最小、回滚代价最小的事务进行回滚,释放其持有的锁,让另一个事务继续执行,并返回错误给被回滚事务(如 ER_LOCK_DEADLOCK)。此外,InnoDB 还有一个锁等待超时机制(innodb_lock_wait_timeout,默认 50 秒)作为兜底:即使未检测到死锁,若一个事务等待锁超过该时间也会被回滚。为避免死锁,应尽量保持一致的加锁顺序、缩短事务时间、合理使用索引缩小锁范围。

死锁是需要"检测 + 回滚"两段机制解决的问题。回答需讲清等待图检测、选择代价最小事务回滚、以及锁等待超时兜底,并简要提及预防策略。

SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';  -- 默认 50 秒
SHOW ENGINE INNODB STATUS\G  -- 查看最近死锁信息
#
★★★

2. InnoDB 自增锁(AUTO-INC Lock)的模式,传统、连续、交叉?

InnoDB 自增锁(AUTO-INC Lock)的三种模式(传统、连续、交叉)是什么,各自特点如何?

  • innodb_autoinc_lock_mode 的三种取值:0(传统)、1(连续)、2(交叉)
  • 不同类型 INSERT 对自增值分配的确定性
  • 并发与自增值可预测性的权衡

InnoDB 通过自增锁(AUTO-INC Lock)来决定自增列(AUTO_INCREMENT)的值分配,其模式由参数 innodb_autoinc_lock_mode 控制,取值为 0、1、2。0(traditional,传统):对每条 INSERT 都加表级自增锁,串行分配自增值,保证语句间自增值连续无间隙,但并发度低。1(consecutive,连续,默认):对"简单 INSERT"(已知插入行数)可直接一次分配一组自增值而无需锁表,对"批量 INSERT(INSERT ... SELECT、LOAD DATA)"等无法预知行数的语句仍加表级锁,以保自增值连续无间隙,兼顾并发与顺序。2(interleaved,交叉):所有 INSERT 都不加表级自增锁,自增值随并发执行交叉分配,并发度最高,但自增值可能不连续、有间隙,且批量插入时可能乱序。取舍在于:并发性能与自增值可预测性(连续性、单调性)之间的权衡。若用到基于自增的复制或需要严格连续,常用 0 或 1;需要高并发可考虑 2。

三种模式对应"锁粒度与自增值可预测性"的权衡。回答需区分三种模式对简单 INSERT 与批量 INSERT 的处理差异,以及模式下自增值是否连续。

SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';  -- 0/1/2
#
★★★

3. InnoDB 行锁的算法,Record Lock、Gap Lock、Next-Key Lock?

InnoDB 行锁的算法有哪些(Record Lock、Gap Lock、Next-Key Lock),它们分别如何工作?

  • Record Lock:单个索引记录的锁
  • Gap Lock:间隙锁,锁住索引记录之间的区间
  • Next-Key Lock:记录锁 + 间隙锁,用于 RR 下防幻读

InnoDB 行锁的加锁算法有三种:Record Lock(记录锁)、Gap Lock(间隙锁)、Next-Key Lock(临键锁)。Record Lock 只锁住索引中的单个记录(单行),是最基本的行锁。Gap Lock 锁住索引记录之间的"间隙"(区间),即索引上两个相邻记录之间的范围,防止其他事务在该间隙中插入新记录,从而防止幻读;间隙锁不锁记录本身,只锁区间。Next-Key Lock 是"记录锁 + 间隙锁"的组合,既锁住记录本身,也锁住该记录之前的间隙,是一个左开右闭区间(前开后闭);在 RR(可重复读)隔离级别下,InnoDB 默认使用 Next-Key Lock 对范围查询加锁,从而防止幻读(阻止其他事务在锁定范围内插入新行)。在 RC(读已提交)下则只使用 Record Lock,不锁间隙,因此 RC 下不会产生 Next-Key Lock。需要强调的是,这些锁都是加在索引上,若没有索引则退化为表锁。

三种锁是递进关系:记录锁锁单行、间隙锁锁区间、Next-Key 锁记录+区间。回答需说明各自的锁定对象、作用(防幻读)以及 RR 与 RC 下的选择差异。

#
★★★

4. InnoDB 锁类型,共享锁(S)、排他锁(X)、意向锁(IS、IX)?

InnoDB 的锁类型有哪些(共享锁 S、排他锁 X、意向锁 IS、IX),它们的兼容性与作用是什么?

  • 共享锁(S)与排他锁(X)的兼容矩阵
  • 意向锁(IS、IX)的存在意义与规则
  • 意向锁与表级锁的配合

InnoDB 采用多粒度锁,锁类型包括:共享锁(S,Shared Lock)、排他锁(X,Exclusive Lock)、意向共享锁(IS,Intention Shared)、意向排他锁(IX,Intention Exclusive)。共享锁(S)允许持锁事务读取一行,其他事务也可加 S 锁读取,但不能加 X 锁修改;排他锁(X)允许持锁事务读写该行,其他事务不能加任何锁。兼容性:S 与 S 兼容,S 与 X 不兼容,X 与任何锁都不兼容。意向锁(IS、IX)是表级锁,表示事务准备在表内的某些行上加 S 或 X 锁,其作用是:当某个事务要加表级锁(如表锁)时,只需要检查表上是否有意向锁,就能判断表内是否有行锁,从而避免逐行检查,提高加锁效率。意向锁之间相互兼容(IS 与 IX 兼容),但意向锁与相应的表级排他锁不兼容。加锁规则:对某行加 S 锁前需先对表加 IS 锁,加 X 锁前需先对表加 IX 锁。

意向锁是"表级意图指示",用于协调表级锁与行级锁,避免加表锁时逐行扫描。回答需给出 S/X/IS/IX 的兼容矩阵与意向锁的作用。

#
★★★

5. InnoDB MVCC 如何通过 undo log 版本链 + Read View 实现多版本读(沿 roll pointer 回溯,按 trx_id 与活跃事务列表比较判定可见性)?

InnoDB MVCC 如何通过 undo log 版本链与 Read View 实现多版本读,其可见性判定逻辑是什么?

  • 版本链:每行通过 roll pointer 串联 undo 版本
  • Read View:记录活跃事务列表与最小/最大事务 id
  • 可见性判定:按 trx_id 与活跃事务比较

MVCC(多版本并发控制)让快照读能读到某一时间点的历史版本,无需加锁。其实现依赖两部分:undo log 版本链和 Read View。每条记录都有一个隐藏的 trx_id(最近修改它的事务 id)和 roll pointer(指向 undo 中该记录的旧版本)。roll pointer 把同一行的多个历史版本串成一条版本链,越往后越旧。Read View 是事务开始快照读时生成的"快照",记录了当前活跃事务的 id 列表、最小活跃事务 id(m_low_limit_id)和将要分配的最大事务 id(m_up_limit_id)。可见性判定时,对版本链上每个版本的事务 id 做比较:若该版本 trx_id 小于最小活跃事务 id(即事务已提交且早于快照),则对该版本可见;若 trx_id 大于最大上限,则不可见;若在最小与最大之间,则判断 trx_id 是否在活跃事务列表中——若在则不可见(该事务未提交),若不在则可见。沿 roll pointer 从新到旧回溯,找到第一个可见版本即为该快照时刻应读取的数据。这样实现的可重复读(RR)下,事务内多次读取结果一致(基于同一快照),且读写不互斥。

核心是"版本链存储历史 + Read View 判定可见性"。可见性判定按 trx_id 与活跃事务列表比较,是 MVCC 的精髓。回答需讲清版本链结构、Read View 三个边界值、判定规则。

#
★★★

6. 当前读(SELECT ... FOR UPDATE/LOCK IN SHARE MODE、UPDATE、DELETE)与快照读在加锁行为上有何区别?RR 下如何用 Next-Key Lock 配合快照读共同防止幻读?

当前读(SELECT ... FOR UPDATE、LOCK IN SHARE MODE、UPDATE、DELETE)与快照读在加锁行为上有何区别?RR 下如何用 Next-Key Lock 配合快照读共同防止幻读?

  • 快照读:不加锁,基于 MVCC 读历史版本
  • 当前读:加锁,读最新版本
  • RR 下快照读靠 MVCC 防幻读,当前读靠 Next-Key Lock 防幻读

快照读(snapshot read)是普通的 SELECT 语句,不加任何锁,基于 MVCC 的 Read View 读取某个时间点的历史版本,因此读写互不阻塞、并发高。当前读(current read)指 SELECT ... FOR UPDATE、SELECT ... LOCK IN SHARE MODE、UPDATE、DELETE 以及 INSERT 等语句,它们必须读取最新版本并加锁(排他锁或共享锁),防止其他事务并发修改。在 RR 隔离级别下防止幻读是两种机制配合的:快照读通过 MVCC 的 Read View,让事务内多次读取看到一致的快照,从而避免快照读看到幻影新行;而当前读(如 UPDATE/DELETE/范围查询 FOR UPDATE)通过 Next-Key Lock(记录锁 + 间隙锁)对扫描范围加锁,阻止其他事务在范围内插入新行,从而避免当前读出现幻读。即:快照读靠 MVCC 版本隔离,当前读靠 Next-Key Lock 间隙锁定,两者共同保证 RR 下不出现幻读。

要区分"快照读不加锁靠 MVCC"与"当前读加锁靠 Next-Key Lock"。RR 下防幻读是"MVCC 对快照读 + Next-Key Lock 对当前读"的双保险。回答需分别说明两种读的加锁行为与防幻读机制。

#
★★★

7. RC 下 UPDATE 遇到被锁定的行为何要读取最新版本(当前读)并重新评估 WHERE(semi-consistent read)?这与 RR 的行为有何不同?

RC 下 UPDATE 遇到被锁定的行时为何要读取最新版本(当前读)并重新评估 WHERE(semi-consistent read)?这与 RR 的行为有何不同?

  • semi-consistent read 的概念与作用
  • RC 下 UPDATE 对已锁定的行读取最新版本重新判断 WHERE
  • 与 RR 下行为的差异(RR 下一般直接等待锁)

semi-consistent read(半一致性读)是 InnoDB 在 RC 隔离级别下的一种优化。当执行 UPDATE 或 DELETE 时,如果某行被其他事务锁定,通常需要等待锁;但 RC 下,InnoDB 会先对该行做一次"当前读"(读取最新已提交版本),然后用最新版本重新评估 WHERE 条件:如果最新版本不满足 WHERE 条件,就无需更新该行,也就不必等待该行锁,直接跳过继续;如果最新版本满足 WHERE,才需要等待锁并更新。这样能避免许多不必要的锁等待,减少 UPDATE 阻塞。这与 RR 隔离级别不同:RR 下由于要保证可重复读和防幻读,会使用 Next-Key Lock,且 UPDATE 遇到被锁定的行一般会直接等待锁释放,不会用 semi-consistent read 去读取最新版本重新评估(因为 RR 不允许读取最新未提交之外的版本/需保持快照一致)。因此 semi-consistent read 是 RC 特有的、降低锁等待的优化。

semi-consistent read 是"以最新已提交版本重估 WHERE 减少锁等待"的 RC 优化。回答需说明其触发场景(UPDATE 遇锁行)与 RC 特有、RR 不用的原因。

#
★★★

8. MySQL 主从复制(Master-Slave)的搭建步骤?

搭建 MySQL 主从复制(Master-Slave)的基本步骤是什么?

  • 主库配置:开启 binlog、设置 server-id、创建复制账号
  • 从库配置:配置 server-id、change master 指定主库位置
  • 启动复制并验证状态

搭建 MySQL 主从复制的基本步骤如下:第一步,配置主库(Master):在 my.cnf 中开启 binlog(log_bin=ON)、设置唯一的 server-id、设置合适的 binlog_format(常为 ROW),重启使配置生效;创建用于复制的账号并授权(如 CREATE USER 'repl'@'%' IDENTIFIED BY '...'; GRANT REPLICATION SLAVE ON . TO ...)。第二步,配置从库(Slave):设置与主库不同的 server-id,并配置相应的 relay log;若从库已有数据,需先做一致性数据初始化(如用 mysqldump 全量备份并导入)。第三步,在从库上执行 CHANGE MASTER TO 指定主库地址、端口、复制账号、binlog 文件与位置(或使用 GTID 模式则指定 master_auto_position=1、gtid_mode=ON),然后 START SLAVE。第四步,通过 SHOW SLAVE STATUS 检查 Slave_IO_Running 与 Slave_SQL_Running 均为 YES,且无错误,验证复制正常。若使用 GTID 复制,则需主从都开启 gtid_mode 并设置 --set-gtid-purged 同步 GTID 集合。

搭建步骤是"主库开 binlog + 建账号 → 从库配置 server-id + 初始化数据 → change master + start slave → 验证状态"。回答需强调 binlog、server-id、复制账号与正确的位置指定。

-- 主库
CREATE USER 'repl'@'%' IDENTIFIED BY 'replpass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
-- 从库
CHANGE MASTER TO MASTER_HOST='master_ip', MASTER_USER='repl', MASTER_PASSWORD='replpass',
  MASTER_LOG_FILE='binlog.000001', MASTER_LOG_POS=154;
START SLAVE;
SHOW SLAVE STATUS\G
#
★★★

9. 主从延迟(Replication Lag)的成因与监控,Seconds_Behind_Master?

主从延迟(Replication Lag)的成因是什么,如何通过 Seconds_Behind_Master 等进行监控?

  • 主从延迟的成因:从库单线程执行慢、大事务、DDL、从库压力大
  • Seconds_Behind_Master 的含义与局限
  • 其他监控手段(GTID 对比、心跳表)

主从延迟指从库应用 binlog 的速度落后于主库产生 binlog 的速度,常见成因包括:主库写入量大而从库单线程(或并行度不足)执行慢;主库执行大事务(长时间不提交的更新)导致从库要一次性重放大量数据;从库执行了耗时 DDL 或慢查询;从库自身硬件性能、IO 能力弱;以及从库有其他并发查询压力。监控手段:最常用的是 SHOW SLAVE STATUS 中的 Seconds_Behind_Master,它表示从库 SQL 线程实际执行时间与主库 IO 线程读取到的 binlog 时间之差,但该值有局限:SQL 线程与 IO 线程重连时可能错误为 0,且它仅反映 SQL 应用进度,多线程复制下可能不准确。更可靠的监控方式是对比主从的 GTID 集合(如 from 主库的 gtid_executed 与从库的 gtid_executed 差集),或使用心跳表(heartbeat)方案(如 pt-heartbeat 定期在主库写入带时间戳的记录,从库读取其时间差)来精确测量延迟。缓解延迟可增大从库并行度(并行复制)、拆分大事务、优化从库 SQL 等。

回答需列出成因,并指出 Seconds_Behind_Master 的语义与局限,再给出更精确的监控手段(GTID 差集、心跳表)。

#
★★★

10. 并行复制(Multi-Threaded Slave)的演进,DATABASE、WRITESET、LOGICAL_CLOCK?

MySQL 并行复制(Multi-Threaded Slave)的演进过程是怎样的,DATABASE、WRITESET、LOGICAL_CLOCK 分别是什么?

  • 并行复制从单线程到多线程的演进
  • slave_parallel_type 的 DATABASE 与 LOGICAL_CLOCK 两种模式
  • WRITESET 依赖追踪(8.0)进一步细分

早期 MySQL 从库是单线程 SQL 应用,主库并发高时从库容易落后,因此引入并行复制(Multi-Threaded Slave,MTS)。其演进分几个阶段:最早的并行复制按数据库(DATABASE)并行,即 slave_parallel_type=DATABASE,不同库的事务可并行执行,但同一库内仍串行,若业务集中在单个库则并行度有限。后来(5.7)引入 LOGICAL_CLOCK 逻辑时钟并行:从库根据主库事务的提交时间(commit sequence)划分并行组,认为提交时间接近的事务无依赖冲突,可并行执行,从而提升单库内的并行度。在此基础上,MySQL 8.0 引入 WRITESET 依赖追踪(binlog_transaction_dependency_tracking=WRITESET),通过事务写入的"写集合"(writeset,即修改的行标识集合)判断两个事务是否真正存在冲突:若写集合无交集则无冲突,可并行执行,进一步细化依赖判断,提高并行度。并行度由 slave_parallel_workers 控制。演进脉络是:DATABASE(粗粒度)→ LOGICAL_CLOCK(按提交时间)→ WRITESET(按写集合精确判断)。

演进是"并行划分粒度从粗到细"的过程。回答需说明 DATABASE 按库、LOGICAL_CLOCK 按提交时间、WRITESET 按写集合冲突,三者并行度依次提升。

SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';  -- 或 DATABASE
SET GLOBAL slave_parallel_workers = 8;
SET GLOBAL binlog_transaction_dependency_tracking = 'WRITESET';  -- 8.0
#
★★★

11. 过滤复制(replicate-do-db、replicate-ignore-db)的应用?

过滤复制(replicate-do-db、replicate-ignore-db)如何应用,有什么注意事项?

  • replicate-do-db / replicate-ignore-db 的作用
  • 基于库与基于表的过滤规则
  • 过滤复制的风险与注意事项

过滤复制允许从库只执行主库 binlog 中匹配特定规则的事务,从而只复制部分库或部分表。常用参数包括:replicate-do-db(只复制指定库)、replicate-ignore-db(忽略指定库)、replicate-do-table(只复制指定表)、replicate-ignore-table(忽略指定表)、replicate-wild-do-table(通配符匹配表)等。应用场景:从库只承载部分业务、做数据归档、多用途从库(如把一个从库只用于某一库的报表)等。注意事项:过滤复制容易造成从库数据不完整,若误配可能丢数据;基于库过滤(do-db)在 ROW 格式下对跨库操作(如 UPDATE db1.t1 JOIN db2.t2)的处理基于当前库判定,可能产生意外结果;GTID 模式下过滤复制与 GTID 执行集合的配合需谨慎,跳过的事务可能造成 GTID 与数据不一致;过滤复制增加维护复杂度,需谨慎使用。因此,非必要不启用过滤复制,必要时用 replicate-do-db 等并充分测试。

过滤复制是"按需复制部分库/表"的机制。回答需列参数、说应用场景,并强调其风险(数据不完整、跨库判定、GTID 配合)与谨慎使用。

[mysqld]
replicate-do-db = appdb
replicate-ignore-db = test
#
★★★

12. 多源复制(Multi-Source Replication)的应用?

多源复制(Multi-Source Replication)是什么,它有哪些应用场景?

  • 多源复制:一个从库从多个主库复制
  • 通过 channel 区分不同复制源
  • 应用场景:数据汇聚、分库分表汇总、多环境合并

多源复制(Multi-Source Replication,MSR)让一个从库同时从多个主库(多个源)复制数据,通过"复制通道(channel)"来区分并管理不同源。这是 MySQL 5.7 引入的能力。每个 channel 独立配置 CHANGE MASTER TO 和独立的 relay log,可独立启停、监控。应用场景:数据汇聚——把多个分库分表(或多个业务库)的数据汇聚到一个从库进行统一分析、报表、备份;多环境合并测试——把多个测试环境的数据合并到一处;以及构建两级复制拓扑(多个叶子主库汇聚到中央从库)。多源复制时需注意各源的库表结构一致性、避免不同源间主键冲突(若都写入同一目标表)、以及通过 channel 分别监控各源延迟。管理上使用 START SLAVE FOR CHANNEL 'ch1'、SHOW SLAVE STATUS FOR CHANNEL 'ch1' 等。

MSR 的核心是"一个从库多通道复制多源"。回答需说明 channel 机制、数据汇聚等应用场景,以及主键冲突等注意事项。

CHANGE MASTER TO MASTER_HOST='m1', ... FOR CHANNEL 'ch1';
CHANGE MASTER TO MASTER_HOST='m2', ... FOR CHANNEL 'ch2';
START SLAVE FOR CHANNEL 'ch1';
START SLAVE FOR CHANNEL 'ch2';
SHOW SLAVE STATUS FOR CHANNEL 'ch1'\G
#
★★★

13. writeset-based 并行复制的依赖追踪?

writeset-based 并行复制的依赖追踪是如何工作的?

  • writeset 记录事务修改的行集合
  • 通过写集合交集判断事务间是否有依赖冲突
  • binlog_transaction_dependency_tracking=WRITESET 的启用

writeset-based 并行复制(WRITESET 依赖追踪)通过分析事务实际修改的行集合(writeset)来判断事务之间是否存在依赖,从而决定能否并行执行。每个事务在提交时,会记录它写入的行标识集合(writeset,即修改的所有行唯一标识)。从库判断两个事务能否并行时,比较它们的 writeset:若两个事务的 writeset 没有交集(没有修改相同的行),则认为它们之间没有数据依赖冲突,可以并行执行;若写入的行有交集,则存在依赖,需串行。这样相比 LOGICAL_CLOCK(按提交时间粗略划分)更精确,能发现"提交时间相连但实际操作无冲突"的事务并让其并行,从而显著提升并行度,尤其适合写热点分散、事务间很少修改相同行的负载。启用方式:MySQL 8.0 中设置 binlog_transaction_dependency_tracking=WRITESET(需 binlog_format=ROW),由主库在 binlog 中记录依赖信息,从库据此并行。注意 writeset 依赖基于"行级"判断,事务内对同一行的多次修改也算冲突。

WRITESET 依赖追踪的核心是"以行集合交集判断冲突"。回答需说明 writeset 的内容、交集判断原则、启用前提(ROW 格式)与并行度提升原理。

SET GLOBAL binlog_format='ROW';
SET GLOBAL binlog_transaction_dependency_tracking='WRITESET';
SET GLOBAL slave_parallel_type='LOGICAL_CLOCK';
SET GLOBAL slave_parallel_workers=8;
#
★★★

14. MySQL 半同步复制的原理与取舍,ack 时机(AFTER_COMMIT/AFTER_SYNC)对数据安全与延迟的影响,退化降级为异步复制的条件如何设置?

MySQL 半同步复制的原理与取舍是什么,ack 时机(AFTER_COMMIT/AFTER_SYNC)如何影响数据安全与延迟,退化降级为异步的条件如何设置?

  • 半同步复制:主库等待至少一个从库 ack 后才返回
  • AFTER_COMMIT 与 AFTER_SYNC 两种 ack 时机
  • 退化降级为异步的条件(rpl_semi_sync_master_timeout)

半同步复制(Semi-Sync Replication)在主库提交事务后,需要等待至少一个从库确认(ack)已收到并记录 binlog 后才向客户端返回成功,从而降低数据丢失窗口(相比异步复制)。ack 时机有两种:AFTER_COMMIT(旧版默认):主库先提交事务,再等待从库 ack,若此间主库故障,事务可能已提交但未 ack,从库可能丢失该事务,仍存在一定丢失窗口;AFTER_SYNC(5.7 默认):主库先写 binlog 并 fsync,然后等待从库 ack,ack 成功后才提交事务,这样主库在提交前已确认从库持有 binlog,即使主库故障,已确认事务也不会丢(从库有该 binlog),数据安全性更高。AFTER_SYNC 更安全但等待 ack 发生在提交前,延迟略高;AFTER_COMMIT 延迟略低但安全性稍弱。取舍在于"数据安全 vs 提交延迟"。退化降级:当事务在等待 ack 超过 rpl_semi_sync_master_timeout(默认 10 秒)仍无从库确认时,主库会临时退化为异步复制,不再等待,保证主库可用性;可通过 rpl_semi_sync_master_enabled / rpl_semi_sync_slave_enabled 控制开启,且需至少一个从库定期确认(rpl_semi_sync_master_wait_for_slave_count 指定需几个从库确认,默认 1)。

半同步的核心是"等待从库 ack 后返回"。理解 AFTER_COMMIT 与 AFTER_SYNC 的时序差异(提交与 ack 先后)是关键,以及超时降级为异步保证可用性。

[mysqld]
plugin-load = "rpl_semi_sync_master.so;rpl_semi_sync_slave.so"
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_master_timeout = 1000        # 毫秒,超时降级异步
rpl_semi_sync_master_wait_point = AFTER_SYNC
#
★★★

15. Percona Xtrabackup 物理备份的原理(拷贝数据文件的同时持续追记 redo 变化,--prepare 阶段前滚 redo 达到一致)是什么?为什么结束阶段仍需短暂加全局锁?

Percona Xtrabackup 物理备份的原理是什么,为什么结束阶段仍需短暂加全局锁?

  • Xtrabackup 拷贝数据文件的同时持续追记 redo 变化(从备份起点 LSN)
  • --prepare 阶段对 redo 前滚(roll-forward)使备份一致
  • 结束阶段短暂加全局锁(FLUSH TABLES WITH READ LOCK)以获取 binlog 位置

Xtrabackup 是 Percona 的物理备份工具,工作原理是:在备份运行期间,它一边拷贝(还原)数据库的数据文件(基于物理页拷贝),一边持续记录(追记)从备份开始点到结束点之间产生的 redo log 变化,保证备份期间的数据变更被完整记录下来。由于备份过程中数据库仍在并发写入,直接拷贝的数据文件处于不一致状态(不同页的 LSN 参差不齐)。因此 --prepare(恢复)阶段会把备份期间追记的 redo log 前滚(roll-forward)应用到拷贝的数据文件上,把数据文件恢复到备份结束点的一致状态,这样备份才能用于恢复。在备份结束阶段,Xtrabackup 需要短暂加全局锁(FLUSH TABLES WITH READ LOCK,FTWRL)以冻结写入,从而获取一个一致的 binlog 位置(binlog 文件名与 position 或 GTID 集合),作为备份点坐标,用于后续 PITR 或搭建从库的衔接。因为 redo log 前滚只保证 InnoDB 数据一致,而 binlog 位置需要在一个短暂无写入的瞬间获取,所以需要短暂加全局锁。

核心是"物理拷贝 + redo 追记 + prepare 前滚"机制,以及"结束阶段 FTWRL 获取一致 binlog 坐标"。回答需讲清为何备份会不一致、prepare 如何解决、为何要短暂加锁。

#
★★★

16. Xtrabackup 增量备份如何基于 --incremental-lsn 只拷贝 LSN 之后变化的页?恢复时如何把多个增量依次合并(apply)到全量?

Xtrabackup 增量备份如何基于 --incremental-lsn 只拷贝 LSN 之后变化的页?恢复时如何把多个增量依次合并到全量?

  • 增量备份基于 LSN(--incremental-lsn)只拷贝大 LSN 变化的页
  • 增量依赖全量或上一增量
  • 恢复时用 --apply-log-only 依次把增量合并到全量

Xtrabackup 增量备份基于 InnoDB 的 LSN(日志序列号)工作:每次备份会记录一个 LSN 起点(全量备份的 LSN 或上一增量的结束 LSN)。执行增量备份时,通过 --incremental-lsn 指定从哪个 LSN 开始,Xtrabackup 只拷贝(还原)LSN 大于该起点的、即自上次备份以来发生变化的页,从而只备份增量变化,大幅减少备份量与时间。增量备份是有依赖的,必须基于上一个全量或增量。恢复时,需要把全量备份和多个增量依次合并(apply)到全量上:先用 --prepare --apply-log-only 对全量备份应用 redo(此模式不进行最终回滚,保留增量背景),然后依次对每个增量备份执行 --apply-log-only 将其合并到全量,最后一个增量应用时去掉 --apply-log-only(或最后执行完整 --prepare 执行回滚),形成与最终一致的全量备份,再用于恢复(--copy-back 或还原到目标)。合并顺序必须与备份顺序一致,且每个增量基于前一个的 LSN。

增量备份是"按 LSN 只拷贝变化页",恢复是"用 apply-log-only 依次把增量前滚合并到全量"。回答需讲清 LSN 机制、增量依赖关系与合并步骤。

# 全量备份
xtrabackup --backup --target-dir=/backup/full
# 增量备份(基于上一全量 LSN)
xtrabackup --backup --target-dir=/backup/inc1 --incremental-basedir=/backup/full
# 恢复:先 apply 全量,再依次 apply 增量
xtrabackup --prepare --apply-log-only --target-dir=/backup/full
xtrabackup --prepare --apply-log-only --target-dir=/backup/full --incremental-dir=/backup/inc1
xtrabackup --prepare --target-dir=/backup/full
#
★★★

17. binlog 闪回工具(binlog2sql、MyFlash)如何从 ROW 格式 binlog 生成反向 SQL(DELETE↔INSERT、UPDATE 前后镜像互换)实现误删恢复?前提条件(binlog_format=ROW、binlog_row_image=FULL)是什么?

binlog 闪回工具(binlog2sql、MyFlash)如何从 ROW 格式 binlog 生成反向 SQL 实现误删恢复,其前提条件是什么?

  • 闪回原理:解析 ROW 格式 binlog,把 DELETE 转 INSERT、UPDATE 前后镜像互换
  • 前提条件:binlog_format=ROW、binlog_row_image=FULL
  • 应用:误删数据恢复、审计

binlog 闪回工具(如 binlog2sql、MyFlash)通过解析 ROW 格式的 binlog 生成"反向 SQL"来还原误删/误改的数据。其原理是:ROW 格式的 binlog 记录了每一行的完整变更(before 镜像和 after 镜像),闪回工具读取这些行级事件,生成逆向操作——把 DELETE 事件转换为对应的 INSERT(把删除的行重新插入),把 INSERT 事件转换为 DELETE(把插入的行删除),把 UPDATE 事件用"前后镜像互换"的方式生成反向 UPDATE(把 after 值改回 before 值),从而撤销原操作。生成的反向 SQL 导入数据库即可恢复误删数据。前缀条件:binlog_format 必须为 ROW(因为只有 ROW 格式才记录行级 before/after 镜像),且 binlog_row_image=FULL(完整记录所有列的前后镜像,而非 minimal 只记录键列与变更列),否则无法还原被修改列的全部原始值。此外还需 binlog 完整保留(有足够时间窗口)。闪回常用于误删数据恢复、数据回滚与审计。

闪回的核心是"ROW 格式的 before/after 镜像 + 逆向 SQL 生成"。回答需说明 DELETE↔INSERT、UPDATE 镜像互换的转换逻辑,以及 ROW + FULL 两个前提。

# binlog2sql 反向解析生成回滚 SQL
python binlog2sql/binlog2sql.py -h127.0.0.1 -P3306 -uuser -ppass -d db -t t   --start-file='binlog.000001' --stop-file='binlog.000002' -B > rollback.sql
#
★★★

18. MySQL PITR 的完整流程(还原全量备份 → 用 mysqlbinlog 按 --stop-datetime/--stop-position 重放到误删前一刻)是怎样的?如何跳过引发故障的事务?

MySQL PITR(时间点恢复)的完整流程是什么,如何跳过引发故障的事务?

  • PITR 流程:还原全量备份 → 用 mysqlbinlog 重放 binlog 到指定时间点/位置
  • --stop-datetime / --stop-position 指定停止点
  • 跳过引发故障的事务(--start-position 跳过、或先重放到故障前再手工处理)

MySQL PITR(Point-In-Time Recovery,时间点恢复)的完整流程是:第一步,先还原最近一次全量备份(恢复数据到备份点状态),并按需恢复该备份之后的增量备份。第二步,用 mysqlbinlog 工具把备份点之后的 binlog 重放(apply)到目标数据库,重放到指定时间点或位置,从而把数据恢复到误删/故障之前的时刻。--stop-datetime 指定停止的时间(如 '2026-08-03 10:00:00'),--stop-position 指定停止的 binlog 位置,两者都用于在误删前停住。跳过引发故障的事务:故障事务通常就是误删/误改的那条语句,恢复时有两种方式——其一,先重放到故障事务之前的一个安全位置(如 --stop-position 指向故障事务之前的 binlog 位置),故障事务本身不执行;其二,解析出引发故障的语句,用 --start-position 从故障事务之后继续重放,或用 --skip 等机制跳过。实际做法是:找到故障事务的 binlog 位置,先重放到该位置前,再手工从故障位置之后继续,或对 binlog 进行过滤去除故障语句。重放完成后,验证数据完整性并恢复业务。

PITR 是"全量还原 + binlog 重放到目标点"。核心是定位停止点(时间或位置)并跳过故障事务,使误删的语句不被重放。回答需给出完整流程与跳过故障的具体手法。

# 重放 binlog 到指定时间点之前
mysqlbinlog --stop-datetime='2026-08-03 10:00:00' binlog.000001 binlog.000002 | mysql -u root -p
# 或指定停止位置
mysqlbinlog --stop-position=123456 binlog.000002 | mysql -u root -p
#
★★

19. mysqldump 的 --source-data/--master-data 与 --set-gtid-purged 如何记录备份点坐标/GTID 集合?它们在搭建从库与增量衔接中的作用是什么?

mysqldump 的 --source-data/--master-data 与 --set-gtid-purged 如何记录备份点坐标或 GTID 集合,它们在搭建从库与增量衔接中的作用是什么?

  • --master-data/--source-data 记录 binlog 文件名与位置(备份点坐标)
  • --set-gtid-purged 记录 GTID 集合
  • 作用:搭建从库时从备份点继续复制、增量衔接

mysqldump 是逻辑备份工具,其相关参数用于记录备份点坐标,便于后续增量衔接。--master-data(MySQL 8.0 中更名为 --source-data,取值 1 或 2)会在 dump 文件中输出 CHANGE MASTER TO 语句,其中包含备份时刻的 binlog 文件名与位置(--master-data=1 直接输出可执行的 CHANGE MASTER TO 语句,=2 则输出为注释),从而记录备份点(备份开始时的 binlog 坐标)。--set-gtid-purged 在 GTID 模式下输出备份时刻的 GTID 集合(SET @@GLOBAL.gtid_purged=...),用于告知导入端该备份已包含哪些事务。作用:搭建从库时,用该备份导入数据后,从库作为从库时可以直接从备份点(binlog 位置或 GTID 集合)继续复制主库后续的 binlog,而无需重新全量同步,实现备份与复制链路的无缝衔接;增量衔接则是指备份点之后的 binlog 可继续用 mysqlbinlog 重放(PITR)。注意 --master-data 需要 FILE 权限(或较新版本),且会获取锁来保证备份点一致。

这两个参数把"逻辑备份"与"复制/增量"衔接起来。--master-data/--source-data 记录 binlog 坐标,--set-gtid-purged 记录 GTID 集合,都是从备份点继续复制或做 PITR 的依据。

mysqldump -u root -p --single-transaction --master-data=2 --all-databases > backup.sql
mysqldump -u root -p --set-gtid-purged=ON --all-databases > backup.sql
#
★★

20. 并行备份恢复工具(mydumper/myloader、mysqlpump)如何按表/按块提升效率?在一致性保证与线程数上有哪些取舍?

并行备份恢复工具(mydumper/myloader、mysqlpump)如何按表/按块提升效率,在一致性保证与线程数上有哪些取舍?

  • mydumper/myloader 按表/按块多线程并行备份与恢复
  • mysqlpump 的并行备份机制
  • 一致性保证与线程数的取舍(线程多速度快但锁与压力大)

mydumper/myloader 和 mysqlpump 是提升备份恢复效率的并行工具。mydumper 会把大表按块(chunk)拆分,多个线程并行导出一张表的不同数据块,或并行导出多张表,从而充分利用多核 IO 提升备份速度;myloader 对应并行导入,多线程并行恢复多张表/多个块。mysqlpump 支持按表、按库并行导出(--parallel-schemas)。一致性保证:mydumper 使用 --single-transaction 开启一致性快照(InnoDB 下基于 MVCC),配合 --lock-all-tables 或 --lock-tables 获取一致性。线程数取舍:线程越多并行度越高、备份越快,但会占用更多数据库连接、增加主库 IO 与锁压力,可能影响线上业务;且多线程并发查询会产生更多临时资源与网络带宽消耗。因此需根据服务器核心数、磁盘 IO 能力与业务负载合理设置线程数(如 4-16),在速度与对线上影响之间权衡。此外,mydumper 的块拆分基于主键范围,大表主键分布不均时块大小可能不均,也需注意。

并行工具的核心是"按表/按块多线程拆分"。回答需说明提升效率的机制(块与表并行)、一致性保证(single-transaction 快照)以及线程数在速度与负载压力间的取舍。

# mydumper 并行备份(-t 线程数)
mydumper -u root -p -B appdb -t 8 -o /backup/dump
# myloader 并行恢复
myloader -u root -p -B appdb -t 8 -d /backup/dump
#
★★

21. 如何验证备份可用性(恢复到沙箱实例、pt-table-checksum 与生产比对、关键表行数与校验和)?

如何验证备份的可用性,比如恢复到沙箱实例、用 pt-table-checksum 与生产比对、比较关键表行数与校验和?

  • 备份可用性验证的重要性
  • 恢复到沙箱实例进行测试
  • 用 pt-table-checksum 或行数/校验和比对

备份不等于可恢复,必须定期验证备份可用性。验证方法主要有:其一,恢复到沙箱实例(测试环境)——把备份还原到一个独立的沙箱实例,启动后检查数据能否正常打开、关键业务数据是否完整、是否能正常查询,这是最直接有效的验证;其二,数据比对——用 pt-table-checksum 工具在生产与恢复到沙箱的实例之间对表做校验和比对,检测数据是否一致;其三,关键表行数与校验和比对——对关键表统计行数(SELECT COUNT(*))并计算校验和(如对某列做 SUM 或 CRC32),与生产库或预期值比对,发现差异。通过定期做这些验证,可确保备份在真正灾难发生时能成功恢复,避免"备份存在但不可用"的隐患。此外还应定期做恢复演练(DR drill),验证恢复流程与时间目标。

备份验证是"备份可用性的最后一道防线"。回答需给出沙箱恢复、pt-table-checksum 比对、行数与校验和比对三种手段,并强调定期验证的重要性。

# 校验和比对(沙箱与生产)
pt-table-checksum --host=192.168.1.10 --user=root --password=xxx --databases=appdb
# 关键表行数与校验和
SELECT COUNT(*), SUM(CRC32(column_a)) FROM appdb.big_table;
#
★★

22. 物理备份有哪些版本兼容性限制(Xtrabackup 版本需匹配 MySQL 版本、不能跨大版本或降级恢复)?

物理备份有哪些版本兼容性限制,如 Xtrabackup 版本需匹配 MySQL 版本、不能跨大版本或降级恢复?

  • Xtrabackup 版本与 MySQL 版本需匹配
  • 物理备份不能跨大版本恢复(如 8.0 数据不能恢复到 5.7)
  • 不能降级恢复

物理备份(如 Xtrabackup)存在严格的版本兼容性限制。其一,Xtrabackup 工具的版本必须与目标 MySQL 版本匹配:Xtrabackup 的备份/恢复逻辑依赖 MySQL 的 redo log、数据字典、页格式等内部结构,版本不匹配时可能无法正确解析 redo 或数据文件,导致备份失败或恢复后数据损坏;因此要用对应 MySQL 大版本的 Xtrabackup(如备份 MySQL 8.0 需用 8.0 系列的 Xtrabackup)。其二,物理备份不能跨大版本恢复:由于数据文件、redo 格式、数据字典等在不同大版本间不兼容,8.0 的物理备份不能恢复到 5.7,反之亦然。其三,不能降级恢复:物理备份的 redo 格式和数据字典版本高于目标版本时无法恢复。跨版本或降级场景通常需要改用逻辑备份(mysqldump)并在新版本上做兼容性处理(如 5.7 数据迁移到 8.0 用 mysqldump 或升级工具)。因此生产环境应保证备份工具版本与数据库版本一致,且建立与目标版本相同的环境进行恢复验证。

物理备份的兼容性限制源于其依赖二进制内部格式(redo、字典、页)。回答需说明工具版本匹配、不能跨大版本、不能降级,以及跨版本时用逻辑备份的替代方案。

#
★★

23. MHA vs Orchestrator 的取舍?

MHA 与 Orchestrator 在 MySQL 高可用方案上的取舍是什么?

  • MHA:脚本驱动、保留原从库、无额外存储
  • Orchestrator:功能强大的拓扑管理、基于 Raft 集群、自动故障转移
  • 取舍:切换时间、自动化程度、运维复杂度、fit 场景

MHA(Master High Availability)和 Orchestrator 都是 MySQL 常用高可用工具,取舍不同。MHA:由 Perl 脚本实现,故障切换时自动检测主库故障、选择数据最完整的新主库、补 binlog 并切换,保留原从库作为新主库的从库;MHA 无需额外存储(不自己存拓扑状态),切换逻辑简单,但切换时间相对较长(通常数十秒),且依赖脚本配置,自动化程度有限,无 Web UI 与集中管理。Orchestrator(GitHub 开源):功能更强大,具有完整的复制拓扑管理与自动发现、可视化 Web UI、自动故障检测与恢复,支持基于 Raft 的集群化部署(orchestrator 自身多节点高可用),切换更快、更智能,能处理更复杂的拓扑(多级、多源)。取舍:对拓扑简单、已有 MHA 运维积累、追求轻量的场景,MHA 更简单;对需要强大拓扑管理、自动故障转移、可视化与集群化、追求高可靠自动化的场景,Orchestrator 更合适。团队维护能力与对切换可控性的要求也是关键考量。

取舍核心是"MHA 轻量简单 vs Orchestrator 强大自动化"。回答需对比两者的切换机制、状态存储、UI 与集群能力,并给出适用场景。

#
★★

24. MHA(Master High Availability)的选主与切换流程?

MHA(Master High Availability)的选主与故障切换流程是怎样的?

  • MHA 故障检测与选主逻辑
  • 选主原则:数据最完整、非延迟最大的从库
  • 切换流程:补 binlog、提升新主、改从库指向

MHA 的故障切换流程:首先,MHA manager 通过监控(如 SSH 或基于 master 的探测)检测主库故障(如 master 无响应、网络中断)。确认故障后,进入选主流程:MHA 从所有从库中选择一个作为新主库,选主原则是数据最完整、还需清理其他从库的过期数据。具体地,MHA 会比较各从库的 binlog 位置(relay log / SQL 执行进度),选出数据最接近主库的从库(即不缺数据或数据最全的),作为候选新主库。然后执行切换:先尽量从故障主库补拉缺失的 binlog(若主库仍可访问)应用到候选从库,使其数据追平;接着提升候选从库为新主库(STOP SLAVE、RESET MASTER 等),并让其他从库重新 CHANGE MASTER 指向新主库。最后把应用/客户端切换到新主库。MHA 的特点是保留原从库拓扑,切换后原从库作为新主库的从库。整个过程通常需要数十秒到分钟级,期间需由应用配合切换写库。

MHA 切换是"检测 → 选数据最全从库 → 补 binlog → 提升新主 → 改从库指向"。回答需讲清选主原则(数据最完整)与切换各步骤。

#
★★

25. Orchestrator(GitHub)的工作原理与拓扑管理?

Orchestrator(GitHub)的工作原理与拓扑管理能力是什么?

  • Orchestrator 自动发现复制拓扑、维护拓扑元数据
  • 基于 Raft 的集群化高可用
  • 故障检测与自动恢复、Web UI

Orchestrator 是一个强大的 MySQL 复制拓扑管理与高可用工具,其工作原理是:通过连接各 MySQL 实例并读取复制相关的状态(如 SHOW SLAVE STATUS、SHOW MASTER STATUS),自动发现并构建完整的复制拓扑图,把拓扑元数据(节点、角色、复制关系)持久化到自己的后端存储(默认是 MySQL,可配置为 SQLite 或 Raft 集群的共享存储)。它提供 Web UI 可视化展示拓扑,支持手动/自动执行主从切换、重排从库、调整复制关系等拓扑管理操作。高可用方面,Orchestrator 可在故障时自动检测主库不可用,并自动执行候选主库选取与切换(failover),支持钩子(hooks)在切换前后触发自定义脚本。Orchestrator 自身基于 Raft 共识实现多节点集群化部署,实现 orchestrator 节点本身的高可用与状态一致性。它适合复杂复制拓扑(多级、多源、级联)的集中管理与自动故障转移。

Orchestrator 的核心是"自动发现并持久化拓扑元数据 + 基于 Raft 的集群高可用 + 自动切换"。回答需说明其拓扑发现、存储、UI 与故障恢复能力。

#
★★

26. ProxySQL 的应用,读写分离、查询路由?

ProxySQL 的应用是什么,它如何实现读写分离与查询路由?

  • ProxySQL 是 MySQL 代理层,位于应用与数据库之间
  • 通过 hostgroup 与规则实现读写分离
  • 查询路由基于规则(规则匹配库表、语句类型)

ProxySQL 是一个高性能的 MySQL 数据库代理(Proxy),位于应用与 MySQL 之间,主要应用包括读写分离、查询路由、连接池、负载均衡、故障转移与查询缓存。读写分离与查询路由是核心应用:ProxySQL 通过 hostgroup(主机组)管理连接——把主库(可写)放在一个 hostgroup、从库(只读)放在另一个 hostgroup。通过 query rules(查询规则),根据 SQL 语句特征(如语句类型、正则匹配、库表、用户)把请求路由:写操作(INSERT/UPDATE/DELETE)路由到主库 hostgroup,读操作(SELECT)路由到从库 hostgroup,实现读写分离;也可按规则把特定查询强制路由到主库(如强一致读),或对特定表做分库路由。此外 ProxySQL 还提供连接复用(连接池)、在线变更配置(无需重启)、后端健康检查与自动摘除故障节点等功能。其配置存储在内部库(如 main、runtime、disk)中,支持动态加载。

ProxySQL 的核心是"hostgroup + query rules 实现读写分离与路由"。回答需说明 hostgroup 分组主从库、查询规则按 SQL 特征路由,以及连接池等附加能力。

-- 主库 hostgroup 10,从库 hostgroup 20
INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (10,'master',3306),(20,'slave1',3306);
-- 写操作路由到主库,读操作路由到从库
INSERT INTO mysql_query_rules (rule_id, match_digest, destination_hostgroup) VALUES (1,'^SELECT',20);
INSERT INTO mysql_query_rules (rule_id, destination_hostgroup) VALUES (2,10);
LOAD MYSQL SERVERS TO RUNTIME; LOAD MYSQL QUERY RULES TO RUNTIME;
#
★★

27. MHA Orchestrator ProxySQL 的协同架构?

MHA、Orchestrator、ProxySQL 如何组成协同架构?

  • 各工具职责:MHA/Orchestrator 做高可用切换,ProxySQL 做路由与故障转移
  • 协同:ProxySQL 感知主库变化自动切换读/写路由
  • 整体架构:ProxySQL 在前,HA 工具在后

MHA、Orchestrator、ProxySQL 可以组合成一个完整的高可用与读写分离架构,各司其职:MHA 或 Orchestrator 负责主从复制的高可用管理与故障切换(检测主库故障、选新主、重排从库),ProxySQL 负责应用与数据库之间的代理层,实现读写分离、查询路由、连接池与负载均衡。协同方式是:ProxySQL 位于应用层和数据库集群之间,应用只连接 ProxySQL;ProxySQL 通过 hostgroup 把主库与从库分组,写请求路由到主库、读请求路由到从库,并对后端节点做健康检查。当主库发生故障时,HA 工具(MHA/Orchestrator)执行故障切换,把某个从库提升为新主库;同时需要让 ProxySQL 感知到主库变化,把写路由(对应主库 hostgroup)切换到新主库。Orchestrator 与 ProxySQL 有较好的集成(可配置在切换后通过脚本/API 通知 ProxySQL 更新后端服务器),而 MHA 与 ProxySQL 可通过自定义脚本在切换后更新 ProxySQL 的 mysql_servers。整体架构即"ProxySQL 做应用接入与路由 + HA 工具做主从高可用切换",两者结合实现读写分离、故障自动转移与高可用。

协同架构是"代理层(ProxySQL)+ 高可用层(MHA/Orchestrator)"的分层组合。核心是切换后要让 ProxySQL 感知新主库并更新路由。回答需说明各工具职责与切换协同机制。

#
★★

28. innodb_buffer_pool_size 的设置原则,物理内存的 50%-80%?

innodb_buffer_pool_size 的设置原则是什么,为什么常说设置为物理内存的 50%-80%?

  • Buffer Pool 是 InnoDB 主要内存占用,决定缓存容量
  • 设置原则:通常为物理内存的 50%-80%
  • 需预留内存给操作系统、连接、其他缓存与线程

innodb_buffer_pool_size 决定 InnoDB Buffer Pool 的大小,是 MySQL 最大的内存占用项,直接影响缓存能力与命中率。设置原则是通常取物理内存的 50%-80%:因为还要为 MySQL 的其他部分(如线程栈、连接缓存、排序缓冲区、临时表、Performance Schema、复制缓冲等)和操作系统(页缓存、内核、进程)预留内存。若 Buffer Pool 过大,会挤占操作系统与其他组件内存,导致系统内存不足、频繁 swap、OOM,反而降低性能;若过小,缓存不足、命中率低、磁盘 IO 增多。因此,对纯数据库服务器(专用内存),常把 50%-80% 的物理内存给 Buffer Pool,具体比例需结合数据量(热点集)、并发连接数、其他缓冲占用与操作系统内存需求动态调整。MySQL 8.0 还可用 innodb_buffer_pool_size 设为热插拔/动态调整(SET GLOBAL),支持在线增大。配置时还应考虑多 instance 分片(innodb_buffer_pool_instances)。

设置原则是"在缓存能力与系统稳定性间平衡"。回答需说明 50%-80% 的原因(预留其他组件与 OS 内存)及过大/过小的后果,并提动态调整与多实例。

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SET GLOBAL innodb_buffer_pool_size = 8589934592;  -- 8GB,8.0 支持动态调整
#
★★

29. innodb_flush_log_at_trx_commit 的语义,0、1、2?

innodb_flush_log_at_trx_commit 的取值为 0、1、2 时分别是什么意思?

  • 控制 redo log 刷盘时机与事务提交的持久性
  • 0:每秒刷盘,最快但可能丢最多
  • 1:每次提交 fsync,最安全

innodb_flush_log_at_trx_commit 控制 redo log 在事务提交时的刷盘策略,取值 0、1、2。0:每次提交时不强制刷盘,由后台线程每秒把 log buffer 刷新到磁盘,崩溃时可能丢失最近 1 秒内已提交但未刷盘的事务,性能最高、持久性最弱。1(默认):每次事务提交都立即把 redo log 刷盘(fsync)到磁盘,保证已提交事务的日志落盘,崩溃时已提交事务不丢失,持久性最强,但每次提交多一次 fsync,性能开销最大。2:每次提交把 redo log 写入操作系统缓存(OS cache),但不立即 fsync,由系统每秒刷到磁盘,崩溃时机(若为 MySQL 崩溃而 OS 未崩)已提交数据不丢,但若 OS 崩溃(断电)可能丢失最近 1 秒数据,性能介于 0 与 1 之间。取舍:对交易型、数据安全要求高的业务用 1(与 sync_binlog=1 配合保证数据安全);对性能敏感、可容忍少量数据丢失的业务可用 2 或 0。注意该值只影响 redo log 刷盘,与 binlog 的 sync_binlog 相互独立。

该参数是"持久性 vs 性能"的权衡。回答需准确区分 0/1/2 的刷盘行为与各自的数据丢失窗口,并提与 sync_binlog 配合。

SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';  -- 默认 1
-- 交易型业务常用 1,性能敏感可设 2
#
★★

30. innodb_log_file_size、innodb_log_files_in_group 的设置?

innodb_log_file_size 与 innodb_log_files_in_group 如何设置,它们对 redo log 容量有什么影响?

  • innodb_log_file_size 单个 redo 文件大小,innodb_log_files_in_group 文件数量
  • redo 总容量 = 文件大小 × 文件数
  • 容量大小影响刷新频率与写入性能

innodb_log_file_size 指定单个 redo log 文件的大小,innodb_log_files_in_group 指定 redo log 文件组中的文件数量,两者乘积决定 redo log 的总容量(redo log 总容量 = innodb_log_file_size × innodb_log_files_in_group)。redo log 容量影响写入性能与刷盘频率:redo log 过小,日志空间容易写满,会频繁触发 checkpoint(强制刷脏以推进 checkpoint 回收日志),导致频繁的磁盘写、增加 IO 压力并降低性能;redo log 过大,则占用的磁盘空间多,且崩溃恢复时重放日志的时间更长。因此设置原则:redo log 总容量应能容纳"高峰期的写量",避免频繁刷脏;一般建议 redo log 总容量设为足够大(如 1GB-4GB 甚至更大,取决于业务写量),并合理分配文件大小与数量。MySQL 8.0.30 之后引入了 innodb_redo_log_capacity 参数统一管理 redo 容量,并支持动态调整(redolog 文件可自动调整)。修改这些参数需重启(或使用 8.0.30+ 的动态容量),且修改前需先关闭实例并清理旧 redo 文件。

核心是"redo 总容量 = 文件大小 × 文件数",容量大小平衡"频繁刷脏"与"恢复时间/磁盘占用"。回答需说明容量对刷缓存与恢复的影响及 8.0.30 后的新参数。

[mysqld]
innodb_log_file_size = 1G
innodb_log_files_in_group = 4
# MySQL 8.0.30+ 可用 innodb_redo_log_capacity=4G 统一管理
#
★★

31. sync_binlog 的语义,0、1、N?

sync_binlog 的取值为 0、1、N 时分别是什么意思?

  • 控制 binlog 刷盘(fsync)频率
  • 0:不主动刷盘,由 OS 决定
  • 1:每次提交 fsync

sync_binlog 控制 binlog 在事务提交时的刷盘(fsync)频率,取值 0、1、N。0:每次提交时不主动把 binlog 刷盘,由操作系统自行决定何时把 binlog 写盘,性能最高,但若 MySQL 或 OS 崩溃,可能丢失最近未刷盘的 binlog,主从可能丢数据。1(默认):每次事务提交都立即把 binlog fsync 到磁盘,保证已提交事务的 binlog 落盘,最安全,但每次提交多一次 fsync,性能开销较大;与 innodb_flush_log_at_trx_commit=1 配合可保证崩溃时数据不丢(redo 与 binlog 都落盘)。N:每 N 次事务提交才刷盘一次 binlog,是折中方案,性能介于 0 与 1 之间,但崩溃时可能丢失最近 N 个提交的 binlog。取舍:对数据安全要求高的业务用 sync_binlog=1(配合 innodb_flush_log_at_trx_commit=1);对性能敏感、可容忍少量丢失的业务可用 N 或 0。注意 sync_binlog 影响的是 binlog(用于复制与 PITR),而 innodb_flush_log_at_trx_commit 影响 redo log,两者独立。

该参数是"binlog 持久性 vs 性能"的权衡。回答需准确区分 0/1/N 的刷盘行为与丢数据窗口,并提与 redo 参数配合。

SHOW VARIABLES LIKE 'sync_binlog';  -- 默认 1
#

32. after_sync 模式下从库确认后主库才提交,主库故障时为何不丢已确认事务?

半同步复制 after_sync 模式下,从库确认后主库才提交,主库故障时为何不丢已确认事务?

  • after_sync 的时序:先写 binlog 并 fsync → 等从库 ack → 再提交
  • 已确认事务的 binlog 已在主库落盘且从库已收到
  • 主库故障时,从库(或新主)持有该事务 binlog,可补回

在 after_sync 模式下,主库事务的执行顺序是:先写 binlog 并 fsync 落盘,然后等待至少一个从库确认(ack)已收到该 binlog,收到 ack 后才在存储引擎层提交事务。因此,"已确认"的事务意味着:主库的 binlog 已经 fsync 落盘(持久化),且至少一个从库已经收到并记录了该 binlog。当主库在此之后故障时,由于该事务的 binlog 已持久化,且从库已持有该 binlog,所以在故障切换时,从库(或选出的新主库)拥有该已确认事务的 binlog,可以把它应用到自身数据(或在新主上重放),从而保证该事务不丢失。也就是说,after_sync 下"确认"时刻事务的 binlog 已经安全存在于主库磁盘和从库上,即使主库提交前崩溃,这个事务也不会因主库故障而丢失。这正是 after_sync 相比 after_commit 更安全的原因——after_commit 是先提交再等 ack,主库在提交后、ack 前故障时,已提交事务可能未及时同步到从库而丢失。

关键在于 after_sync 的时序——"binlog 落盘并等 ack 后才提交",确认时数据已端到端持久化。回答需解释主库故障时从库如何持有该事务以确保不丢。

#

33. MySQL 参数的全局与会话设置?

MySQL 参数如何区分全局(GLOBAL)与会话(SESSION)设置,两者怎样配置?

  • 系统变量的作用域:GLOBAL 与 SESSION
  • 全局与会话变量的设置与查看方式
  • 某些参数仅全局、某些仅会话、动态或需重启

MySQL 的系统变量(system variables)按作用域分为全局(GLOBAL)与会话(SESSION)两类。全局变量影响整个 MySQL 实例(如 innodb_buffer_pool_size、server 级配置),设置后对所有新连接生效;会话变量只影响当前连接(如 sort_buffer_size、autocommit、sql_mode 等),每个连接可独立设置。查看与设置:SHOW GLOBAL VARIABLES / SET GLOBAL 用于全局,SHOW SESSION VARIABLES / SET SESSION 用于会话(SET 默认作用于当前会话)。有些变量是动态变量,可在运行中用 SET 修改(如 SET GLOBAL innodb_buffer_pool_size=...),有些是静态变量,需修改配置文件并重启生效。变量作用域分类:部分变量仅全局有效(如 server_id、innodb_buffer_pool_size),部分仅会话有效(如 character_set_client 之类),部分是全局+会话(既可为全局默认也可按会话覆盖,如 sort_buffer_size、sql_mode)。会话变量在没有单独设置时继承全局默认值。此外还可通过 SET PERSIST 在 8.0 中持久化全局设置到 mysqld-auto.cnf。

需区分 GLOBAL 与 SESSION 作用域、查看与设置语法、动态/静态变量及会话继承全局默认值。回答覆盖这些要点即可。

SHOW GLOBAL VARIABLES LIKE 'sort_buffer_size';
SHOW SESSION VARIABLES LIKE 'sort_buffer_size';
SET GLOBAL sort_buffer_size = 262144;   -- 全局(影响新会话)
SET SESSION sort_buffer_size = 524288;  -- 当前会话
SET PERSIST GLOBAL max_connections = 500;  -- 8.0 持久化