RSS
菜单
全部文章快讯开发科技深度热点

第 28 章 模拟面试:中高级DBA架构师

内容摘要

这是场景与模拟面试篇的收官。面向中高级 DBA / 数据库架构师(5 年以上),面试不再问"索引怎么建",而是深挖原理、考你做过什么架构决策、怎么处置线上事故。本篇分三轮:原理深挖与高可用、性能优化与架构设计(含一道完整架构设计题)、故障处置与综合设计。共 28 道题,每题参考答案+追问。示例基于 MySQL 8.0。建议先按架构师视角自己设计答案,再对照。

📖 本篇简介:这是场景与模拟面试篇的收官。面向中高级 DBA / 数据库架构师(5 年以上),面试不再问"索引怎么建",而是深挖原理、考你做过什么架构决策、怎么处置线上事故。本篇分三轮:原理深挖与高可用、性能优化与架构设计(含一道完整架构设计题)、故障处置与综合设计。共 28 道题,每题参考答案+追问。示例基于 MySQL 8.0。建议先按架构师视角自己设计答案,再对照。

目录

  • 1 本篇导读与面试说明
  • 2 第 1 轮 原理深挖与高可用
  • 3 第 2 轮 性能优化与架构设计
  • 4 第 3 轮 故障处置与综合设计
  • 5 中高级 DBA 面试评分速查表
  • 6 常见坑与注意事项
  • 7 自测与复盘

1 本篇导读与面试说明

中高级面试的特点:不考记忆,考判断和决策。同样一个"分库分表",初级只会说"拆表",架构师要能说清"什么时候拆、拆完有什么代价、怎么兜底、怎么回滚"。

三轮安排:

  • 第 1 轮:原理深挖 + 高可用,考你对 InnoDB、复制、高可用的理解深度;
  • 第 2 轮:性能优化 + 架构设计,含一道完整的电商数据库架构设计题;
  • 第 3 轮:故障处置 + 综合,考你处理线上事故的章法。

下面每题参考答案要点化,实际面试要结合自己的项目经历展开,讲"你做过什么决策、为什么"。

最后提醒:中高级面试常被要求"白板画架构图"。建议对着题 13 和题 24,自己在纸上画出完整数据流,反复练到能脱口而出。能边画边讲,比纯口述有说服力得多。

2 第 1 轮 原理深挖与高可用

题 1:InnoDB 的 redo log 和 binlog 各自干嘛?两阶段提交是什么?

参考答案:redo log 是 InnoDB 引擎层的物理日志,保证崩溃恢复(持久性);binlog 是 Server 层的逻辑日志,用于主从复制和恢复。两阶段提交(prepare → commit)保证 redo 和 binlog 一致。

-- 两阶段提交:先 prepare 写 redo,再写 binlog,最后 commit
-- 崩溃恢复时:redo 有 prepare 但无 commit,靠 binlog 是否完整决定提交还是回滚

追问:为什么需要两阶段提交?

如果不用两阶段,可能出现 redo 提交了 binlog 没写,主从数据不一致;两阶段保证两个日志原子地一致。

这里再补一个高频追问:undo log 和 redo log 的角色对比。面试经常连着问:

| 日志 | 层级 | 作用 | 对应 ACID |

|---|---|---|---|

| redo log | InnoDB 引擎层 | 记录物理修改,崩溃恢复 | 持久性 D |

| undo log | InnoDB 引擎层 | 记录反向操作,回滚+MVCC | 原子性 A |

| binlog | Server 层 | 逻辑日志,复制+恢复 | 主从同步 |

能把这三张表讲成一张关系图,就证明你对 InnoDB 日志体系真的理解透了,而不是背概念。

题 2:buffer pool 怎么工作?命中率低说明什么?

参考答案:buffer pool 是内存缓存热点数据页和索引页。命中率低于 99% 说明内存不够,数据频繁读磁盘,要调大 innodb_buffer_pool_size(一般占物理内存 50%~70%)。

SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
-- 命中率 = 1 - reads / read_requests

追问:buffer pool 调大就万事大吉吗?

不是。调太大会挤掉操作系统和其他进程内存,甚至触发 swap,反而更慢。要留余量。

题 3:Change Buffer 是干嘛的?

参考答案:二级索引页不在 buffer pool 时,先把变更记在 Change Buffer,等页被读入内存再合并,减少随机 IO,提升写性能。

追问:什么索引用不上 Change Buffer?

唯一索引用不上,因为要立即查唯一性,必须把页读进来。

题 4:主从复制有哪些方式?异步、半同步、组复制区别?

参考答案:异步(主不等从)、半同步(主等至少一个从收到 binlog)、组复制 MGR(多数派共识)。一致性和性能依次递进。

| 方式 | 数据安全 | 性能 |

|---|---|---|

| 异步 | 主库宕机可能丢数据 | 最高 |

| 半同步 | 至少一从收到 | 略降 |

| MGR | 多数派共识,强一致 | 开销最大 |

追问:MGR 怎么防脑裂?

少数派凑不齐多数,自动只读,从机制上杜绝双主写。

题 5:主从延迟怎么产生的?怎么治理?

参考答案:主库写 binlog → 从库 IO 拉取 → SQL 回放,慢在回放。治理:开并行复制、避免大事务、从库不扛读、从库性能匹配主库。

-- 开基于组提交的并行复制
SET GLOBAL replica_parallel_workers = 4;
SET GLOBAL replica_parallel_type = 'LOGICAL_CLOCK';

追问:大事务为什么放大延迟?

一个大事务 binlog 是整体,从库回放要完整做完,期间整个从库都落后。

题 6:高可用切换怎么防止脑裂?

参考答案:核心是 fencing——提升新主前必须隔离旧主(关机/断网),让它不能复活后继续写。优先用 MGR 这类多数派方案,从机制上防裂。

追问:fencing 具体怎么做?

STONITH(直接关旧主)、防火墙断旧主网络、旧主启动时自检发现不是新主就强制只读。

题 7:RR 隔离级别下 Next-Key Lock 解决了什么?带来什么问题?

参考答案:解决幻读,通过记录锁+间隙锁锁住范围。带来的问题是并发插入间隙时互相等待,易死锁,且锁范围变大。

-- 范围 FOR UPDATE 会锁间隙,别的事务在间隙插入会被阻塞
SELECT * FROM t WHERE id BETWEEN 10 AND 20 FOR UPDATE;

追问:为什么很多互联网公司用 RC 而不是 RR?

RC 下间隙锁大幅减少,并发更高、死锁更少;且业务大多不需要 RR 的防幻读。

题 8:一条 UPDATE 不加索引会发生什么?

参考答案:InnoDB 扫描全表逐行加 X 锁(RR 下连间隙),等于锁全表,并发急剧恶化,还易死锁。

-- 没走索引:扫全表加锁,灾难
UPDATE orders SET status=1 WHERE user_name='张三';
-- 正确:user_name 建索引,只锁命中行

追问:那 DELETE 不走索引呢?

一样,锁全表。大表 DELETE 不走索引是经典事故。

题 9:MVCC 的版本链和 Read View 怎么配合?

参考答案:每行有隐藏事务 id,undo log 串成版本链;Read View 记录活跃事务列表,遍历版本链找到对当前事务可见的那版数据。

追问:RC 和 RR 的 Read View 差别?

RC 每次 SELECT 生成新 Read View;RR 事务开始生成一次,整个事务复用。

题 10:聚簇索引为什么选主键?主键太长有什么问题?

参考答案:InnoDB 按主键组织数据(索引组织表)。主键太长会让所有二级索引都存一份长主键,占空间、拖性能。主键要短、递增。

-- 好:BIGINT 自增,短且递增
-- 坏:UUID 做主键,长且无序,页分裂+二级索引膨胀

追问:没显式主键会怎样?

InnoDB 会选第一个唯一索引,或隐藏生成一个 6 字节 ROWID,不可控。务必显式建主键。

3 第 2 轮 性能优化与架构设计

题 11:一条慢 SQL,你的完整优化方法论?

参考答案:EXPLAIN 看执行计划 → 定位全表扫描/ filesort → 改写法 + 补联合索引 → EXPLAIN ANALYZE 实测验证 → 对比扫描行数和延迟。先改 SQL 再补索引。

EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id=1 AND status=2 ORDER BY create_time DESC LIMIT 20;

追问:怎么判断该加联合索引而不是多个单列索引?

高频组合查询用联合索引,遵循等值列在前排序列在后;单列索引在多条件下只能用一个。

题 12:分库分表怎么选分片键?有什么坑?

参考答案:选最高频查询维度(如 user_id),保证分布均匀、提前定分片数。坑:数据倾斜(大 V 打爆单分片)、跨分片查询、扩容要迁移。

追问:分片数后期不够了怎么办?

要全量数据迁移重新分布,代价极大;所以一开始就要按未来 3 年规划好分片数。

题 13:(架构设计题)设计一个支撑双 11 秒杀的数据库方案

参考答案:分层防线——前端限流/答题挡刷量;Redis 预扣库存拦读洪峰;下单请求进 MQ 异步削峰;主库只平缓消费写;热点库存拆分多行;读走从库;非核心功能降级。

请求 → 限流/答题 → Redis 预扣库存(原子+去重) → MQ 削峰 → MySQL 异步落单
                                            ↓
                                    读流量 → 从库

追问:Redis 扣了库存但消息丢了怎么办?

靠最终一致对账:大促后比对 Redis 库存和 DB 库存,差异修复。

这道秒杀题,面试官往往会继续追问"热点商品库存挤在一行怎么办"——答案是把单行库存拆成多行分片(如 10 片),扣减时随机落片分散行锁;或库存全放 Redis,DB 只做对账。能在架构题里主动点出"热点行"这个细节,立刻和只会讲"限流+MQ"的候选人拉开档次。

题 14:缓存穿透、击穿、雪崩怎么解?

参考答案:穿透(查不存在)用布隆过滤器/空值缓存;击穿(热点 key 过期)用互斥锁/逻辑不过期;雪崩(批量过期)过期时间加随机抖动。

# 热点 key 防击穿:只让一个请求回源重建
# if redis.get(key) is None:
#     if redis.setnx("lock:"+key, 1, nx=True, ex=10):
#         val = db.query(); redis.set(key, val, ex=60); return val
#     else: sleep重试; return redis.get(key)

追问:布隆过滤器原理?

多位 hash 判存在,说不存在一定不存在,说存在可能误判;用来挡不存在的请求直接打 DB。

题 15:亿级表怎么做在线 DDL?

参考答案:8.0 Online DDL(ALGORITHM=INPLACE, LOCK=NONE)或 pt-online-schema-change;大表加列用 8.0 Instant;低峰期执行并盯主从延迟。

ALTER TABLE orders ADD INDEX idx_uid(user_id), ALGORITHM=INPLACE, LOCK=NONE;

追问:Online DDL 真的完全不影响业务吗?

不锁表但耗 IO,主从延迟会上升;大变更还是要低峰、分批。

题 16:读写分离下主从延迟导致读到旧数据,怎么解?

参考答案:关键读(读己之写)走主库;非关键读走从库;或用 WAIT_FOR_EXECUTED_GTID_SET 等从库追平。

-- 等从库追到指定 GTID 再读
SELECT WAIT_FOR_EXECUTED_GTID_SET('aaaaaaaa-...:123', 3);

追问:怎么判断该走主还是走从?

按业务:刚写过的、要最新的走主;容忍延迟的列表、详情走从。

题 17:分库分表后跨分页、count(*) 怎么优化?

参考答案:跨分片分页/聚合走 ES 或 CK;深分页用游标分页;count 用估算值或 Redis 计数器,别在业务库硬查。

-- 后台全量统计不查分片库,走 binlog 同步的分析库

追问:游标分页为什么比 LIMIT offset 快?

不用扫描丢弃 offset 行,直接从上一页最后的排序位置开始。

题 18:怎么设计一个不被打挂的数据库监控体系?

参考答案:三层——采集(慢日志、性能指标)、告警(分级阈值)、治理(慢 SQL 定期 review)。关键指标:QPS、TPS、Threads_running、buffer 命中率、主从延迟、慢查询增量。

SHOW GLOBAL STATUS LIKE 'Threads_running';  -- 活跃并发,关键告警指标

追问:告警怎么避免告警疲劳?

分级:预警(慢查询涨)不电话,紧急(连接堆积)才电话;阈值按历史基线动态调。

4 第 3 轮 故障处置与综合设计

题 19:主库突然宕机,你的处置流程?

参考答案:确认旧主真死并隔离(防脑裂)→ 检查从库追上程度(评估丢数据)→ 提升最同步的从为主 → 其他从改指向新主 → 应用切流。全程保留现场。

STOP REPLICA; SET GLOBAL read_only=OFF;  -- 提升从库
-- 其他从库 CHANGE REPLICATION SOURCE TO 新主

追问:切换时从库还落后怎么办?

旧主磁盘可读就抢救 binlog 补;不可读就接受少量丢失(RPO>0),业务补偿。

架构师级别的回答,要主动提 RTO 和 RPO 两个指标:RTO(多久恢复)靠自动化切换压到秒级;RPO(丢多少数据)靠半同步复制压到接近 0。面试官听到你主动用这两个词,就知道你真的做过高可用设计。

题 20:线上发现一条 SQL 把 CPU 打满,但 SQL 还在跑,怎么止血?

参考答案:processlist 找跑最久的会话 → KILL 止血 → 保留现场 → 事后 EXPLAIN 分析加索引。先止血再根因。

SELECT id,time,info FROM processlist WHERE command<>'Sleep' ORDER BY time DESC;
KILL <id>;

追问:KILL 大事务后要注意什么?

还要做 undo 回滚,期间资源照样占用,别以为 KILL 就立刻好了。

题 21:突发死锁风暴,怎么处理?

参考答案:先回滚引发风暴的新版本;限流降级;应急可临时关死锁检测(但会把死锁变锁等待);业务层对 1213 自动重试。

-- 应急:临时关死锁检测(谨慎,事后要开回)
SET GLOBAL innodb_deadlock_detect = OFF;

追问:为什么统一加锁顺序能防死锁?

所有事务按相同顺序加锁,就不会形成循环等待。

题 22:误删了一张表的数据,怎么办?

参考答案:评估能否用备份/binlog 恢复。有全量备份+binlog 的话,先恢复全量备份再重放 binlog 到误删前。平时要有备份恢复预案并演练。

# 恢复流程(示意):先恢复最近全量备份,再 mysqlbinlog 重放 binlog 到误删时刻前

追问:怎么避免误删?

生产库收回 DELETE/DROP 权限、用 LIMIT 分批、大删除先 SELECT 确认、操作前备份。

题 23:数据库磁盘突然满了,怎么办?

参考答案:先找最大的文件(binlog、慢日志、临时表)清理;binlog 过期自动清理;别删正在用的数据文件。紧急时清旧 binlog 腾空间。

-- 控制 binlog 保留天数,自动清理
SET GLOBAL binlog_expire_logs_seconds = 604800;  -- 保留 7 天

追问:磁盘满导致数据库写入失败,怎么恢复?

先腾空间,再让数据库恢复;注意 binlog 不全会影响主从和恢复。

题 24:(综合设计)设计一个日订单 1000 万的订单库架构

参考答案:按 user_id 分库分表(如 16 库×64 表),全局雪花 ID;读写分离;binlog 同步到 CK 做报表、到 ES 做订单搜索;热点新数据进 Redis 缓存;跨服务用本地消息表最终一致。

订单 → 按 user_id 分片 (16库×64表)
     → binlog → ES(搜索) / CK(报表)
     → 新订单详情 → Redis 缓存

追问:为什么按 user_id 不按 order_id?

最高频是"用户看自己订单",按 user_id 路由单分片;order_id 查询走 ES 或全局映射。

这道综合题还有个隐藏考点:热点账户。头部大商户的订单量远超普通用户,按 user_id 哈希后个别分片会被打爆。成熟方案会把这种大商户单独路由到独立分片,或对超大商户做垂直拆分。能主动提"数据倾斜"这个点,是区分架构师和背模板的关键。

题 25:怎么评估一个数据库方案是否过度设计?

参考答案:看规模是否真到了那一步。日活几千就上分布式数据库是过度;日订单千万还单库是不足。架构要随规模演进。

追问:过度设计的代价是什么?

运维复杂度、排障成本、团队学习成本,早期拖慢迭代速度。

题 26:你怎么做数据库容量规划?

参考答案:预估增长(行数/存储/读写 QPS)→ 估算单库上限 → 留 30% 余量 → 制定扩容/归档计划;每季度复盘一次。

SELECT table_rows, data_length FROM information_schema.tables
WHERE table_schema='shop';   -- 监控增长趋势

追问:容量规划最容易漏什么?

漏了索引体积和 binlog 体积,只算数据本身;实际索引+binlog 可能是数据的 2~3 倍。

题 27:MySQL 8.0 相比 5.7 你最看重哪些改进?

参考答案:隐藏索引、原子 DDL、窗口函数、CTE、Instant 加列、降索引开销、并行复制增强。Instant 加列对大表 DDL 是质变。

-- 8.0 Instant 加列,几乎瞬间完成
ALTER TABLE t ADD COLUMN c INT DEFAULT 0, ALGORITHM=INSTANT;

追问:8.0 升级有什么坑?

字符集默认从 latin1 变 utf8mb4、sql_mode 变严、group by 不再隐式排序,老应用要适配。

升级类问题答好有个技巧:别只列新特性,要讲升级风险。真正做过升级的 DBA 会提到"先在从库升级、验证无误再切主""回滚预案是什么""灰度升级而非一刀切"。能把升级讲成一次有预案的变更,而不是列特性清单,才是架构师水准。

题 28:你作为 DBA,怎么推动一个慢 SQL 治理项目落地?

参考答案:采集慢日志 → TOP N 分派业务方 → 新 SQL 上线接 CI 审核 → 定期 review → 闭环销项。靠制度和卡点,不靠人肉。

# 慢 SQL 治理台账:记录每条慢 SQL 状态,周会 review
# 待处理 → 优化中 → 已解决,形成闭环

追问:业务方不配合优化慢 SQL 怎么办?

靠数据说话(列出它拖垮了多少吞吐),靠 CI 卡点(新烂 SQL 进不来),靠监控告警升级。

5 中高级 DBA 面试评分速查表

| 考察维度 | 及格 | 优秀(架构师) |

|---|---|---|

| 原理 | 知道 ACID、索引 | 能讲两阶段提交、MVCC 版本链、Change Buffer |

| 高可用 | 会主从切换 | 能讲脑裂防护、MGR、RPO/RTO 权衡 |

| 架构 | 会分库分表 | 能做完整架构设计、选型、演进规划 |

| 故障 | 会 KILL 止血 | 能讲完整故障时间线和预防机制 |

| 治理 | 会调一条 SQL | 能建监控告警和治理闭环 |

| 决策类问题 | 架构师的回答姿态 |

|---|---|

| 要不要分库分表 | 先问规模,讲代价,不急于拆 |

| 怎么防脑裂 | fencing + 多数派,讲 RPO 权衡 |

| 慢 SQL 怎么治 | 止血→定位→改写→监控闭环 |

| 新业务怎么选型 | 按读写模型+规模,克制引入 |

评分时还有一条隐形标准:你有没有"自己踩过坑"的具体案例。同样答"主从延迟",背理论的人讲概念,做过的人会讲"我们大促时延迟飙到 300 秒,后来靠开并行复制和拆大事务压回 1 秒"。面试前准备 2~3 个这样的真实案例,比多背 10 道题管用。

6 常见坑与注意事项

1. 背名词不讲决策:中高级面试光说"用分库分表"没用,要讲为什么、代价、怎么兜底。

2. 忽略 RPO/RTO:高可用题不讲数据丢失和恢复时间目标,显得没做过真实切换。

3. 架构一步到位:讲方案时过度设计,暴露"没被真实业务逼过"。

4. 故障不讲时间线:讲事故复盘说不出"几点做了什么",像编的。

5. 只讲技术不讲治理:中高级要体现"建制度、建闭环"的管理视角。

6. 不结合自己项目:答案空泛,面试官追问"你具体做过什么"就露馅。

7. 忽略版本差异:答题不注明 MySQL 8.0,把 5.7 的命令(如 SLAVE)和 8.0(REPLICA)混用,暴露不严谨。

8. 只谈理想不谈权衡:任何架构都有代价,光说好处不说代价的方案,面试官一眼看穿是背的。

记住:中高级面试没有标准答案,面试官看的是你做决策时的权衡能力。多讲"为什么这么选、放弃了什么、代价是什么",比堆名词更有说服力。

7 自测与复盘

自测 1:讲清 redo log、binlog、两阶段提交的关系。

参考答案:redo 引擎层保持久,binlog Server 层供复制/恢复;两阶段提交保证两者一致,崩溃恢复靠 binlog 是否完整决定 prepare 事务的命运。

自测 2:口述主库宕机切换的完整步骤,并指出防脑裂的关键动作。

自测要点:确认旧主死透并隔离(fencing)→ 提升最同步从库 → 其他从改指向 → 应用切流。

自测 3:画出日订单千万级的订单库架构,说明分片键和数据流向。

自测要点:user_id 分片 + 雪花 ID + binlog 同步 ES/CK + Redis 缓存新订单。

自测 4:为什么互联网公司多用 RC 而不是 RR?

参考答案:RC 下间隙锁大幅减少,并发更高、死锁更少;业务大多不需要 RR 的防幻读。

自测 5:作为 DBA,你怎么从"修一条慢 SQL"升级到"建一套治理体系"?

自测要点:能否说出采集慢日志→TOP N 分派→CI 卡点→定期 review→闭环销项这套治理闭环,而不是每次人工救火。

结语:模拟面试到这里就结束了。建议你把这三轮的题目合起来,掐表完整过一遍——基础轮卡壳就回去重读前面精讲篇,原理轮卡壳就重读 MVCC/锁/主从篇,架构轮卡壳就重读场景篇。面试是系统性工程,单点背题过不了中高级,只有把"原理—场景—决策"串成一条线,才能在白板前从容作答。

下一篇预告:第 29 章 阿里系MySQL真题精讲

— 全文完 —回到顶部 ↑
下载推广海报

文章推广海报

《第 28 章 模拟面试:中高级DBA架构师》完整推广海报
DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。