之前的文章中,我们介绍过innodb的两次写特性,这里给出链接:
InnoDB的两次写特性
今天我们完善一下这部分的内容。
我们知道innodb数据页的默认大小是16kb,磁盘和内存通过数据页进行交互,在数据库关闭的时候,innodb会将内存中的数据脏页刷新到磁盘上。如果在刷新的过程中,数据页发生了损坏,那么我们就无法使用redo log进行数据页的恢复了。想要使用redo log进行数据恢复,首先要保证数据页的完整性,Innodb的两次写就是为了解决数据页损坏的问题的,它基于一种备份的思想,在数据页刷盘之前先备份一份在两次写文件中,然后再进行数据刷盘。
单一页面的刷盘方法上面的文章中提到了,我们今天主要看在批量场景下innodb是如何使用两次写机制的。
在单一页面的刷盘过程中,因为要先将数据页从内存中的doublewrite_buffer刷到ibdata中,然后再从内存中刷到磁盘上,相当于磁盘IO次数增加,会导致数据库的性能变差(安全和方便从来都是双刃剑)。引入了批量刷盘之后,如果还采用单一页面刷盘过程,那么性能肯定会急剧下降。在MySQL5.7中,innodb设置了最小的批量缓存单元,简称shard,该缓存单元隶属于innodb buffer pool的每个instance,每个instance都有独立的shart。与此同时,innodb引入了参数innodb_parallel_doublewrite_path和innodb_doublewrite_batch_size,其中第一个参数指的是“两次写”磁盘文件的绝对路径,第二个参数指的是shard的大小。
批量刷盘一般采用LRU的方法淘汰冷数据页,当需要批量刷盘的时候,innodb会判断当前页面所属的instance,然后找到对应的shard,查看当前shard是否已满,如果没满,则将数据页内容添加复制到该shard中。如果添加完成之后,shard已经写满,此时需要将shard缓存的数据页写入到两次写文件中,写完之后再将两次写文件flush到磁盘中,最后将对应的真实页面刷盘。由于是连续写入多个页面,所以性能比写多次,每次写一个页面要好。
数据恢复的时候,如果需要修复数据页,那么innodb将会从"两次写"磁盘文件中读取所需要的页面,加载到内存中去,然后在此基础上继续做redo log的应用。
最后,之所以需要"两次写",是因为磁盘写入的时候,是以512字节为单位的原子写入,不能保证16kb的数据页一次性原子写入,如果能保证每次写入16kb的数据页原子写入,那么"两次写"也就失去了意义了。
有帮助的话还希望点下再看哈