今天主要介绍下mysql一个崩溃恢复很重要的特性-重复写入。
doublewrite缓冲区是位于系统表空间中的存储区域,在该区域中,InnoDB会在将页面写入数据文件中的适当位置之前,从InnoDB缓冲池中刷新这些页面。仅在刷新页面并将其写入doublewrite缓冲区后,InnoDB才会将页面写入其适当位置。如果在页面写入过程中发生操作系统,存储子系统或mysqld进程崩溃,InnoDB稍后可以在崩溃恢复期间从doublewrite缓冲区中找到该页面的良好副本。
部分页面写
InnoDB的页面大小通常是16KB,其数据校验也是针对这16KB来计算的,将数据写入到磁盘并以页面为单位进行操作的。而计算机硬件和操作系统,在极端情况下(有时断电) )通常并不能保证这一步的原子性,16K的数据,写入4K时,发生了系统断电/ os崩溃,只有一部分写是成功的,这种情况下就是局部页面写问题。
很多DBA会想到系统恢复后,MySQL可以根据redolog进行恢复,而mysql在恢复的过程中是检查页面的校验和,checksum就是pgae的最后事务号,发生部分页面写问题,页面已经损坏,找不到该页面中的事务号,就无法恢复。
double white原理
Double write是InnoDB在表空间上的128个页(2个区)是2MB;
其原理:
为了解决部分页写问题,当mysql将脏数据刷新到数据文件的时候,先使用内存复制将脏数据复制到内存中的double write buffer,之后通过double write buffer再分2次,每次写入1MB到共享表空间,然后立即调用fsync函数,同步到磁盘上,避免缓冲带来的问题,在这个过程中,doublewrite是顺序写,不会大小写大,在完成doublewrite写入后,在将double write buffer写入各个表空间文件,这时是离散写入。
如果发生了极端情况(断电),InnoDB再次启动后,发现了一个页面数据已经损坏,那么此时就可以从doublewrite buffer中进行数据恢复了。
double对性能的影响
在共享表空间上的双重写缓冲区实际上也是一个文件,写DWB会导致系统有更多的fsync操作,而硬盘的fsync性能,所以它会降低mysql的整体性能。但是并不会降低到原来的50%。这主要是因为:
1)double write是一个连接的存储空间,所以硬盘在写数据的时候是顺序写,而不是随机写,这样性能更高。
2)将数据从双写缓冲区写入到真正的segment中的时候,系统会自动合并连接空间刷新的方式,每次可以刷新多个页面;
如果页面大小是16k,那么就有128个页面(1M)需要写,但是128个页面写入到共享表空间是1次IO完成,则doublewrite写入是1 + 128次。其中128次是写数据文件表空间。
doublewrite写入是顺序的,性能开销转化为量,通常5%-25%的性能影响。
double在恢复的时候是如何工作的?
如果部分页面写入doublewrite缓冲区本身,则原始页面仍将保留在磁盘上的实际位置。
如果是写双写缓冲区本身失败,那么这些数据不会被写入磁盘,InnoDB此时会从磁盘加载原始数据,然后通过InnoDB的事务日志来计算出正确的数据,重新写入到双写缓冲区。
当InnoDB恢复时,它将使用原始页面而不是doublewrite缓冲区中的损坏副本。但是,如果双写缓冲区成功并且对页面实际位置的写入失败,则InnoDB将在恢复期间使用双写缓冲区中的副本。
如果doublewrite buffer写成功的话,但是写磁盘失败,InnoDB就不用通过事务日志来计算了,或者直接用buffer的数据再写一遍。
InnoDB知道页面何时损坏,因为每个页面的末尾都有一个校验和。校验和是最后要写入的内容,因此,如果页面的内容与校验和不匹配,则页面已损坏。因此,恢复后,InnoDB只会读取doublewrite缓冲区中的每个页面并验证校验和。如果页面的校验和不正确,它将从其原始位置读取页面。
在恢复的时候,InnoDB直接比较页面的校验和,如果不对的话,就从硬盘加载原始数据,再由事务日志开始推演正确的数据。所以InnoDB的恢复通常需要花费时间。
重复写相关参数
InnoDB_doublewrite = 1表示启动双写,显示状态为'InnoDB_dblwr%'可以查询双写的使用情况;
#是否开启double write
mysql>显示类似'%double%write%'的变量;
#Double write的使用情况
mysql>显示状态,例如“%InnoDB_dblwr%”;
InnoDB_dblwr_pages_write#从bp刷新到DBWB的个数
InnoDB_dblwr_writes#写文件的次数
每次写操作合并page的个数= InnoDB_dblwr_pages_write / InnoDB_dblwr_writes
是否一定需要重复写
在某些情况下,确实没有必要使用doublewrite缓冲区-例如,您可能想在从属服务器上禁用它。另外,某些文件系统(例如ZFS)本身也会执行相同的操作,因此InnoDB这样做是多余的。您可以通过将InnoDB_doublewrite设置为0来禁用双写缓冲区。
1,Fursion-io原子写,如果每次写16k就是16k,每次写都是16k不会出现部分写partial write写4k的情况。
2,特定的文件系统(b-tree文件系统),支持原子写。