神图镇楼:
mysql体系结构大概由一下几个部分组成:
1、连接池组件
2、管理服务和工具组件
3、SQL接口组件
4、查询分析器组件
5、优化器组件
6、缓冲组件
7、插件式的储引擎
8、物理文件
Mysql数据库区别于其他数据库的最重要的一个特点就是插件式的存储引擎,存储引擎是基于表的,而不是基于数据库的,这个概念很容易混淆。说到存储引擎,就不得不说innodb,今天主要说说Innodb中的一个关键特性,也就是两次写。
之前的文章中提到过,Innodb中内存和硬盘的交互是通过数据页实现的,这种方式存在一定问题。当发生数据库宕机,可能innodb正在写入某个数据页到表中,而这个数据页只写了一部分,这种情况我们称之为"部分写失效",很容易出现数据丢失的问题。
这种情况下,我们可能会想到通过redo log进行恢复,这是一个办法,但是也存在一些小问题,因为redo log记录的是对数据页的操作,如果这个数据页已经发生了损坏,这种情况下对数据页进行重做是没有意义的,我们必须保证有一个数据页的副本,通过数据页的副本来还原这个数据页,再进行重做,这就是我们所说的二次写,也称之为doublewrite。它的流程图如下:
对于上面这个图,解释如下:
我们看到的double分为两个部分,其中一个是内存中的,大小为2MB,另外一部分是物理磁盘的共享表空间中的,也就是ibdata文件中的连续的128个数据页,128*16K,也就是2MB,在对缓冲池的脏数据进行刷盘的时候,并不会直接写到磁盘中,而是先将数据复制到内存中的doublewrite的缓存中,之后通过缓存,再分两次,每次1MB的写入共享表空间的物理磁盘上。完事儿之后然后立马同步磁盘。这样,一份数据就在磁盘上有两个副本。
在上面的过程中,从数据页往内存中的doublewrite缓冲中写入数据是顺序的,相对来讲比较快,而从内存中的doublewrite落盘时候是离散的IO,相对来讲比较慢。如果在写入磁盘的时候出现了问题,innodb将会在共享表空间的doublewrite中找到该数据页的一个副本,将其复制到表空间文件,再应用重做日志,也就是redo log。
通过这种方式,可以在数据真实落盘之前防患于未然,一旦刷盘的动作失败,可以从共享表空间中找到副本进行恢复。我们都知道,ibdata文件一般比较大,如果你可以接收刷盘失败带来的损失,也可以使用skip_innodb_doublewrite来禁止使用doublewrite的功能,这个参数也可以改进一些性能问题。