之前有网友希望我对mysql的double write和oracle能够做一个对比,其实这种对比方式挺好,能够触类旁通,举一反三。不过限于本人水平有限,欢迎拍砖。
关于MySQL的double write是对partilal write的一个补充。比如将数据写入磁盘的时候,发生了断电情况,那么一部分内容写入一部分就丢失了,这个时候使用redo log来恢复就不可行了,因为从日志文件层面数据的变更已经是不完整的了。
double write的大体是这样的。部分内容参考了链接 http://www.cnblogs.com/benshan/archive/2013/01/14/2859336.html
double write分为两部分,一部分是doublewrite buffer,大小为2M,另外一部分就是物理磁盘上的共享表空间中连续的128个页,即两个区,大小同样为2M。当缓冲池的胀业刷新时,并不直接写硬 盘,而是通过memcpy函数将脏页先拷贝到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次写,每次写入1M到共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘。
这个问题可以简单的归结为innodb恢复的原理,从这个层面来说和oracle还是存在着很大的不同。
首先double write是限于Innodb 存储引擎的,而且是作为一个可选的方案,通过参数InnoDB_doublewrite的值来控制,如果为0表示不启用,可以通过show status like "%InnoDB_dblwr%"来查看。
既然作为可选方案,肯定是有一定的原因,就是出于性能的考虑,位于共享表空间的double write buffer其实也是文件,写double write buffer本身也会有fsync操作,只是double write写入的过程是一个顺序写的过程,所以对性能降低不会太低。
oracle的恢复机制相比double wriite更加灵活和全面。
首先oracle中采用了undo+redo机制来作为数据恢复的基石,数据的恢复是通过前后台结合来实现的,在缓存级别,存在dbwr,能够把修改后的数据块刷入数据文件,这是一个异步的过程,不会因为发生数据变更就马上写入数据文件,同时存在log buffer,能够通过log buffer生成redo日志,最后通过lgwr把这部分变更刷到redo 日志,在这个过程中lgwr负责了保持数据完整性的任务,保证了数据在任何情况下都不会丢失。
上面的操作,写入数据文件的过程不是实时的,可以存在一定的延时,所以重点就放在了redo日志上面,在备份恢复方面还是最重要的。
如果在dbwr把数据变更的数据块写入数据文件的时候,如果发生断电的情况,当实例重新启动的时候,oracle会根据redo 日志构造出变更前的数据块信息,从而完成了前滚,把丢失的数据块找回来。这样数据库就恢复为了奔溃前的状态,如果某些事务没有提交或者回滚,又会继续做一个回滚操作。这个过程会通过smon来结合Undo来实现。
从整个过程来说,oracle支持的面很广,就如Oracle所承诺的那样,做了commit的数据就能够恢复。从IO消耗的角度来看,物理IO的消耗就在于刷新数据到数据文件,数据变更写入redo,没有额外的物理IO。
结合MySQL来看,double write buffer扮演的角色有点类似 log buffer的作用。因为oracle已经开辟了log buffer的缓存空间,所以缓存级的IO还是很快的,double write buffer就会存在部分的物理IO操作。
不过从技术的架构和角度来看,不能完全说出某一种好还是不好,从目前的分析来看,oracle相比double write还是技高一筹,不过从体系结构上要复杂的多。而且还涉及到更多的细节需要优化。