MySQL如何保证数据不丢失?

MySQL作为为现下最流行的开源数据库之一,其中一个重要的原因就是其能保证数据的可靠性,即可以保证数据不丢失。本文对MySQL保证数据不丢失的原理知识进行了总结。本文的内容都是在MySQL的innodb引擎下的原理

1.一条sql语句在MySQL中的执行过程

理解MySQL数据不丢失原理首先要理解一条sql语句在MySQL中是如何执行的。

总体上,MySQL的逻辑架构可以分为Server层和存储引擎两层。

Server层的主要负责处理MySQL的核心服务功能,以及一些内置函数处理等等。

存储引擎层则主要负责数据的存储和提取。支持多种存储引擎。比如最常用的InnoDB。

sql语句大致可以分为两种,查询语句和更新语句。

(1)查询语句执行过程:

其大致流程如下图所示:

流程:

Step1 :客户端与MySQL进行连接,负责这个功能就是Server层的连接器。这一步主要做的是验证客户端的身份,权限等。

Step2:查询缓存,即从缓存中看看这个语句之前是不是执行过,如果执行过,且缓存中有数据,则直接返回数据给客户端。(MySQL8.0以上版本不支持查询缓存,MySQL8.0版本以上可以认为没有这个步骤,缓存技术一般由非关系数据库实现,比如redis,不应该是数据库考虑的)

Step3:没有命中缓存,则分析语句,准备开始执行,sql是与数据库沟通用的语言,分析器就是解析sql语言,明白客户端需要什么数据。当然,这里也有可能sql存在语法错误,出现语法错误则返回语法错误信息。

Step4:经过分析器,则可以认为MySQL已经了解客户端需要查询的内容,这个时候进入优化器,优化器的作用就是为选择合适查询方式。(比如:走哪个索引合适,连接表的顺序等等优化操作)。

Step5:语句进入执行阶段,调用存储引擎查询数据(这个过程还会再核对一次当前客户端的权限,如果对该表没有查询权限,就会返回错误信息),引擎将查询出来的结果组成结果集返回给客户端。

(2)更新语句执行流程:

更新语句执行流程其实与查询语句执行流程差不多,因为更新过程一样要先定位到该数据,这个过程就和查询语句的流程是差不多,依次需要经过连接器->分析器->优化器->执行器->存储引擎找到该数据项,然后更新。与查询流程最大的不同的地方就是,更新过程中涉及到两个日志模块,分别是重做日志(redo log)和归档日志(binlog)。这两个日志模块是MySQL保证数据不丢失的重要模块。

2.重做日志(redo log)

每次更新操作如果都要直接写进磁盘中,则每一次的更新操作都要先到磁盘找到该行数据,然后进行更新,操作磁盘则就涉及到IO操作,每个更新操作都要进行IO操作成本将很大。所以MySQL引入了redo log来提升更新效率。即WAL(Write-Ahead Logging)技术,其核心就在于每次更新操作都是先写日志,等空闲或者redolog写不下的时候再去更新磁盘。

即有了redolog后,更新流程变为,每次更新操作,将记录写在redolog中,并更新内存中的数据,然后直接返回修改成功。然后到合适的时候将redolog中的内容更新到磁盘中。(这样做将极大的提高更新的效率,客户端可以在较短的时间内得到反馈,而且存储引擎不再需要为每一次的更新操作都进行IO操作,可以存到一定的“量”,然后再刷新进磁盘里)。

redolog是固定大小的,写完则重头开始写,MySQL通过两个指针来控制redolog中的内容,分别是checkPoint(当前更新进磁盘的位置),writePoint(当前已经写到的位置),两个指针右移到末尾则又重新开始(checkPoint将指向的内容刷新进磁盘并右移,writePoint将新的更新操作写入并右移),显然,writePoint和checkPoint之间的位置就是可写位置,如果writePoint == checkPoint,说明redolog满了,这个时候就需要停下来将redolog中的内容刷新进磁盘里(这个时候MySQL的更新操作会变慢),让checkPoint向右移动,从而“腾出位置”继续写。

redolog的存在不仅提高了更新的效率,还保证数据的不丢失,如果MySQL发生异常重启,则可以加载redolog文件恢复数据。

3.归档日志(binlog)

binlog是Server层的日志文件,binlog与redolog,都是用来记录对数据做了什么修改,,但是有一定的区别:

记录的内容上:redolog是物理日志,记录的是具体在哪一个数据页(数据页是MySQL中磁盘和内存交换的基本单位,也是MySQL管理存储空间的基本单位,可以理解为一个数据页中有多行数据)做了什么修改,而binlog记录的更新语句的原始逻辑,比如在id=XXX的a字段上+1.

记录方式上:redolog是循环写,有固定的大小,binlog是追加写,一个文件用完切换到下一个,不会覆盖之前的数据。

实现的位置:redolog是存储引擎层实现的(innodb特有的一种日志),binlog是server层的日志,所有引擎都具有。

整合两个日志,重新梳理一下更新过程:

step1:建立连接(连接器)

step2:分析sql(分析器)

step3:优化过程,选择合适的索引来定位数据等等(优化器)

step4:调用引擎层接口去拿数据(执行器)

step5:存储引擎找到这一行,如果这一行所在的数据页就在内存中,直接返回这行数据,没有则从磁盘中读入内存,然后返回。

step6:执行器拿到数据,对该数据进行对应的修改,得到一行新的数据,然后调用引擎接口写入这行新数据。

step7:存储引擎直接将数据更新在内存中,并将这个操作更新到redolog中,redolog此时处于prepare状态。然后直接返回,表明随时可以提交。

step8:执行器将这个操作更新到binlog中,并更新进磁盘。

step9:执行器再次调用引擎接口,让引擎将刚刚的更新操作进行提交(redolog改成commit状态),整个更新过程完成。

为什么这样就能保证数据不丢失呢?或者说为什么redolog要分为prepare和commit两个状态(即两阶段提交)?

首先,如果redolog不分两个阶段,直接在step7直接提交,那么假如MySQL在执行step8的时候发生异常重启,则恢复过来后,这个更新操作是再redolog中是已提交的,则这个修改是最终会成功刷新进磁盘的,但是binlog中没有对应的记录,这将导致如果要使用binlog将数据库回退到某一个时刻的时候,“漏”了一条sql更新记录而导致数据回退的与那个时刻并不一致,或者做主从一致(通过binlog实现主从一致)时,从库从主库中拿到的binlog是“少”了一条sql记录的,这将导致主从数据不一致。(其实可以直接理解为binlog没有记录MySQL中的所有更新操作本身就是违背了binlog的设计的初衷)。

其次,如果先提交binlog也是不行的,如果先提交了binlog,再提交了redolog,提交redolog过程中发生异常重启,redolog中的数据没有提交从而丢失,则binlog则是“多”了一条数据操作。

但是如果是两阶段提交则能有效规避这些问题,比如step8中binlog提交过程发生异常,则redolog中记录的是出于prepare状态的,等MySQL恢复过来时,则认为这次更新是失败的,则会自动回滚这次操作。这样binlog中更新记录与数据库中的数据是可以对应上的。

最后,MySQL保证了binlog和redolog中的数据更新记录与真实数据操作是一致的,就可以保证数据不丢失(所有的更新操作都记录了,可以恢复到任意时刻),在做主从备份或者数据库备份时往往都是依靠binlog进行,所以关键便在于保证binlog的数据与数据库操作保持一致。(MySQL在保证数据不丢失上还有很多细节,这将在后续继续总结)。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值