《MySQL运维内参》节选 | InnoDB日志管理机制(五)

网友投稿 857 2022-10-05

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

《MySQL运维内参》节选 | InnoDB日志管理机制(五)

《MySQL运维内参》导读

作者签名预售活动 | 预售进行中,五一左右发货关于《MySQL运维内参》的内容前言 | 周彦伟前言 | 王竹峰推荐序 | 甘泉推荐序 | 王瀚漓推荐序 | 韩朱忠推荐序 | 盖国强《MySQL运维内参》| 目录节选 | Binlog中的时间戳(上)节选 | Binlog中的时间戳(下)节选 | InnoDB数据字典(上)节选 | InnoDB数据字典(中)节选 | InnoDB数据字典(下)节选 | InnoDB日志管理机制(一)节选 | InnoDB日志管理机制(二)节选 | InnoDB日志管理机制(三)节选 | InnoDB日志管理机制(四)

前面几篇连载讲述了Buffer Pool以及日志的基础内容,接下来,讲述的是基于日志的想象,理解,以及它的存储格式。

日志的意义在哪里?

上面已经讲述过,日志是在逻辑事务对数据库做DML操作时,其所包含的物理事务MTR所记录的针对所有涉及到的Buffer Pool页面的修改记录。

为了更好的讲述日志的意义,这里通过下面几个方面来更好的说明。

假如没有写日志

假如没有写日志,那数据库在做了任何修改之后,必须要直接将Buffer Page刷磁盘,不然如果此时数据库挂了,即使事务被提交了,这些修改还是没法恢复。这将带来的灾难是,IO大量增加,这个时候的数据库,相当于是一个简单的文件系统,无论写什么数据,都必须马上刷入磁盘,Buffer Pool的作用可能只是一个用来修改文件页面的临时缓存而已。

假如没有写日志,在数据库做了DML操作之后,数据库可能在事务没有提交时就将Buffer Page刷到磁盘了,但此时需要回滚,而我们知道,回滚段的内容也是通过Buffer Pool管理的,它的每个页和B树页面是一样的,只是作用不一样而已,由此可知,回滚段数据也是通过REDO日志来保证完整性的。那么如果没有了日志,Buffer Page中的回滚段页面也需要直接写入,没有了任何缓存,性能会非常低。

假如没有写日志,数据库在关闭(挂掉)后再启动时,就不需要做REDO操作了(因为没有写日志),但需要做UNDO操作,因为UNDO不是通过REDO来恢复的,而是自己写入了(假设每次写Buffer Page之后都直接刷盘了),所以回滚段是有效的,还可以让没有提交的事务回滚掉(因为如果一个事务修改的页面很多的话,肯定会有一部分页面先刷掉的,所以有可能需要回滚),勉强还可以保证数据库的完整性。

综合上面的假设,现在已经明白,日志的作用就是用来保证Buffer Pool页面的数据写入不丢失,反过来说,如果每个Buffer Pool中的Page每次都刷入到磁盘了,这样就不需要REDO日志了,此时这个数据库就是一个文件系统了,因为Buffer Pool每次都刷,相当于每次写完直接写文件。所以说,日志,是数据库管理系统与文件系统的最核心的区别。

所以如果没有日志,数据库的性能就低到完全没法用了,因为IO太大了,同时,这种IO操作都是随机写入,很容易导致IO到达瓶颈,所以为了提高数据库性能,就必须要使用到REDO日志机制。

使用日志能提高性能的关键原因,有以下三方面:

1. 因为日志是用来记录Buffer Pool中Page的修改记录的,把对Page的写入转化为对日志的写入,那此时Page就不需要每次都刷盘,写Page页面只需要在内存中写入即可,性能会非常好。

2. 通常,一个页面是16K,如果不写日志的话,每次的写入单位还是16K,即使修改很少量的数据,也是如此,这样会导致无效IO非常严重,反过来说,也只有通过日志机制,才能真正体现出真实写入的数据量,不会存在对IO的浪费,Page的刷盘数量会大大减少。

3. 如果没有日志就会每次都刷Page,而这些Page的相对位置是乱的,并不是顺序的,刷盘大多都是随机IO,这对于机械硬盘,性能是非常差的,而有了日志,巧妙的将随机IO转化成了日志的顺序IO,这将大大的提高IOPS,性能会非常好。

日志文件大小区别

使用日志对数据库的性能有很大的影响,那日志还有什么其它的因素会影响数据库的性能呢?那就是日志文件空间容量。

现在已经知道,日志在设置好后其容量是固定的,它是循环使用的,如果不够用了,引发的事件是做一个检查点,让最小有效的LSN向前推,让出一部分空间给新产生的日志来使用,也就是说,只要这个日志空间未用完,那么Buffer Pool中的Page将会一直不刷盘(因为还有其它的刷盘时机,所以这里单指因为日志不够用导致检查点的刷盘),任何修改都是在内存中发生的,那么下面做一个计算。

假如当前日志容量设置为128M,某一个DML操作只针对某一行记录一直做修改操作。每次操作产生日志量为1KB(包括Buffer中数据页面的修改及UNDO记录的产生),这样算下来,128M的日志量可以容纳对这条记录的131072(128M/1K)次修改,也就是说,在这么多次修改之后,这个页面才需要刷盘,才会产生一次随机刷盘操作。而如果把日志文件设置为1280M,很容易知道,这将容纳对这条记录的1310720次修改,这么多次修改只产生一次随机刷盘操作,而如果还是128M的话,需要10次随机刷盘。很明显,日志容量对数据库的性能还是有很大影响的。

但也不是设置的越大越好,这里有两点需要注意:

1. 如果设置的非常大,固然性能可能会很好,但如果某一天(真的有可能到来),数据库异常挂了,此时可能有很多的日志都没有刷盘,也就是Log flushed up to与Last checkpoint at两个值之间相差太多,恢复起来,可能需要比较长的时间。但这个一般问题不大,本身挂的机率不大,同时REDO日志的恢复是顺序的,都是根据页面号的大小排序恢复的,所以比较快。同时在以后的MySQL版本中,会有多线程REDO恢复(听说的),这样就更快了,所以这一点不需要太多担心。

2. 日志容量大小的设置,最好要与Buffer Pool的总大小匹配,假如日志容量太小,Buffer Pool太大,那么这样的一个后果是导致Buffer Pool频繁做检查点,大的Buffer Pool不能被好好的利用。如果是日志容量很大,而Buffer Pool很小,此时Buffer Page经常会被淘汰出去,增加了IO频次,同时如果数据库意外挂掉,Buffer Pool小的话恢复起来也会比较慢。一般情况下,Buffer Pool的总大小与日志容量的大小比例最好保持在10~5:1的范围内。

日志的格式

前面已经讲述了太多的日志相关的内容了,这一节将要讲一下,具体到一个日志记录时,它是如何组织的,一条日志记录,究竟存储了什么?在这里都会说清楚。

前面已经讲到,InnoDB的日志是具有逻辑意义的物理日志,所以日志记录的格式就不完全是物理信息,而是有一定的逻辑意义,首先看一个基本的格式,如下图所示:

图中各个列代表的意义如下:

Type:日志类型,是一个日志记录的最高位,只占一个字节的空间。Space:表空间ID值,如果是系统页面(UNDO页面,或者是字典表页面),则是0,如果是索引页面,则是这个索引所在的表空间ID值。Offset:在上面Space所指定的文件中的页面号,以页面大小为单位,它是第几个页面(从0开始计数),则这个Offset就是几。Data:表示这条日志记录对应的数据,这个数据是不确定的,根据不同的Type值而不同,分别具有自己的格式。

Type类型有很多,下面列举一些在InnoDB中比较常用的类型,并简单做一些解释,以便可以更好的理解。InnoDB中的REDO,究竟是在做什么?究竟是存储了什么内容?功能是什么?知道每个类型之后,这些问题也就清楚了。

注:下面讲到的数据记录,都是以Compact格式的记录为对象的,其它类型这里不考虑。

上面讲述的是,InnoDB存储引擎中,REDO日志的一部分类型,并对不同类型做了解释。从解释中可以看到,基本上每一个类型其实都是具有逻辑意义的,与DML相关的类型中,不是存储了列数据,就是存储了记录在页面内的偏移等信息。

这样做的优点有:

可以写REDO解析工具,去做一个第三方的同步工具,或者了解数据库做了什么操作,类似Binlog内容,但侧重点不同。日志占用空间比全物理日志少。

最大的缺点就是系统首先要保证日志对应的页面的正确性,否则会造成逻辑日志执行不成功,或者造成数据的不一致等问题,这个问题在InnoDB中的解决方式,就是后面介绍的Double Write机制。

本文就此结束,接下来继续连载,讲述有关日志的其他内容。

上一篇:分布式作业系统 Elastic-Job-Lite 源码分析 —— 运维平台
下一篇:赶紧收藏,某公司中级运维工程师笔试题
相关文章

 发表评论

暂时没有评论,来抢沙发吧~