聊聊MySQL里面的undo Log、redo Log和bin Log日志的原子性和持久性已经复制和恢复数据实现过程

最近闲来无事自己突发奇想的想看一下MySQL的存储引擎,看了事务相关的ACID,想了解MySQL是怎么实现数据的持久性和数据的一致性,自己上网看了一下MySQL里边出现的几种常见的log,根据自己的了解写了这篇文章与大家分享,不足之处还望指出。

MySQL中比较常见的几种log为:
1、bin Log
2、undo Log
3、redo Log
当然面试当中MySQL中也是必问的题目,MySQL是开发当中用的比较的多的数据库,也是整个系统中最重要的一部分,相关底层问题也是比较多问。

直接开门见山吧

1、什么是big Log?
通俗一点就是我们的数据都是保存在数据库当中的,当我们对一个数据进行变更的时候,比如:
update user set name =‘张三’ where id = ‘1’
这个数据的变更是会记录到big Log日志当中去,于是我们就会监听big Log的变更,如果监听到big Log变更了,那就需要将变更的数据写到对应的数据库当中。
用户查询出来的数据是走搜索引擎的。为了让用户能搜到最新的数据,我们需要把引擎的数据也改掉。所以数据库的变更,搜索引擎的数据也需要变更。

big主要存储了数据结构和数据的变更,比如 update/delete/insert/truncate/create,另外select的数据不会进行记录,因为它不是操作变更的。

那这个big Log是怎么记录变更的数据的呢?
1.1 检验是否开启了big Log
show variables like ‘%log_bin%’ 首先使用这个命令查看是否开启了big Log,

在这里插入图片描述
1.2 如果没有开启的话使用以下的方式:
在这里插入图片描述
1.3 查看所有的bigLong
使用show master logs命令查看所有 bin Log 日志文件列表:
在这里插入图片描述
注意:bin Log 日志包括两类文件;第一个是二进制索引文件(后缀名为.index),第二个为日志文件(后缀名为.00000*),记录数据库所有的 DDL 和 DML操作,当然除了 select查询语句。
1.4 查看 bigLog的内容
使用 mysqlbinlog binlog_files
在这里插入图片描述

该方式不好观察,使用 show binlog events in ‘mysql-bin.000017’; 这种形式可以方便的观察内容。从指定索引位置开始查看: show binlog events in ‘mysql-bin.000017’ from 3183;
在这里插入图片描述
查询

show binlog events in ‘mysql-bin.000017’ from 3183 limit 2,4; 分页查询
又或者show binlog events in ‘mysql-bin.000017’ from 3183 limit 2,4; 分页查询
在这里插入图片描述
从上面的图片可以看出,bin Log我们可以简单理解为:存储着每条变更的SQL语句(当然从上面的图看来看,不止SQL,还有XID「事务Id」等等)。

2、使用bigLog恢复数据

2.1首先向表中插入一条数据
INSERT INTO liancan_order_summary (id, plan_id, business_outlets_id, user_id, user_name, dept_id, dept_name, sex, student_job_no, meals_type, order_status, order_way, order_operator_name, company_id, tenant_id, create_user, create_dept, create_time, update_user, update_time, status, is_del, version)
VALUES (‘136698720922’, ‘1366567339981574145’, ‘1366565872042283009’, ‘1366691815461265409’, ‘阿一’, ‘1303608208296366081’, ‘高二(6)班’, ‘1’, ‘TS2222222222’, ‘1366566360468983809’, ‘1’, ‘1’, ‘系统’, ‘1298166075598311425’, ‘0’, NULL, NULL, ‘2021-03-02 19:05:01’, NULL, NULL, NULL, ‘0’, ‘0’);
通过 show master logs;命令查看明显size增多了
在这里插入图片描述
2.2 恢复
2.2.1 通过 pos 恢复

在这里插入图片描述
其中标红的就是记录刚刚新增数据操作的那个 log。
2.2.2 查询日志: show binlog events in ‘mysql-bin.000017’ ;
在这里插入图片描述

3、恢复语句:
3.1 position 方式

/usr/bin/mysqlbinlog --start-position=52440044 --stop-position=52440957–database=liancan /var/lib/mysql/mysql-bin.000017 | mysql -uroot -p123456 -v
或者

3.2 time 方式

/usr/bin/mysqlbinlog --start-datetime=‘2019-10-25 17:00:35’ --stop-datetime=‘2019-10-25 17:01:42’ --database=bart /var/lib/mysql/mysql-bin.000017 | /usr/bin/mysql -uroot -p123456

4、bin Log一般用来做什么

主要有两个作用:复制和恢复数据

MySQL在公司使用的时候往往都是一主多从结构的,从服务器需要与主服务器的数据保持一致,这就是通过bin Log来实现的数据库的数据被干掉了,我们可以通过bin Log来对数据进行恢复。

因为bin Log记录了数据库表的变更,所以我们可以用bin Log进行复制(主从复制)和恢复数据。

2、什么是undo Log?
主要作用是回滚和多版本控制(MVCC)

MVCC,即多版本控制。在MySQL数据库InnoDB存储引擎中,用undo Log来实现多版本并发控制(MVCC)。当读取的某一行被其他事务锁定时,它可以从undo Log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据【快照读】。

在数据修改的时候,不仅记录了redo Log(这个放在后面讲),还记录undo Log,如果因为某些原因导致事务失败或回滚了,可以用undo Log进行回滚,undo log主要存储的也是逻辑日志,比如我们要insert一条数据了,那undo Log会记录的一条对应的delete日志。我们要update一条记录时,它会记录一条对应相反的update记录。

回滚嘛顾名思义就是跟需要修改的操作相反就好,这样就能达到回滚的目的。因为支持回滚操作,所以我们就能保证:“一个事务包含多个操作,这些操作要么全部执行,要么全都不执行”。【原子性】

因为undo Log存储着修改之前的数据,相当于一个前版本,MVCC实现的是读写不阻塞,读的时候只要返回前一个版本的数据就行了。

2.1 在InnoDB存储引擎中,undo Log有两种类型:

2.1.1 insert undo Log(记录的是insert 语句对应的undo Log)
指在insert操作中产生的undo Log,因为insert操作的记录,只对事务本身可见,对其他事务不可见(这是事务隔离性的要求),故该undo Log可以在事务提交后直接删除。不需要进行purge操作

下面看一下insert undo Log图片
在这里插入图片描述
insert undo Log开始的前两个字节next 记录的是 下一个undo log的位置,通过该next的字节 可以知道 一个undo log所占的空间字节数

类似地,尾部的两个字节start记录的是undo log的开始位置

type_cmpl占用一个字节,记录的是undo的类型,对于insert undo log,该值总是为11

undo_no记录事务的ID,table_id记录undo log所对应的表对象。这两个值都是在压缩后保存的

接着的部分记录了所有主键的列和值。在进行rollback操作时,根据这些值可以定位到具体的记录,然后进行删除即可

2.1.2 update undo Log(对应的是 update、delete 语句对应的undo Log)
记录的是对delete和update操作产生的undo Log该undo Log可能需要 提供MVCC机制,因此不能在事务提交时就进行删除,事务提交时放入undo Log链表,等待purge线程进行最后的删除。
在这里插入图片描述
update undo Log相对于之前介绍的insert undo log,记录的内容更多,所需占用的空间也更大

next、start、undo_no、table_id与之前介绍的insert undo log部分相同

这里的type_cmpl,由于update undo log本身还有分类,故其可能的值如下:

TRX_UNDO_UPD_EXIST_REC更新non-delete-mark的记录
TRX_UNDO_UPD_DEL_REC将delete的记录标记为not delete
TRX_UNDO_DEL_MARK_REC将记录标记为delete

接着的部分记录update_vector信息,update_vector表示update操作导致发生改变的列。每个修改的列信息都要记录的undo log中。对于不同的undo log类型,可能还需要记录对索引列所做的修改

3、什么是 redo Log?
redo Log重做日志)是InnoDB存储引擎独有的,它让MySQL拥有了崩溃恢复能力。
假如有这么一条数据:

update user_table set name=‘张三’ where id = ‘1’
那么这条语句是怎么执行怎么存入log的呢?

按照我们正常的理解肯定是先把id=1的这条记录查出来,然后将name字段给改掉。是这样吧,就这么简单的实现,其实底层的话是这样的:

实际上MySQL的基本存储结构是页(记录都存在页里边),你查询一条记录,会从硬盘把一页的数据加载出来,加载出来的数据叫数据页,会放入到Buffer Pool中。

后续的查询都是先从Buffer Pool中找,没有命中再去硬盘加载,减少硬盘IO开销,提升性能。

更新表数据的时候,也是如此,发现Buffer Pool里存在要更新的数据,就直接在buffer Pool里更新。

然后会把“在某个数据页上做了什么修改”记录到重做日志缓存(redo log buffer)里,接着刷盘到redo Log文件里。

现在就可能存在一个问题:如果在内存中把数据改了,因为宕机了还没来得及落磁盘,而此时的数据库挂了怎么办?很明显数据就找不到了!
在这里插入图片描述
问题是如果每次有数据请求过来都必须要磁盘,那速度会非常的慢,这里就引出了上面所说的redo Log了,当有数据请求过来内存中写入数据,然后会在redo Log中记录一份该数据,redo Log记载着这次在某个页上做了什么修改,以下图片:
在这里插入图片描述
写redo log也是需要写磁盘的,但它的好处就是顺序IO,顺序IO比随机IO快非常多。

那到底是什么时候刷盘呢?
刷盘时间
InnoDB存储引擎为redo Log的刷盘策略提供了innodb_flush_log_at_trx_commit参数,它支持三种策略
innodb_flush_log_at_trx_commit = 0,表示每次事务提交时不进行刷盘操作
innodb_flush_log_at_trx_commit = 1,表示每次事务提交时都将进行刷盘操作(默认值)
innodb_flush_log_at_trx_commit = 2,表示每次事务提交时都只把redo log buffer内容写入page cache

下面是不同刷盘时间流程图:
innodb_flush_log_at_trx_commit = 0,表示每次事务提交时不进行刷盘操作,为0时,如果MySQL挂了或宕机可能会有1秒数据的丢失。
在这里插入图片描述
innodb_flush_log_at_trx_commit = 1,表示每次事务提交时都将进行刷盘操作(默认值),为1时, 只要事务提交成功,redo log记录就一定在硬盘里,不会有任何数据丢失。
在这里插入图片描述
innodb_flush_log_at_trx_commit = 2,表示每次事务提交时都只把redo log buffer内容写入page cache,为2时, 只要事务提交成功,redo log buffer中的内容只写入文件系统缓存(page cache)。
在这里插入图片描述
最后看完以后是不是会觉得bin Log和redo Log很相像呢,其实还是有不一样的地方,比如:

存储内容:
从上面的介绍可以知道bin Log记载的是 update/delete/insert/truncate/create这样的SQL语句,而redo Log记载的是物理修改的内容(xxxx页修改了xxx)。

功能:
redo Log的主要作用是持久化。写完内存,如果数据库挂了可以通过redo Log来恢复内存还没来得及刷到磁盘的数据,将redo Log加载到内存里边,那内存就能恢复到挂掉之前的数据了。

bin Log的作用是复制和恢复数据。

比如多master和多slave1,slave2的主从服务器需要保持数据的一致性,可以通过bin Log来同步数据。

如果整个数据库的数据都被删除了,bin Log存储着所有的数据变更情况,那么可以通过bin Log来对数据进行恢复。

最后一个问题:如果我把数据库的数据都删除掉了可以使用redo Log的日志记录来恢复这些数据吗?

因为redo Log存的是物理数据的修改,如果我们内存的数据已经刷到了磁盘了,那redo Log的数据就无效了。而redo Log不会存着以前的所有数据的变更,日志文件的内容会被覆盖的,所以不能恢复。
数据就无效了。所以redo log不会存储着历史所有数据的变更,文件的内容会被覆盖的。

最后

粗略的把bin Log /redo Log/undo Log给讲了一遍,还有别得没有深入去讲,大家可以补充没有讲的呢

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值