Skip to content

MySQL 架构分层与请求全过程

面试里问“MySQL 有几层”,不是让你背一个固定数字。真正要回答清楚的是:客户端发来一条 SQL 后,请求经过哪些模块,每一层解决什么问题,binlog、redo log、undo log 分别在哪里,慢 SQL、连接满、锁等待、刷盘慢分别该看哪一层

这一页把 MySQL 从外到内拆开,再用 selectupdate 两条链路把所有层串起来。

这一页解决这些问题

问题要掌握到什么程度
MySQL 到底有几层能说三层,也能展开五层,不死背数字
每层负责什么连接、解析、优化、执行、引擎、页、日志边界清楚
binlog、redo、undo 在哪binlog 属于 Server 层,redo/undo 属于 InnoDB
一条 select 怎么执行从连接、解析、优化器到 InnoDB B+Tree 读页
一条 update 怎么提交从加锁、undo、脏页、redo、binlog 到两阶段提交
线上问题怎么定位能按层判断连接满、慢 SQL、锁等待、IO 慢、主从延迟

不要死背“几层”

不同资料对 MySQL 架构分层叫法不完全一样。学习和面试时建议掌握两种表达。

表达方式分层适合场景
三层模型连接层、Server 层、存储引擎层面试快速回答
五层模型客户端层、连接层、SQL 层、存储引擎层、文件与日志层深入解释流程和排查

三层模型强调职责边界:

mermaid
flowchart TD
    A["连接层<br/>连接、认证、权限、线程"] --> B["Server 层<br/>解析、预处理、优化器、执行器、binlog"]
    B --> C["存储引擎层<br/>InnoDB、B+Tree、Buffer Pool、锁、MVCC、redo、undo"]
    C --> D["磁盘文件<br/>表空间、数据页、索引页、日志文件"]

五层模型强调一次请求经过的完整路径:

mermaid
flowchart TD
    A["客户端层<br/>JDBC、连接池、ORM"] --> B["连接层<br/>TCP、认证、权限、连接状态"]
    B --> C["SQL 层<br/>解析、预处理、优化、执行"]
    C --> D["存储引擎层<br/>InnoDB 接口、索引、事务、锁"]
    D --> E["文件与日志层<br/>数据页、undo、redo、binlog 文件"]

这两个说法并不矛盾。三层适合快速讲边界,五层适合讲全过程。

每层到底负责什么

负责什么典型组件不负责什么
客户端层发起连接、发送 SQL、管理连接池JDBC、MyBatis、HikariCP、Navicat不负责真正执行 SQL
连接层建连接、认证、权限、连接状态连接器、线程、权限检查不负责选择索引
SQL 层理解 SQL、选择执行计划、调度执行解析器、预处理器、优化器、执行器、binlog不直接管理 InnoDB 数据页
存储引擎层读写数据页、维护索引、事务、锁、MVCCInnoDB、Buffer Pool、B+Tree、redo、undo不解析 SQL 文本
文件与日志层数据和日志落盘ibd、redo log file、undo tablespace、binlog file不决定业务语义

一个容易混淆的边界:

机制所属层主要作用
binlogServer 层主从复制、时间点恢复、审计回放
redo logInnoDB 引擎层崩溃恢复,保证已提交事务不丢
undo logInnoDB 引擎层事务回滚,MVCC 历史版本
Buffer PoolInnoDB 引擎层缓存数据页和索引页
优化器Server 层根据统计信息选择访问路径

select 请求全过程

一条查询 SQL 不会直接去磁盘找数据,而是先经过 Server 层生成执行计划,再由执行器调用 InnoDB。

mermaid
flowchart TD
    A["客户端发送 SELECT"] --> B["连接层检查连接和权限"]
    B --> C["解析器做词法和语法分析"]
    C --> D["预处理器检查表、列、权限"]
    D --> E["优化器选择索引和 Join 顺序"]
    E --> F["执行器按计划调用引擎接口"]
    F --> G["InnoDB 从 B+Tree 定位页"]
    G --> H{"Buffer Pool 是否命中"}
    H -- "命中" --> I["内存读取记录"]
    H -- "未命中" --> J["从磁盘加载页"]
    J --> I
    I --> K["返回行给执行器"]
    K --> L["Server 层过滤、排序、聚合"]
    L --> M["返回结果给客户端"]

每一步发生什么:

步骤做什么如果出问题会怎样
连接层校验账号、权限、连接状态连接失败、连接数满、权限不足
解析器判断 SQL 语法语法错误直接失败
预处理器检查表字段是否存在表不存在、字段不存在
优化器选索引、Join 顺序、估算 rows统计信息不准可能选错索引
执行器调用引擎,一行行取结果扫描多、回表多会慢
InnoDB查 B+Tree、读页、MVCC 判断IO 高、锁等待、版本链长
Server 返回排序、聚合、网络返回filesort、临时表、大结果集慢

update 请求全过程

updateselect 多了事务、锁、undo、redo、binlog 和提交过程。

mermaid
flowchart TD
    A["客户端发送 UPDATE"] --> B["连接层和 SQL 层处理"]
    B --> C["优化器选择定位记录的索引"]
    C --> D["执行器调用 InnoDB"]
    D --> E["InnoDB 定位记录并加行锁"]
    E --> F["生成 undo log 旧版本"]
    F --> G["修改 Buffer Pool 中的数据页"]
    G --> H["生成 redo log record"]
    H --> I["提交阶段 redo prepare"]
    I --> J["Server 层写 binlog"]
    J --> K["redo commit"]
    K --> L["返回提交成功"]

这里最关键的是两阶段提交:

mermaid
sequenceDiagram
    participant T as Transaction
    participant R as InnoDB redo
    participant B as Server binlog
    T->>R: write redo prepare
    T->>B: write binlog
    T->>R: write redo commit
    T-->>T: commit success

为什么要这样做?

如果没有两阶段提交可能后果
redo 成功,binlog 失败主库恢复有数据,从库没有,主从不一致
binlog 成功,redo 失败从库可能重放了,主库恢复后没有
两者无法对齐崩溃恢复时不知道事务到底该提交还是回滚

所以 update 链路里有两个层面的“正确”:

  1. InnoDB 用 undo、锁、redo 保证事务自身正确。
  2. Server 层 binlog 和 InnoDB redo 用两阶段提交保证复制和恢复一致。

为什么 Server 层和存储引擎层要分开

如果 MySQL 只有一个混在一起的巨大模块,会很难支持不同存储方式。分层以后:

好处解释
SQL 处理复用解析器、优化器、执行器可以服务不同引擎
引擎可替换InnoDB、MyISAM、Memory 可以有不同存储实现
职责清晰Server 层管 SQL 语义,引擎层管数据页和事务
便于扩展binlog、复制、权限、优化器在通用层处理

但这种分层也带来一个问题:Server 层 binlog 和 InnoDB redo 是两套日志。所以事务提交必须通过两阶段提交协调它们。

按层排查线上问题

线上 MySQL 问题不要一上来就“加索引”或“重启”。先判断是哪一层。

mermaid
flowchart TD
    A["MySQL 问题"] --> B{"表现是什么"}
    B -- "连接失败或等待" --> C["查连接层"]
    B -- "SQL 慢" --> D["查优化器和执行计划"]
    B -- "锁等待或死锁" --> E["查 InnoDB 锁和事务"]
    B -- "IO 高或刷盘慢" --> F["查 Buffer Pool、redo、磁盘"]
    B -- "主从延迟" --> G["查 binlog、复制线程、大事务"]
现象优先看哪层常用手段
Too many connections连接层show processlist、连接池配置、max_connections
SQL 扫描很多行SQL 层、优化器EXPLAIN、慢日志、统计信息
明明有索引却不用优化器show indexanalyze table、直方图
update 卡住InnoDB 锁show engine innodb status、事务表、锁等待
普通 select 很慢InnoDB、Buffer Pool命中率、IO、undo 版本链、返回行数
commit 慢日志和磁盘redo/binlog 刷盘策略、磁盘延迟
从库延迟binlog 和复制层大事务、SQL 线程、并行复制、从库慢查询

可运行 Demo:观察连接、执行计划和引擎状态

准备表:

sql
create table layer_demo_order (
  id bigint primary key auto_increment,
  user_id bigint not null,
  status tinyint not null,
  amount decimal(10, 2) not null,
  created_at datetime not null,
  key idx_user_created (user_id, created_at),
  key idx_status_created (status, created_at)
) engine = InnoDB default charset = utf8mb4;

插入数据:

sql
insert into layer_demo_order(user_id, status, amount, created_at)
values
  (1001, 1, 99.00, now()),
  (1001, 2, 199.00, now()),
  (1002, 1, 299.00, now());

观察连接层:

sql
show processlist;
show global status like 'Threads%';
show variables like 'max_connections';

观察优化器计划:

sql
explain
select id, amount
from layer_demo_order
where user_id = 1001
order by created_at desc
limit 10;

观察 InnoDB 状态:

sql
show engine innodb status\G

更新统计信息:

sql
analyze table layer_demo_order;

这个 Demo 对应的学习重点是:同一个 SQL 问题,可能涉及连接层、优化器、InnoDB、日志和磁盘,不要只盯一个点。

常见误区

误区为什么错正确理解
MySQL 架构只有一种官方标准层数学习资料按不同角度划分重点是职责边界,不是死背数字
binlog 和 redo log 都是事务日志,所以一样所属层、格式、用途不同binlog 管复制和恢复,redo 管崩溃恢复
SQL 层会直接读磁盘SQL 层通过引擎接口访问数据InnoDB 管页、索引、Buffer Pool
有索引就一定快优化器可能不用,或回表太多看 EXPLAIN、rows、filtered、Extra
update 只是改一行涉及锁、undo、redo、binlog、刷盘写链路比读链路复杂得多

面试标准回答

text
MySQL 可以按三层理解:连接层、Server 层和存储引擎层。连接层负责客户端连接、认证、权限和连接状态;Server 层负责 SQL 解析、预处理、优化器、执行器以及 binlog;存储引擎层负责真正的数据读写,例如 InnoDB 的 B+Tree、Buffer Pool、事务、锁、MVCC、redo log 和 undo log。

如果展开,也可以说成客户端层、连接层、SQL 层、存储引擎层、文件与日志层。select 请求会先经过连接和权限校验,再经过解析器、预处理器、优化器生成执行计划,执行器调用 InnoDB 接口,InnoDB 通过 B+Tree 和 Buffer Pool 读取数据页,最后返回结果。update 请求还会涉及行锁、undo log、修改 Buffer Pool、redo log、binlog 和两阶段提交。

binlog 属于 Server 层,主要用于主从复制和时间点恢复;redo log 和 undo log 属于 InnoDB,redo 用于崩溃恢复,undo 用于回滚和 MVCC。按层理解 MySQL,排查问题时才能区分连接满、优化器选错计划、锁等待、磁盘 IO 和主从延迟分别应该看哪里。

关联知识点

知识点说明
MySQL 架构分层基础分层说明
SQL 执行全过程原理查询 SQL 从连接到 InnoDB 的完整链路
InnoDB 更新事务全过程update 的锁、undo、redo、binlog、MVCC
EXPLAIN 执行计划优化器如何选择计划,rows 从哪里来
redo log 与 binlog两阶段提交和崩溃恢复