MySQL面试五题深度解析——备份恢复、高可用与架构设计
作者:没有四次元口袋的蓝胖
日期:2026-06-13
标签:Java, MySQL, 备份恢复, 高可用, 读写分离
题目21:MySQL备份方式有哪些?各有什么优缺点?
21.1 备份方式分类全景
MySQL备份分类 ├── 按备份内容 │ ├── 逻辑备份 → 导出SQL语句(mysqldump) │ ├── 物理备份 → 拷贝数据文件(xtrabackup) │ └── 快照备份 → 文件系统快照(LVM/ZFS) ├── 按是否停机 │ ├── 冷备 → 停库备份 │ ├── 温备 → 不停库但加读锁 │ └── 热备 → 不停库不影响业务 ├── 按数据范围 │ ├── 全量备份 → 所有数据 │ ├── 增量备份 → 自上次备份后的变更 │ └── 差异备份 → 自上次全备后的变更 └── 按备份位置 ├── 本地备份 └── 异地备份(灾备)21.2 逻辑备份 vs 物理备份
| 对比项 | 逻辑备份(mysqldump) | 物理备份(xtrabackup) |
|---|---|---|
| 备份内容 | SQL语句文本 | 数据文件(.ibd等) |
| 备份速度 | 慢(要生成SQL) | 快(直接拷文件) |
| 恢复速度 | 慢(要执行SQL) | 快(直接复制文件) |
| 文件大小 | 小(压缩的文本) | 大(原始数据文件) |
| 跨版本/平台 | ✅ 可以 | ❌ 可能不兼容 |
| 粒度 | 可选库/表 | 只能整库 |
| 一致性 | 靠MVCC | 靠redo log |
面试回答:“逻辑备份导出SQL文本,跨版本兼容但慢,适合小库;物理备份拷数据文件,快但不跨版本,适合大库。生产环境两者配合用。”
21.3 冷备 / 温备 / 热备
| 方式 | 业务影响 | 一致性 | 适用场景 |
|---|---|---|---|
| 冷备 | 停库,业务不可用 | ✅ 最好 | 可以接受停机的小业务 |
| 温备 | 只读,不能写 | ✅ 好 | 维护窗口期 |
| 热备 | 完全不影响 | ⚠️ 需要技术保证 | 7×24在线业务 |
生产环境99%用热备——停库是不可接受的。InnoDB热备靠MVCC,MyISAM热备需要FTWRL(全局读锁)。
21.4 常用备份工具详解
mysqldump——最常用的逻辑备份
MySQL自带,导出纯SQL文本。
# 基础全量备份mysqldump-uroot-pdbname>dbname.sql# 备份所有库mysqldump-uroot-p--all-databases>all_db.sql# 只备份某些表mysqldump-uroot-pdbname table1 table2>tables.sql# InnoDB一致性热备(最常用)mysqldump-uroot-p\--single-transaction\# InnoDB一致性快照--master-data=2\# 记录binlog位置--routines\# 存储过程和函数--triggers\# 触发器--events\# 事件dbname>backup.sql# 恢复mysql-uroot-pdbname<backup.sqlmysqldump的坑:
# ❌ 默认会锁MyISAM表,大表锁很久mysqldump-uroot-pdbname>backup.sql# ✅ InnoDB表用--single-transaction不锁表# 但MyISAM表还是会锁!如果库里有MyISAM表,要额外加--lock-tables=falsemysqldump-uroot-p--single-transaction dbname>backup.sql面试追问:“mysqldump备份100GB的库要多久?”
→ 取决于服务器性能和数据特点,通常几十分钟到几小时。大库不推荐用mysqldump,用xtrabackup更快。
xtrabackup——生产环境首选
Percona开源的物理备份工具,InnoDB热备不锁表。
# 全量备份xtrabackup--user=root--password=xxx\--backup--target-dir=/backup/full/# 增量备份(基于全备)xtrabackup--user=root--password=xxx\--backup--target-dir=/backup/inc1/\--incremental-basedir=/backup/full/# 第二次增量(基于上一次增量)xtrabackup--user=root--password=xxx\--backup--target-dir=/backup/inc2/\--incremental-basedir=/backup/inc1/# 恢复步骤(重要!)# 步骤1:prepare全备(应用redo log,使数据文件一致)xtrabackup--prepare--target-dir=/backup/full/# 步骤2:如果有增量,合并增量到全备xtrabackup--prepare--target-dir=/backup/full/\--incremental-dir=/backup/inc1/# 步骤3:恢复(要先停MySQL,清空数据目录)systemctl stop mysql xtrabackup --copy-back --target-dir=/backup/full/chown-Rmysql:mysql /var/lib/mysql systemctl start mysqlxtrabackup为什么能热备?
→ 备份期间持续监控redo log的变化,记录备份开始后的所有修改。备份完成后,用redo log把拷贝的数据文件"追"到一致性状态。本质就是利用了redo log的WAL机制。
prepare阶段为什么必须?
→ 拷贝的数据文件可能处于不一致状态(备份过程中数据在变)。prepare阶段应用redo log,把数据文件恢复到某个一致的时间点。没有prepare的备份不能直接用!
LVM快照备份
# 1. 加读锁(保证一致性)mysql-e"FLUSH TABLES WITH READ LOCK; SYSTEM sync;"# 2. 创建LVM快照(瞬间完成)lvcreate-L10G-s-nmysql_snap /dev/vg/mysql_lv# 3. 释放读锁mysql-e"UNLOCK TABLES;"# 4. 挂载快照,拷贝数据mount/dev/vg/mysql_snap /mnt/snapcp-r/mnt/snap/data/ /backup/# 5. 删除快照umount/mnt/snap lvremove /dev/vg/mysql_snap优点:快照创建瞬间完成,业务影响极小。
缺点:需要LVM支持,快照占用存储,拷贝数据仍需时间。
主从备份——最推荐的备份方式
在从库上做备份,主库完全不受影响。
# 从库上执行备份,主库无感知# 可以停从库SQL线程做一致性备份mysql-e"STOP SLAVE SQL_THREAD;"xtrabackup--backup--target-dir=/backup/ mysql-e"START SLAVE SQL_THREAD;"21.5 生产备份策略
备份策略:全量 + 增量 + binlog 周日 02:00 全量备份(xtrabackup full) 周一~周六 02:00 增量备份(xtrabackup incremental) 实时 binlog同步到备份服务器 保留策略: 全备保留4周 增量保留1周 binlog保留7天关键原则:
- 备份要验证——定期做恢复演练,没验证过的备份等于没备份
- 备份要异地——防止机房级故障
- 备份要加密——防止数据泄露
- 备份要监控——备份失败要告警
面试追问:“如何验证备份是否可用?”
→ 定期(至少每月)在测试环境恢复一次,验证数据完整性和恢复耗时。自动化恢复测试脚本是个好实践。
题目22:mysqldump的–single-transaction原理是什么?
22.1 一致性备份的核心问题
备份为什么要保证一致性?
假设user表有id=1,2,3三行: 没有一致性保证: T1: 备份id=1(age=20) T2: 其他事务把id=1的age改成25,把id=3删除,插入id=4 T3: 备份id=2(age=30) T4: 备份id=4(age=40) -- id=3被删了,没备份到 结果:备份出来的数据 id=1的age=20(旧值),id=4存在但id=3不存在 → 数据是"混合时间点"的,不一致!一致性备份要保证:备份出来的所有数据是同一个时间点的快照。
22.2 --single-transaction的执行流程
-- mysqldump加了--single-transaction后,实际执行的SQL:SETSESSIONTRANSACTIONISOLATIONLEVELREPEATABLEREAD;-- 设置隔离级别为RRSTARTTRANSACTIONWITHCONSISTENTSNAPSHOT;-- 开启事务,并立即创建一致性快照-- 这就是MVCC的Read View!所有数据以这个时间点为准-- 然后逐表读取数据...SELECT*FROMtable1;SELECT*FROMtable2;...-- 备份完成,事务自动结束核心原理:START TRANSACTION WITH CONSISTENT SNAPSHOT
这条SQL做了两件事:
- 开启一个事务
- 立即创建Read View(一致性快照)
之后所有SELECT都基于这个Read View读取——不管其他事务怎么修改,本事务看到的数据永远是快照时刻的版本。
这和上一篇讲的MVCC完全对上了:RR级别下,Read View在事务开始时创建,后续读操作都复用这个Read View。
22.3 为什么不需要锁表
没有--single-transaction时: → mysqldump默认加LOCK TABLES(读锁) → 所有写操作被阻塞 → 保证一致性但影响业务 加了--single-transaction后: → 靠MVCC快照读,不加锁 → 其他事务正常读写 → InnoDB表不影响业务,MyISAM还是会锁对比:
| 方式 | InnoDB | MyISAM | 业务影响 |
|---|---|---|---|
| 默认(–lock-tables) | 加读锁 | 加读锁 | 写阻塞 |
| –single-transaction | MVCC快照,不加锁 | 仍加读锁 | InnoDB不受影响 |
22.4 注意事项——面试易追问
坑1:备份期间不能有DDL
-- 备份过程中如果执行了DDLALTERTABLEuserADDCOLUMNageINT;-- 可能导致:-- 1. 备份失败(表结构变了,查询报错)-- 2. 数据不一致(MDL锁和备份事务冲突)为什么?DDL会修改表结构,mysqldump在备份过程中需要查询表结构(SHOW CREATE TABLE),如果表结构中途变了,备份结果就会混乱。而且DDL需要MDL写锁,可能和备份事务的MDL读锁冲突。
解决:备份窗口内禁止DDL操作;或者监控长DDL避开备份时间。
坑2:大事务影响undo log清理
备份事务:START TRANSACTION WITH CONSISTENT SNAPSHOT → 备份100GB → 可能持续几小时 这几小时内: → undo log不能清理(备份事务的Read View可能需要旧版本) → undo log持续膨胀 → 可能占满磁盘解决:用xtrabackup替代(物理备份不受undo log影响);或监控undo表空间大小。
坑3:只对InnoDB有效
MyISAM不支持MVCC,–single-transaction对MyISAM表无效。如果库里有MyISAM表,还需要额外加--lock-tables或者把MyISAM表转成InnoDB。
22.5 --master-data的作用
# --master-data=2mysqldump --single-transaction --master-data=2dbname>backup.sql# backup.sql开头会有:-- CHANGE MASTER TOMASTER_LOG_FILE='mysql-bin.000123',MASTER_LOG_POS=4567;# 注意是注释掉的(=2表示注释形式)# --master-data=1# 同上但不是注释,会被执行(用于搭建从库)为什么重要?记录了备份时刻的binlog位置。恢复时就知道从哪个binlog位置开始重放,实现时间点恢复(PITR)。
和–single-transaction配合时:--master-data会先加FTWRL获取binlog位置,然后释放锁,再用–single-transaction做一致性备份。FTWRL持有时间极短(只是获取一下位置),对业务影响很小。
题目23:如何将MySQL恢复到某个时间点?
23.1 PITR原理
Point-in-Time Recovery(PITR)= 全量备份 + binlog重放
时间线: ├──────┼──────┼──────┼──────┼──────┼──────┤ 0:00 2:00 6:00 9:00 10:00 10:30 12:00 ↑ ↑ ↑ 全量备份 误操作 要恢复到这里 恢复步骤: 1. 恢复2:00的全量备份 2. 重放2:00到10:00之间的binlog(跳过10:00的误操作) 3. 数据库回到10:00之前的状态23.2 完整恢复流程
第1步:找到最近的全量备份
# 假设凌晨2点做了全备ls-la/backup/# full_backup_20260613_0200.sql 或 xtrabackup全备目录第2步:恢复全量备份
-- 逻辑备份恢复mysql-u root-p<full_backup_20260613_0200.sql-- 物理备份恢复(要先停MySQL)systemctl stop mysql xtrabackup--prepare --target-dir=/backup/full/xtrabackup--copy-back --target-dir=/backup/full/chown-R mysql:mysql/var/lib/mysql systemctlstartmysql第3步:确定binlog范围
-- 查看备份记录的binlog位置(--master-data=2记录的)-- 或者查看当前binlog列表SHOWBINARYLOGS;-- +------------------+-----------+-- | Log_name | File_size |-- +------------------+-----------+-- | mysql-bin.000120 | 1048576 |-- | mysql-bin.000121 | 2097152 |-- | mysql-bin.000122 | 524288 |-- | mysql-bin.000123 | 107 |-- +------------------+-----------+-- 确定目标时间点-- 假设误操作发生在 2026-06-13 10:00:00-- 要恢复到 2026-06-13 09:59:00第4步:重放binlog
# 方法1:按时间重放(最常用)mysqlbinlog\--start-datetime="2026-06-13 02:00:00"\--stop-datetime="2026-06-13 09:59:00"\mysql-bin.000120 mysql-bin.000121 mysql-bin.000122\|mysql-uroot-p# 方法2:按位置重放(更精确)# 先查看binlog找到误操作的位置mysqlbinlog mysql-bin.000122|grep-n"DROP TABLE"# 假设误操作在position 5678mysqlbinlog\--start-position=107\--stop-position=5678\mysql-bin.000122\|mysql-uroot-p按位置 vs 按时间:
- 按时间:简单直观,但可能不精确(多个操作在同一秒内)
- 按位置:精确到具体SQL,但需要先分析binlog找到位置
23.3 跳过误操作——关键技巧
问题:重放binlog时,误操作也在binlog里,怎么跳过?
# 步骤1:分析binlog,找到误操作的位置mysqlbinlog --base64-output=decode-rows-vmysql-bin.000122>binlog_decode.sql# 搜索误操作,比如 DROP TABLE user# 记录误操作前后的position# 步骤2:分两段重放,中间跳过误操作# 段1:从备份位置到误操作之前mysqlbinlog\--start-position=107\--stop-position=5678\mysql-bin.000122|mysql-uroot-p# 段2:从误操作之后继续mysqlbinlog\--start-position=5890\mysql-bin.000122|mysql-uroot-p23.4 闪回工具——误操作的救命稻草
| 工具 | 原理 | 特点 |
|---|---|---|
| binlog2sql | 解析ROW格式binlog,生成回滚SQL | Python开发,简单易用 |
| MyFlash | 美团开源,直接反转binlog | C开发,性能好 |
binlog2sql使用示例:
# 生成回滚SQL(前提:binlog格式为ROW)python binlog2sql.py\-h127.0.0.1-P3306-uroot-p'xxx'\--start-file='mysql-bin.000122'\--start-pos=5678\--end-pos=5890\-B\# 生成回滚SQL>rollback.sql# 执行回滚SQLmysql-uroot-p<rollback.sql为什么必须用ROW格式?STATEMENT格式只记录SQL语句,无法知道具体改了哪些行,无法生成精确的回滚SQL。ROW格式记录了每行的变更前后值,可以精确反转。
23.5 预防误操作
| 措施 | 说明 |
|---|---|
| 开启binlog(ROW格式) | 恢复的前提 |
| 定期备份 | 全备+增量,缩短恢复时间 |
| 权限最小化 | 不要给开发人员DROP/DELETE权限 |
| SQL审计 | 记录谁执行了什么SQL |
| 危险操作先备份 | DELETE/UPDATE前先备份相关数据 |
| 从库验证 | 先在从库执行,确认无误再操作主库 |
| 开启safe-updates | mysql客户端默认加WHERE条件 |
题目24:MySQL高可用方案有哪些?各有什么优缺点?
24.1 高可用的核心指标
RPO(Recovery Point Objective):恢复点目标,能容忍丢失多少数据 RTO(Recovery Time Objective):恢复时间目标,能容忍多长时间不可用 高可用方案的选择本质是在RPO和RTO之间做取舍: → RPO=0(不丢数据)→ 同步复制 → 性能差 → RTO=0(不中断)→ 多主 → 复杂24.2 方案对比
| 方案 | 自动切换 | 数据安全 | 复杂度 | 适用规模 |
|---|---|---|---|---|
| MHA | ✅ | 可能丢少量 | 中 | 中小(最常用) |
| MGR | ✅ | 强一致 | 中 | 中大 |
| PXC/Galera | ✅ | 强一致 | 高 | 中 |
| Keepalived+主从 | ✅ | 可能丢数据 | 低 | 简单场景 |
| 半同步+MHA | ✅ | 极少丢 | 中高 | 数据敏感 |
24.3 MHA——最主流的方案
┌──────────┐ │ MHA │ │ Manager │ ← 监控主库状态 └────┬─────┘ │ 故障检测 ┌────────────┼────────────┐ │ │ │ ▼ ▼ ▼ ┌────────┐ ┌────────┐ ┌────────┐ │ Master │ │ Slave1 │ │ Slave2 │ │ (主库) │ │ (从库1)│ │ (从库2)│ └────────┘ └────────┘ └────────┘MHA故障切换流程:
1. Manager检测到主库不可用(多次心跳失败) 2. 选择数据最完整的从库作为新主库 → 对比各从库的relay log,选最新最全的 3. 补全缺失数据 → 从旧主库的binlog中读取缺失的部分(如果旧主库还活着) → 或者从其他从库的中继日志中补 4. 提升新主库 → 在新主库上执行CHANGE MASTER TO,停止复制 → 执行RESET SLAVE ALL 5. 其他从库切换指向新主库 → CHANGE MASTER TO指向新主库 → START SLAVE 6. VIP漂移到新主库(可选)切换时间:通常10-30秒。
MHA的局限:
- Manager是单点(需要做Manager高可用)
- 需要SSH互信(安全风险)
- 异步复制,极端情况可能丢数据
- 不适合超大规模集群
24.4 MGR——MySQL官方方案
MySQL 5.7.17+原生支持,基于Paxos协议。
┌────────┐ ┌────────┐ ┌────────┐ │ Node1 │←→│ Node2 │←→│ Node3 │ │(读写) │ │(只读) │ │(只读) │ └────────┘ └────────┘ └────────┘ 单主模式:只有Node1可写 或 ┌────────┐ ┌────────┐ ┌────────┐ │ Node1 │←→│ Node2 │←→│ Node3 │ │(读写) │ │(读写) │ │(读写) │ └────────┘ └────────┘ └────────┘ 多主模式:所有节点可写(有冲突风险)MGR vs MHA:
| 对比 | MHA | MGR |
|---|---|---|
| 数据一致性 | 异步,可能丢 | Paxos共识,强一致 |
| 官方支持 | 第三方 | ✅ MySQL官方 |
| 切换速度 | 10-30秒 | 秒级 |
| 性能损耗 | 小 | 有(事务需多数节点确认) |
| 成熟度 | 生产验证多 | 较新但增长快 |
| 限制 | SSH互信 | 必须InnoDB+主键 |
MGR的限制:
- 所有表必须是InnoDB
- 每张表必须有主键
- 不支持DDL并发
- 对网络延迟敏感
- 最大9个节点
24.5 PXC/Galera——强一致方案
┌────────┐ ┌────────┐ ┌────────┐ │ Node1 │←→│ Node2 │←→│ Node3 │ │(读写) │ │(读写) │ │(读写) │ └────────┘ └────────┘ └────────┘ 写入流程: 1. 事务在本地执行 2. 事务发送到所有节点验证(认证阶段) 3. 所有节点验证通过 → 提交 4. 任一节点验证失败 → 回滚PXC的特点:
- 真正多主,任意节点可读写
- 同步复制,写操作必须所有节点确认 → 强一致
- 但性能代价大:每次写都要等所有节点,延迟取决于最慢的节点
性能对比:
主从异步复制:1次写 → 1次IO → 最快 MGR:1次写 → 多数节点确认 → 中等 PXC:1次写 → 所有节点确认+验证 → 最慢(比异步慢20-50%)24.6 选型建议
你的业务是什么? ├── 中小团队,能接受极少量数据丢失 │ → MHA + 半同步(最主流,性价比最高) │ ├── 数据不能丢,合规要求高 │ → MGR(官方方案,趋势所在) │ → 或 PXC(强一致,但性能损耗大) │ ├── 简单业务,快速搞定 │ → Keepalived + 主从(最简单,但可能丢数据) │ └── 大厂,有自己的运维团队 → 自研或基于MHA/MGR二次开发面试回答策略:“先说主流用MHA,再说趋势是MGR,最后根据场景选型。”
题目25:什么是读写分离?如何实现?有什么问题?
25.1 为什么需要读写分离
大多数互联网业务的读写比:10:1 到 20:1 单库架构: 写请求 ──┐ ├──→ 主库(读写混合)──→ 瓶颈! 读请求 ──┘ 10000 QPS扛不住 读写分离架构: 写请求 ──→ 主库(只写)──→ 压力小 读请求 ──→ 从库1 ──┐ 读请求 ──→ 从库2 ──┼──→ 读压力线性扩展 读请求 ──→ 从库3 ──┘25.2 实现方式
方式1:代码层实现
// Spring + MyBatis动态数据源publicclassDynamicDataSourceextendsAbstractRoutingDataSource{@OverrideprotectedObjectdetermineCurrentLookupKey(){// 写操作走主库if(TransactionSynchronizationManager.isActualTransactionActive()){// 事务内走主库return"master";}// 读操作走从库return"slave_"+(currentIndex++%slaveCount);}}// AOP切面@Around("execution(* com.example.service..*.*(..))")publicObjectaround(ProceedingJoinPointpjp){StringmethodName=pjp.getSignature().getName();if(methodName.startsWith("select")||methodName.startsWith("get")||methodName.startsWith("list")){DynamicDataSource.setSlave();// 读走从库}else{DynamicDataSource.setMaster();// 写走主库}returnpjp.proceed();}优点:灵活可控,可以根据业务精细路由
缺点:代码侵入,每个项目都要改
方式2:中间件层实现
应用 ──→ 中间件 ──→ 主库(写) ├──→ 从库1(读) ├──→ 从库2(读) └──→ 从库3(读)| 中间件 | 类型 | 特点 |
|---|---|---|
| ShardingSphere-JDBC | JDBC层增强 | 无代理,性能好,Apache顶级项目 |
| ShardingSphere-Proxy | 代理模式 | 透明,但有代理层开销 |
| MyCat | 代理模式 | 老牌,社区活跃但更新慢 |
| ProxySQL | 代理模式 | MySQL专用,性能好 |
ShardingSphere-JDBC vs Proxy:
| 对比 | JDBC模式 | Proxy模式 |
|---|---|---|
| 性能 | 好(直连数据库) | 有代理层开销 |
| 侵入性 | 需要改代码/配置 | 对应用透明 |
| 部署 | 跟应用走 | 独立部署 |
| 运维 | 简单 | 需要维护代理层 |
推荐:新项目用ShardingSphere-JDBC;老项目改造用Proxy模式。
25.3 读写分离的核心问题——主从延迟
这是读写分离最大的问题,面试必考。
场景:用户下单后马上查看订单列表 1. 应用写主库:INSERT INTO order ... → 主库写入成功 2. 应用读从库:SELECT * FROM order ... → 从库还没同步! → 查不到订单 3. 用户:"我明明下单了,怎么看不到?" → 体验极差解决方案对比
| 方案 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 写后读走主库 | 同一session写后读走主库 | 简单有效 | 需要跟踪session |
| 强制走主库 | 关键读操作指定主库 | 最可靠 | 增加主库压力 |
| 延迟判断 | 检查Seconds_Behind_Master | 自动化 | 有判断延迟 |
| 半同步复制 | 等从库确认才返回 | 从库一定有数据 | 性能损失5-10% |
| 业务容错 | 业务能接受短暂不一致 | 零成本 | 不是所有业务都能接受 |
最实用的方案:写后读走主库
// 核心思路:同一个用户/session,写操作后的一段时间内读走主库publicclassDataSourceRouter{// ThreadLocal记录该线程最近一次写操作时间privatestaticfinalThreadLocal<Long>lastWriteTime=newThreadLocal<>();privatestaticfinallongMASTER_READ_THRESHOLD=3000;// 写后3秒内读主库publicObjectdetermineDataSource(){LongwriteTime=lastWriteTime.get();if(writeTime!=null&&System.currentTimeMillis()-writeTime<MASTER_READ_THRESHOLD){return"master";// 写后3秒内,读走主库}return"slave";// 其他情况走从库}publicvoidmarkWrite(){lastWriteTime.set(System.currentTimeMillis());}}ShardingSphere的方案:内置了"主库路由"提示机制
// 强制走主库HintManagerhintManager=HintManager.getInstance();hintManager.setMasterRouteOnly();// 之后这个线程的查询都走主库25.4 其他问题
事务内的读写
// ❌ 问题:事务内写后读,读走从库可能不一致@TransactionalpublicvoidcreateOrder(Orderorder){orderMapper.insert(order);// 写主库Orderresult=orderMapper.selectById(order.getId());// 读从库 → 可能读不到!}// ✅ 解决:事务内全部走主库@Transactional(readOnly=false)// 标记非只读事务publicvoidcreateOrder(Orderorder){orderMapper.insert(order);Orderresult=orderMapper.selectById(order.getId());// 走主库}从库故障
中间件自动剔除故障从库: 从库1 → 正常 → 分配流量 从库2 → 故障 → 自动剔除 从库3 → 正常 → 分配更多流量 从库恢复后自动加入,不需要人工干预。负载均衡策略
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 轮询 | 依次分配 | 从库配置相同 |
| 权重 | 按配置比例分配 | 从库配置不同 |
| 最少连接 | 选当前连接数最少的 | 请求耗时差异大 |
| 随机 | 随机分配 | 简单场景 |
| 响应时间 | 选响应最快的 | 对延迟敏感 |
25.5 读写分离的适用判断
适合读写分离: ✅ 读多写少(读写比 > 5:1) ✅ 单库读QPS已经扛不住 ✅ 业务能接受短暂的数据延迟 ✅ 查询逻辑相对简单 不适合读写分离: ❌ 写请求多,主库已经是瓶颈 ❌ 数据一致性要求极高 ❌ 业务量小,单库绰绰有余 ❌ 大量复杂关联查询面试追问:“读写分离解决不了什么问题?”
→ 解决不了写瓶颈。所有写操作都在主库,如果写QPS很高,主库照样扛不住。这时候需要分库分表——把写压力分散到多个主库。
25.6 读写分离 → 分库分表 → 分布式事务
数据库架构演进路线: 单库 ↓ 读QPS高 读写分离(一主多从) ↓ 写QPS也高 / 单表数据太大 分库分表(水平拆分) ↓ 跨库事务/关联查询 分布式事务 + 搜索引擎每个阶段解决不同的问题,不要过度设计——单库够用就不要读写分离,读写分离够用就不要分库分表。
思维导图速览
MySQL备份恢复与高可用架构 ├── 二十一、备份方式 │ ├── 逻辑备份(mysqldump)→ 慢但跨版本 │ ├── 物理备份(xtrabackup)→ 快但不跨版本 │ ├── 快照备份(LVM)→ 瞬间但需文件系统支持 │ ├── 冷备/温备/热备 │ └── 生产策略:全量+增量+binlog ├── 二十二、--single-transaction │ ├── 原理:RR+MVCC Read View一致性快照 │ ├── 不锁表(InnoDB),MyISAM仍锁 │ └── 注意:不能有DDL / 大库undo log膨胀 ├── 二十三、PITR时间点恢复 │ ├── 全备恢复 + binlog重放 │ ├── 按时间 / 按位置重放 │ ├── 跳过误操作:分段重放 │ └── 闪回工具:binlog2sql / MyFlash ├── 二十四、高可用方案 │ ├── MHA:最主流,10-30秒切换 │ ├── MGR:官方方案,Paxos共识 │ ├── PXC/Galera:强一致,性能损耗大 │ ├── Keepalived+主从:最简单 │ └── 选型:RPO/RTO取舍 ├── 二十五、读写分离 ├── 实现:代码层 / 中间件 / 驱动层 ├── 核心问题:主从延迟 ├── 解决:写后读走主库(最实用) ├── 事务内走主库 └── 演进:单库→读写分离→分库分表写在最后
- 备份:逻辑慢但跨版本,物理快但不跨版,生产用xtrabackup+全量增量binlog
- –single-transaction:本质就是MVCC一致性快照,和前面事务篇的知识完全打通
- PITR:全备恢复+binlog重放,前提是ROW格式binlog和–master-data
- 高可用:MHA最主流,MGR是趋势,选型看RPO/RTO取舍
- 读写分离:最大问题是主从延迟,写后读走主库最实用