信息荟萃
    你的位置:首页 > 信息荟萃

    突然停电了,我的数据还没保存到数据库……

    来源:誉澄智能 2021/1/5 8:53:47      点击:

    最近看到全国各地都在“拉闸限电”,吓的我赶紧登上后台服务器,看了看MySQL数据库是否有问题,还好一切如常,也没听说北京有停电通知,好歹松了一口气。

    微信图片_20210105084913.jpg

    忽然想到一个问题,万一数据库正在执行写入操作,突然断电了,会是怎么样的呢?


    从MySQL V5.5开始,InnoDB成为了默认的存储引擎。InnoDB中将页作为磁盘管理的最小单位,数据校验和数据写入到磁盘都是以页为单位操作的,通常情况下默认每个页的大小为16KB。但由于文件系统对数据页(16KB)的写入多数情况下都不是原子操作,意味着当服务器断电时可能只写了部分数据。


    一个数据页的大小是16K,假设在把内存中的脏页(页中有记录被更新过)写到磁盘时,写了2K突然掉电,则前2K数据是新的,后14K是旧的,那么磁盘中的这个数据页就是不完整的,是一个坏掉的数据页。


    可能有经验的DBA会想到,如果发生写失效,可以利用redo log进行恢复。


    这也许能够解决部分问题,但redo log中记录的是对页的物理操作,redo log只能加上旧的、校检完整的数据页恢复一个脏块,不能修复坏掉的数据页。如果数据页本身已经发生了损坏,再对其进行重做是没有意义的。

    那么就没有其它办法了吗?当然不是!这个时候double write就闪亮登场了。


    开启了Double write(两次写/双写)后,在将内存中的脏页写入到磁盘之前,会先保存该页的副本,当磁盘中的数据页坏掉时,可以利用副本来还原该页,再执行重做,这就完美的解决了redo log无法修复坏页的问题啦。


    Double write由两部分组成,一部分是内存中的double write缓存,共有128个页(2MB);另一部分是磁盘上共享表空间中连续的128个页(2MB)。


    下面我们来看一下将数据页写入磁盘的过程:

    1 拷贝:当一系列机制触发数据页缓冲池中的脏页(图中黄色块)刷新时,并不直接写入磁盘数据文件中,而是先拷贝到内存中的double write缓存中;

    2 顺序写:接着将double write缓存区中的数据分两次顺序写入到磁盘的共享表空间中,每次写入1MB。共享表空间中的double write页是连续存储的,采用顺序写的方式能够很迅速的完成写回操作,开销较小。

    3 离散写:将double write缓存区中的脏页数据写入到实际的各个表空间文件。当脏页里的数据完全写回磁盘后,即可将double write中的页标记为可覆盖。


    如果在将脏页刷新回磁盘的过程中发生崩溃,在恢复时,InnoDB存储引擎可以从共享表空间中的double write中找到该页的最近的一个副本,将其复制到表空间文件,再利用redo log进行重做,就完成了恢复过程。


    因存在副本,妈妈再也不用担心我的电脑突然断电了!


    有人可能会问,在写redo log的时候是否需要double write支持呢?


    答案是不需要的,因为redo log在往磁盘中记录信息的时候是以512字节为单位进行写入的,而磁盘IO的最小单位恰巧也是512字节,那么就无所谓数据损坏啦。


    有人可能会觉得开启double write会带来性能的损耗,其实呢,内存中的double write缓存对应的磁盘共享表空间的文件是连续存储的,写入时是顺序写。顺序写的性能非常高,稍微牺牲一点性能来保证数据页的完整是非常有必要的!