备份一般会有文件级的备份,还有块级的备份两种,我们接下来先简要了解一下这两种备份的区别。
文件级备份:备份软件只能感知到文件这一层,将磁盘上的所有文件,通过调用文件系统的接口备份到另一个介质上,所以文件级备份软件,要么依靠操作系统提供的API来备份,要么本身具有文件系统的功能,可以识别文件系统元数据。其机制就是将数据以文件的形势独处,然后在将独处的文件存储在另外一个介质上。这些文件在原来的介质上存放可以使不连续的,各个不连续的块之间的链关系由文件系统来管理。如果备份软件将这些文件备份到新的空白介质上,那么这些文件很大程度上是连续存放的,不管是备份到磁带还是磁盘上。
块级备份:块级别的备份就是备份设备上的所有块,不管这个块上有没有数据,这里块的概念,对于磁盘来说,就是扇区Sector。块级别的备份,是最底层的备份,它抛开了文件系统,直接对磁盘扇区进行读取。这种方式最典型的实例,就是磁盘镜像。而磁盘镜像最简单的实现就是RAID1。
1、常见的快照模式:
Copy on first write(CoFW)
redirect on first write(RoFW)
上面这两种模式的,一看就能懂,下面我们看一下创建两个快照的情况:
1、某时刻状态1号框所示,生成第一个快照,并且重定向写出了A'和C' 这两个数据块。
2、之后某个时刻,当前活动文件系统的B被更新为B',则系统直接将B‘重定向写出去。这个时候系统再次触发一个快照,此时系统暂时挂起所有IO,然后立即开始将整个当前活动文件系统的元数据复制一份存放,复制完成后立即解除暂挂。被复制下来的这份元数据链是与当前活动元数据链完全相同的,所以此时刻其指向底层数据块与当前活动元数据链也是相同的。可以看到数据块D,是被三套元数据链共享指向的。
3、之后某时刻应用程序要更改当前活动文件系统中的A’数据块为A'',此时是否需要做一些动作?我们来看一下,对于快照1来讲,A'已经是被重定向复制初七的块了,那么对于快照1,是不需要任何改变了,因为执行快照1的时刻就是那个A那个样子而不是A‘那个样子。 对于快照2,用A''覆盖A'是第一次覆盖,所以需要将A''重定向写出去。同时可以看到A'对于当前活动文件系统和快照1来讲已经没有用了,但是对于快照2来说,却是必须的,A'是快照2时刻这个块所对应的历史版本。
4、同理,之后某时刻D被覆盖更改为D',那么系统同样也会将D'重定向写出,并且修改当前活动文件系统元数据链中的指针。D这个数据块依然保留,因为快照1与快照2共同指向他。
到此,我们基本明白了快照原理,但是,还没有完,我们想一下,在面对一个海量庞大的文件系统的时候,其元数据可能会达到上GB或者上百GB都是可能的,如此一来,首次元数据复制所耗费的时间将是不可接受的。有没有办法再降低复制量的???
整个文件系统的宗是元数据链,而元数据链也有一个宗,这就是根入口块,或者叫SUPER BLOCK, 这个块的地址在底层空间上是绝对恒定的,这个块内存放有指向下一级元数据链块的指针,操作系统每次载入元数据都要从这个地址读入super block,从而根据其中的指针一层层的向下遍历,我们想到:完全可以只复制SUPER BLOCK,他下面的元数据的变更,也和数据文件一样,用CoFW或者RoFW流程。看图就明白了:
首次复制只复制SUPER BLOCK的做法加快了复制速度,使得快照真的可以被瞬间执行,但是相对于复制元数据的那种,这种在后续会需要将完整的元数据进行CoFW或者RoFW吗,相比于首次复制全部元数据链的模式,其实需要复制的数据量长期来看是一样的,但是这种方式却可以更加快速的完成拍摄过程。
2、快照底层架构设计
1,、基于Copy on First Write的架构设计
本设计包含了4个实体数据结构:
第一个:用户存放变化IO块的IO仓库,可以使任何形式的高性能永久存储空间,再加上一份IO仓库的bitmap,用来标记仓库中空闲块与非空闲块。
第二个:地址映射表,用于保存指针,地址映射表也存放于IO仓库的特定位置,并且每个快照各保存一份。由于我们考虑到内存占用和处理效率问题,地址映射表不可能为每个针对源卷的LBA地址都有一个Slot,而只能是系统生成条目的时候,利用二分查找方式将新条目插入表格中并且保证所有条目按照LBA地址大小的顺序排列,从而方便后续的步骤中对表中地址查找。不需要做索引等其他结构,以求降低系统资源的耗费。
第三个:RoFW数据映射表。这个表保存所有针对虚拟快照影像卷的写IO,同样是每个快照一份,只读挂载的快照则不需要这个数据结构。
下面给出具体步骤:
1、T0时刻,有卷V1,IO仓库V2,此时系统触发一份Snapshot,进入触发流程之后,系统创建一份针对T0时刻的快照S0的地址映射表F0,这份表在T0时刻为空:
2、T1时刻,有写IO将源卷LBA0地址上的A0更新为A1,系统首先检验所有已存在地址映射表中哪个或者哪些没有针对源卷LBA0地址的映射条目,发现没有,所以CoFW读出A0,将A0写入IO仓库的LBA0,然后在地址映射表F0中更新地址映射条目:LBA0=LBA0,意思是源卷在T0时刻的LBA0这个地址上的数据目前保存在IO仓库中的LBA地址上,最后体统将A1正常的写入源卷对应地址,如下图:
3、T2时刻,有写IO将源卷LBA30地址上的C0更新问C2,系统首先检查所有已存在的地址映射表中哪个或者哪些没有针对源卷LBA30地址的映射条目,发现没有,所以CoFW读出C0,将C0写入IO仓库的LBA1,然后在地址映射表F0中更新地址映射条目;LBA30=LBA1,意思是源卷在T0时刻(T0时刻与T2时刻源卷LBA30地址上的数据相同)的LBA30这个地址上的数据目前保存在IO仓库中的LBA1地址上。最后系统将C2正常写入源卷对应地址。同时,系统