oracle为什么不用double write ?
数据库,OS和磁盘读写的基本单位是块,也可以称之为(page size) block size。
数据库的块一般为8k,16k; OS的块则一般为4K; IO块更小,linux 内核要求IO block size <= OS block size.
磁盘IO除了IO block size , 还有扇区的概念(IO sector), 扇区是磁盘物理操作的基本单位, 而IO 块是磁盘操作的逻辑单位,一个IO块对应一个或多个扇区,扇区大小一般为512字节。
所以各个块大小的关系如下:
DB block > OS Block >= IO Block> Disk Block ,而且他们之间保持着整数倍的关系。比如DB 以mysql 为例, OS 以linux 为例:
DB block size
mysql> show variables like 'innodb_page_size';
| Variable_name | Value |
| innodb_page_size | 16384 |
1 row in set (0.01 sec)
OS block size
IO block size
Sector size
Sector size (logical/physical): 512 bytes / 512 bytes
从上面的结果可以看到 DB page=4OS page=16IO pages=32*sector size
由于任何DB page的写入,最终都会转为sector的写入,如果在写磁盘的过程中,出现异常重启,就可能会发生一个DB 页只写了部分sector到磁盘,进而出现页断裂的情况。
InnoDB 的page size 一般是16KB,其数据校验也是针对这16KB计算的,将数据写入到磁盘是以page为单位进行操作的。而计算机硬件和操作系统,在极端情况下(比如断电)往往并不能保证这一操作的原子性,16K的数据, 写入4K时,发生了系统断电/os crash , 只有一部分写是成功的,这种情况写就是partial page write。
很多DBA 会想到系统恢复后,Mysql 可以根据redo log 进行恢复, 而mysql 在恢复的过程中是检查page的checksum, checksum就是page的最后事务号,发生 partial page write 问题时, page 已经损坏,找不到改page的事务号,就无法恢复。
所以说,当page 损坏后,应用redo 是没有意义的,这时候无法使用redo 来恢复,因为游戏原始页已经损坏了,会发生数据丢失。
文章图片来源:游戏http://www.sangpi.com/
在InnoDB 将Buffer Pool 中的Dirty Page 刷到磁盘上时,首先会将(memcpy函数) page 刷到InnoDB system tablespace(ibdata1)的一个区域中,我们称该区域为double write buffer (大小为2MB, 每次写入1MB,128个页)。在向dwww.cungun.comouble write buffer写入成功后,第二步再将数据拷贝到数据文件对应的位置。
当第二步过程中发生故障,也就是发生partial page write的问题。 恢复的时候先检查页内的checksum是否相同,不一致,则直接从doublewrite中恢复
1)如果写doublewrite buffer失败,那么这些数据不会写到磁盘,innodb会载入磁盘原始数据和redo日志比较,并重新刷到doublewrite buffer。
2) 如果写doublewrite buffer成功,但是刷新到磁盘失败,那么innodb就不会通过事务日志来恢复了,而是直接刷新doublewrite buffer中的数据。
mysql> show variables like '%double%';
| Variable_name | Value |
| innodb_doublewrite | ON |
1 row in set (0.00 sec)
mysql> show status like '%innodb_dblw%';
| Variable_name | Value |
| Innodb_dblwr_pages_written | 5951 |
| Innodb_dblwr_writes | 1383 |