MySQL的crash-safe的原理
MySQL的crash-safe的原理
组件分为
- 连接器
- 分析器
- 优化器
- 执行器
- 存储引擎(插件的形式)
前面的四个分别是Server层的组件,后面存储引擎层是插件,如InnoDB,MyISAM,Memory等
连接器
连接器的作用主要是维持和客户端之间的通信功能。同时还负责同客户端的认证和授权的功能。
每个连接在完成认证和授权后就会一直维持一个长连接,创建完连接的后的所有通信都不需要进行再次进行认证,但每次SQL请求操作都会有权限的认证
在连接完成后,如果连接长时间没有SQL请求通信,该连接会处于Sleep状态,直到超过MySQL实例配置的wait_timeout
参数的时间后,连接器会主动断开该长连接。MySQL实例默认的wait_timeout
的的时间是8小时
分析器
分析器的执行分为两个过程,一个是词法分析,另一个是语法分析
我们发送的SQL语句是一个字符串,里面可能存在空格和字符串。词法分析器的作用就是把这个字符串代表的意思进行数据的格式化,比如SELECT
子串标识这是一个读请求,FROM t_table
表示要操作t_table这张表
语法分析的作用是要对这个语法的正确性做一个检查,如果当前的SQL语法不符合MySQL的语法,那么就直接报错了,不进行下一步的执行
优化器
优化器的作用是根据分析器得出的结果再结合当前表数据的储存情况来的出一个查询效率最高的执行计划。常见的情况有“:
- 同一个SQL语句中存在多个索引列条件,那么应该先选择哪个索引先进行查询
- 多表join操作的时候,如何选择哪个表作为驱动表等
上面两种情况都是优化器等工作职责
执行器
执行器的作用就是负责调用底层存储引擎实现的抽象接口,按照优化器输出的执行计划进行执行。执行器才是真正负责执行SQL操作的组件
存储引擎
存储引擎的作用就是当初MySQL实现的时候留下的可扩展的点,不同的存储引擎的实现可以有着不同的应用场景。MySQL为存储引擎定一个统一的抽象接口,只要不同的存储引擎实现该抽象接口就能被上层的执行器比如OLTP的场景下需要数据库事务的支持,那么InnoDB就是好的选择。而在需要大量读请求而写请求少,并且不需要事物的情况下MyISAM是一个好的选择
一条SQL的执行就是上面的组件从上到下的执行顺序,下面就用MySQL默认的InnoDB引擎进行展开看看InnoDB的执行原理
redo-log
InnoDB有一个重要的模块: redo-log
,它是InnoDB支持事物的重要模块。redo-log是物理日志,它记录了哪一个数据页上做了什么修改。可以说如果没有redo-log,InnoDB就不具有crash-safe的能力
redo-log是由一组分别为4个固定大小文件组成。可以通过MySQL的参数来指定文件的大小。作为日志文件,redo-log是顺序写的,所以写对磁盘来说是非常高效的。数据的结构可以看成是下面的图
Check-point是当前的数据擦除指针,标识了当前redo-log的擦除文件位置。write-point是写指针,标识了当前的数据写文件位置。InnoDB要保证的是write-point不能超过check-point。check-point要一直保持在write-point之前的一段距离。
bin-log
bin-log是MySQL的server层实现的逻辑日志,相当于记录的SQL语句的操作逻辑。
两阶段提交
InnoDB是如何实现crash-safe的呢?一个需要知道的理论就是两阶段提交
两阶段提交用简单点的话讲就是:
- 先读取数据,并更新然后将新行数据保存在内存中
- 将物理更新记录写入redo-log,并标记这条记录为prepare状态(第一步)
- InnoDB将操作提交到执行器,执行器再将逻辑更新记录写入bin-log,同时调用引擎的写入和更新接口将磁盘文件更新
- 上一步操作完成后再提交事物,将redo-log中对应的记录状态改为commit状态(第二步)
- 返回更新结果
崩溃后的数据恢复阶段
如果在更新或写入数据的过程中,机器出现崩溃。那么在机器在重启后,MySQL会首先去验证redolog的完整性,如果redolog中没有prepare状态的记录,则记录是完整的,就日记提交。如果redolog中存在prepare记录,那么就去验证这条redolog对应的binlog记录,如果这条binlog是完整的,那么完整提交redolog,否则执行回滚逻辑