前置概念
MySQL的双层架构分工
在执行的时候
MySQL的服务层实现逻辑处理,优化,计算
存储引擎层实现数据提供和存储 以及存储上的优化方案和操作 包括BufferPool的设计 优化
redolog日志
redolog日志是MySQL 存储引擎层的物理日志 记录事务修改的操作以及结果 他用于保证事务的持久性 能够保证数据持久化和崩溃恢复
binlog日志
binlog日志是MySQL服务层的日志 是一种二进制格式的日志 用于数据恢复 数据迁移等
流程分析
一条更新SQL语句是如何执行的 以update user set age=18 where id=21为例子
首先 客户端需要先通过连接器 实现连接以及权限的校验 通过校验之后
就可以通过分析器 进行词法分析 随后通过优化器 进行执行计划的生成以及索引的选择
通过优化器的选择之后 由执行器来操作引擎 进行后续的处理
那么执行器是怎么做的呢
-
首先 先通过磁盘IO 找到对应的数据页 如果数据页在BufferPool中 就直接对内存中数据页进行操作 如果数据页不存在于BufferPool中 需要先从磁盘读取数据页 加载到BufferPool 对应上文 会先通过索引快速找到id=21的数据 将数据页加载到BufferPool(如果不存在于BufferPool的话)
-
随后 执行器会根据返回的数据 对这些数据进行计算 并且将结果返回给存储引擎层
-
存储引擎层把更新结果更新到BufferPool中 并且将BufferPool标记为脏页 并且记录到redolog日志中 此时redolog处于prepare状态 随后告诉服务层 事务可以提交了
-
服务层收到消息后 会生成对应的binlog记录 持久化到binlog日志
-
执行器再调用存储引擎的提交事务接口 将redolog的状态改为commit 并且提交事务
思考分析
基于 流程分析 模块可以衍生出很多问题
- BufferPool的作用是什么
- 为什么需要采用两阶段提交(redolog->binlog->redolog)
BufferPool的作用
在做后端项目的时候 我们常常会使用Redis做一层缓存 在缓存进行修改 再通过一致性操作 保证修改
最终能够落盘 MySQL作为一个高性能的持久化存储数据库 同样存在读写并发压力
因此他通过设计一层BufferPool缓存 通过独特的缓存淘汰机制 既能够保证大部分读请求能够打到缓存上 又能够避免修改操作时的随机磁盘IO 从而提高总体的吞吐量
在修改事务中 不是直接修改磁盘 而是通过将数据对应的数据页加载到BufferPool
对BufferPool进行更改 标记为脏页 再进行异步刷盘
为什么需要两阶段提交
在基于InnoDB存储引擎的MySQL的事务内
存储引擎层的redolog负责数据持久化 保证事务的持久性 他能够保证事务提交成功 数据就一定能够持久化保存下来
服务层的binlog主要用于数据备份 数据恢复等
设计两阶段的根本原因是保证redolog以及binlog的一致性 从而保证数据binlog数据和数据库数据的一致性 如果没有保证其一致性 那么后续通过binlog进行数据恢复或者数据迁移时就会产生很多问题
如果没有设计两阶段提交
情况1 先修改redolog 再修改binlog
在这种情况下 如果redolog修改后 数据库宕机了 重启时通过redolog恢复数据 此时就会导致存储数据和binlog出现不一致性
情况2 先修改binlog 再修改redolog
如果先修改binlog 然后数据库宕机了 重启的时候binlog就会多出新的数据记录 导致出现不一致性
而先通过redolog的prepare预提交 然后再提交binlog
最后由执行器 进行prepare的提交 和 事务的提交
能够保证redolog和binlog的的一致性
- redolog prepare后宕机: MySQL重启时 由于binlog和redolog都没有提交 数据不会恢复 能够保证一致性
- binlog提交后宕机:MySQL重启时 由于redolog已预提交 binlog已提交 说明该事务已经进入提交阶段 因此现在可以补提交