Mysql专栏 - redo log日志细节
来源:SegmentFault
时间:2023-01-27 19:11:20 440浏览 收藏
对于一个数据库开发者来说,牢固扎实的基础是十分重要的,golang学习网就来带大家一点点的掌握基础知识点。今天本篇文章带大家了解《Mysql专栏 - redo log日志细节》,主要介绍了MySQL,希望对大家的知识积累有所帮助,快点收藏起来吧,否则需要时就找不到了!
概述
redo log 日志在介绍整个innodb的存储引擎结构的时候进行过介绍,本节将会继续深入redo log了解内部的结构了解内部的基础存储结构,同时了解关于redo log写入到磁盘的时机,并且了解redo log的日志有几个,
为什么要引入redo log?
说白了是为了保证mysql宕机的时候,数据恢复可以按照顺序的恢复方式而不是随机读写,redo log也是保证事务一致性的关键组件。
Redo log写磁盘的过程
Redo log存放的内容
存放的内容如下:表空间号+数据页号+偏移量+修改几个字节的值+具体的值,为了使表示数据页的内容修改了几个字节的值, redo log使用了类型划分:
- Mlog_1byte:表示修改了1个字节
- Mlog_2byte:表示两个
- 以此类推的4字节和8字节
- 如果修改了很多:mlog_write_string
所以一条redo log的格式如下:
日志类型(就是类似MLOG_1BYTE之类的),表空间ID,数据页号,数据页中的偏移量,具体修改的数据
下面是对应的数据结构图:
Redo log block 存放数据页
Redo log不是按照单行写入日志文件的,而是使用block来进行管理,一个redo log block 为512字节。内部包含了12字节的header块,496字节的body块,和4字节的trailer 块尾,而12个字节的数据头又包含了:4个字节的块编号,2个字节写入的数据长度,2个字节第一个日志的分组偏移量,4个字节的check point no,最终他的数据结构如下
redolog行如何存储
在写入数据的时候,redo log一行日志是如下的形式进行写入的,由于redo log并不是单行存储,而是使用连续的512字节的block块进行存放的,当然这个操作是在内存中的redolog buffer中完成,当缓冲池中一个块被写满之后,是肯定需要刷入到磁盘的,所以此时会有一个后台线程不断的把数据写入到redo log的磁盘文件中,最终他的效果就如同下面这般:
上面我们介绍的redo log一行的存储结构,在这里就可以派上用场,redo log的行数据不断写入到body到数据块里面,并且后台线程不断的把数据刷新到磁盘当中,当一行数据的不断写入,到达一个block块的大小的时候,就需要把它写入到磁盘的文件里面,写入完成之后,内存完成操作,将会把数据写入到具体的磁盘对应的块里面也就是磁盘文件的内部。
redo log buffer存储redo log block
Redo log的数据和缓冲池一样也是使用缓存的方式刷入到磁盘的,redo log buffer会在mysql启动的时候申请一块连续的内存空间来存放 redo log block,他的格式如下所示:
我们可以设置参数:innodb_log_buffer_size 来指定redo log buffer的大小,默认值为16mb,这个大小足够大了,毕竟一个block为512字节,在执行大批量数据操作的时候,可能会出现多个redo log 为一组的情况,也就是数据跨越了多个redo log页进行存储。
Redo log 日志什么时候写入磁盘
关于这个内容我们需要了解下面两个问题:
- Redo log日志文件有几个?
- Redo log block什么时候会把数据刷入到磁盘?
刷新到磁盘的时机
mysql触发下面的条件的时候会把redo log buffer 刷新到磁盘当中:
- 超过redo log buffer 的一半大小
- Redo log需要在事务提交的时候,需要把redo log对应的redo log block刷新到磁盘中,同时为了保证事务正确提交,redo log存在重做日志。
- 后台线程1秒一次刷新数据到磁盘
- mysql关闭会把redo log 全部刷新到磁盘
这里需要记住一个重点:只有在redo log 的内容刷新到磁盘,事务提交才算是成功,只有这样才能算是事务的正确。
实际上默认情况下redo log都会写入一个目录中的文件里,这个目录可以通过
show variables like 'datadir'来查看,可以通过innodb_log_group_home_dir参数来设置这个 目录的。
Redo log日志文件有几个
redo log是有多个的,写满了一个就会写下一个redo log,而且可以限制redo log文件的数量,通过innodb_log_file_size可以指定每个redo log文件的大小,默认是48MB,通过 innodb_log_files_in_group可以指定日志文件的数量,默认就2个,也就是96MB,可能看上去很小,但是实际上这个文件数量存个百万千万的数据完全不是问题。
所以在上面提到的目录中里就两个日志文件,分别为ib_logfile0和ib_logfile1,每个48MB,最多就这2个日志文件,就是先写第一个,写满了写第二个,那第二个写满了怎么办?继续回去写第一个即可。
如果不想使用默认的大小如何处理呢,其实调节上述两个参数就可以了,比如每个redo log文件是96MB, 最多保留100个redo log文件等等。
Undo log配合 redo log进行日志回滚
Undo log需要配合redo log进行下面的记录操作:
- 删除需要把删除之前的数据插入回去
- 更新需要旧值更新回去
- 新增需要把新增之后的数据删除掉
最终undo log日志的结构如下:
Redo log并发问题
多个事务并发执行的时候,可能会同时对缓存页里的一行数据进行更新,这个冲突怎么处理?是否要加锁?可能有的事务在对一行数据做更新,有的事务在查询这行数据,这里的冲突怎么处理?
脏写、脏读、不可重复读、幻读(重点)
1. 脏写
根据下面的图我们说下脏写,当事务A更新一行事务B准备更新的数据,在事务A更新之后事务B执行了更新操作,然后A更新完成之后却回滚了,并且在B更新之后把值改了回去。这样的操作结果就是:B操作完结果却是NULL,本质就是事务B更新了一个事务A操作过的数据,结果事务A没有提交,但是一旦更新会随时影响事务B的操作结果。
2. 脏读
用最简单的话其实就是一个事务读到了一个未提交的值,而一旦这个值失效就会出现业务的问题。
其实一句话总结,无论是脏写还是脏读,都是因为一个事务去更新或者查询了另外一个还没提交的事务 更新过的数据。因为另外一个事务还没提交,所以他随时可能会反悔会回滚,那么必然导致你更新的数据就没了,或者你之前查询到的数据就没了,这就是脏写和脏读两种坑爹场景。
3. 不可重复读:
不可重复读:在第一次进行查询的时候没有任何干扰
事务B进行更新+提交事务,同时修改一个值,然而A再去读和上一次不一样了
然后C也插进来,又把这个值给更新了,然后A又去读了一次,又发现不一样了
不可重复读并不是严重的问题,但是取决于数据库如何设计,因为重复读取一个值发生改变或者不改变要根据数据库的设计者来决定。
这里有两种方案:
- A事务读取之后,除非他提交事务,否则BC不能做任何更改,或者A读取一次之后就不会再读取第二次,或者多次读取的值都是相同的,也称为不可重复读
- 可重复读就是上面图表的情况。
4. 幻读
幻读指的就是你一个事务用一样的SQL多次查询,结果每次查询都会发现查到了一些之前没看到过的数据,幻读就是读到了别人没有提交过的数据。
不可重复读和幻读到底有什么区别呢?
(1) 不可重复读是读取了其他事务更改的数据,针对update操作
解决:使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据。
(2) 幻读是读取了其他事务新增的数据,针对insert和delete操作
解决:使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。
这时候再理解事务隔离级别就简单多了呢。
mysql的四种隔离级别:
- read uncommitted(读未提交)
- read committed(读已提交)
- repeatable read(可重复读)
- serializable(串行化)
隔离级别的特性:
- 读未提交:不允许脏写发生。其实就是说可以防止两个线程同时更新一个值。但是不防其他任何内容
- 读已提交:不允许脏写和脏读,也是即可防止两个线程同时更新一个值,又可以防止两个值同时读同一个值,也就是一个值肯定读不到另一个未提交的事务改动的数据情况。但是可能会多次读到一个值被提交到事务不断改动的情况
- 不可重复读:也就是可以防止脏写、脏读、不可重复读这三个层级在Mysql中的体现就是,同一个事务无论读多少次都不会读到已经提交的业务。但是会出现读取到其他事务新增或者删除的数据
- 串行化:完全同步,每次操作都只允许一个线程访问
总结
本节深入了redo log的内部细节,并且简单介绍了undo log是如何配合redo log进行回滚操作的,以及事务的ACID特性的细节内容,最终我们简单回顾了mysql的四种隔离级别以及对应的问题。
写在最后
可以看到redo log的内容结构还是有些复杂的,但是我们只需要基础了解即可,如果需要继续深入需要更多的阅读源代码并且进行总结和消化。
终于介绍完啦!小伙伴们,这篇关于《Mysql专栏 - redo log日志细节》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布数据库相关知识,快来关注吧!
-
499 收藏
-
244 收藏
-
235 收藏
-
157 收藏
-
101 收藏
-
485 收藏
-
113 收藏
-
293 收藏
-
365 收藏
-
247 收藏
-
188 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 风中的月饼
- 这篇博文太及时了,很详细,很好,已加入收藏夹了,关注大佬了!希望大佬能多写数据库相关的文章。
- 2023-06-16 23:22:04
-
- 舒服的水杯
- 很有用,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢师傅分享文章内容!
- 2023-03-20 18:14:07
-
- 美好的煎蛋
- 写的不错,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢老哥分享博文!
- 2023-02-27 13:35:38
-
- 妩媚的砖头
- 这篇博文太及时了,好细啊,受益颇多,已加入收藏夹了,关注老哥了!希望老哥能多写数据库相关的文章。
- 2023-02-23 06:32:05
-
- 舒适的电脑
- 好细啊,已加入收藏夹了,感谢作者大大的这篇文章内容,我会继续支持!
- 2023-02-03 20:03:04
-
- 淡然的萝莉
- 太详细了,已收藏,感谢师傅的这篇文章,我会继续支持!
- 2023-01-28 02:24:39