突然停电了,我的数据还没保存到数据库……
最近看到全国各地都在“拉闸限电”,吓的我赶紧登上后台服务器,看了看MySQL数据库是否有问题,还好一切如常,也没听说北京有停电通知,好歹松了一口气。
忽然想到一个问题,万一数据库正在执行写入操作,突然断电了,会是怎么样的呢?
从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缓存对应的磁盘共享表空间的文件是连续存储的,写入时是顺序写。顺序写的性能非常高,稍微牺牲一点性能来保证数据页的完整是非常有必要的!
- 上一篇: 移动互联网进军营的趋势分析 2021/1/6
- 下一篇:同济大学照明改造2期工程完工,来欣赏一波美图 2021/1/5