Openstack 中cinder backup三种backend的对比

K版Openstack的Cinderbackup service新增加NFS作为backend,同时增加对增量备份的支持。这样当前已经支持四种backend,这里主要对其中三种ceph、nfs、swift的备份实现机制做一下对比介绍。另外一种TSM是IBM的存储,如果以后能有幸接触到再做研究和介绍。

先看下面的表格有一个整体了解。

 

增量备份

备份之间依赖关系

增量恢复

Ceph

特特定条件下支持

没有依赖关系

特定条件下支持

Swift

支持

备份链

不支持

NFS

支持

备份链

不支持

Ceph、Swift、NFS三种cinderbackup backend的特点对比

根据备份实现的特点,将这三种backend分为两类,其中NFS和Swift分为一类,Ceph单独作为一类。

一、基于Chunk的backend

首先介绍一下Swift和NFS,这两个放在一起说,是因为他们都继承自ChunkedBackupDriver,二者的实现机制完全一样,都是将原始的volume拆分成chunk,然后保存到对应的存储上。不同点只在于存放数据的方式。

在介绍之前先了解两个重要的参数:

Chunk_size:表示将volume分成多大的块进行备份。在NFS中这个值叫做backup_file_size,默认是1999994880 Byte,大约1.8G。在Swift中这个值叫做backup_swift_object_size,默认是52428800Byte,也就是50M。在Ceph中这个值叫做backup_ceph_chunk_size,默认值是128M。

Sha_block_size:这个值用于增量备份,它决定了增量备份的粒度。在NFS中,这个值叫做backup_sha_block_size_bytes,在Swift中,这个值叫做backup_swift_block_size。默认都是32768Byte,也就是32K。在Ceph,没有对应的概念。

1.1全量备份

对一个volume做全量备份的时候,每次从volume读入Chunk_size字节的数据,然后从头开始,每Sha_block_size(Chunk_size必须是Sha_block_size的整数倍)个字节做一次SHA计算,并将结果保存起来,然后会把Chunk_size的数据进行压缩(可以配置不压缩),并保存到对应的存储上,这就形成了NFS上的一个文件或者Swift中的一个object。这样循环,直到把整个volume都保存到backend上。最后还会生成两个文件,一个是metadata,其中记录了这个volume对应存储上哪些文件(或objects),每个文件(或object)的大小、压缩算法、长度、偏移量等;另一个是sha256file,其中按顺序记录了每次SHA计算的结果。这两个文件也会随之前的Chunk一起保存。至于metadata和sha256file这两个文件有什么用,且见下面分析。

1.2增量备份

增量备份实现思路很简单,对一个volume进行增量备份时,会读取前一次备份(全量或增量)的sha256file,备份时会将每Sha_block_size数据SHA计算的结果与上次备份的值比较,如果相同,就只保存计算结果,如果不同就会将对应的Sha_block进行备份。连续SHA计算结果不同的Sha_block会保存成同一个文件。其中metadata中会注明每个文件的大小以及在原始volume中的偏移量。

由以上描述可以知道,sha256file是实现增量备份的关键。这个文件记录了原始卷每个Sha_block_size数据的SHA值,每次增量备份时,将新的SHA值和上次备份记录的值进行比较,只需要备份SHA值不同的数据。另外,我么也可以知道,增量备份之间是有依赖的,新创建的备份会依赖于上一次的备份,多次增量备份会形成一个依赖链,在这里我们可以称之为备份链。在给volume创建增量备份时,总是会基于这个volume最新备份去创建。每次创建一个全量备份,都意味着增加一个备份链。

1.3全量备份的恢复

备份恢复时,如果指定了volume id,会恢复到指定的volume中,如果没有指定会新创建一个volume,并恢复到对应的volume中。

全量备份的恢复很简单,只需要找到对应的备份,将其内容写回对应的volume即可。那么这里有个问题,每个备份都对应存储上哪些文件呢,每个文件又对于原始volume中哪些数据?还记得创建备份时生成的metadata文件吗,答案就在其中。恢复备份时,会读取这个文件,然后将每一个备份文件恢复到对应的位置。当然,如果有压缩也会根据metadata中的描述,先解压再写入对应的volume中。

1.4增量备份的恢复

增量备份的恢复稍微复杂一些,正如之前的描述,增量备份之间有依赖,会形成备份链,我们需要恢复所选备份及其在备份链上之前所有的数据。在恢复时,需要查询数据库,获取当前备份及备份链上之前的所有备份,其顺序是[所选备份,父备份,父父备份,……全量备份],恢复的时候会按照相反的顺序依次进行,即首先恢复全量备份,接着创建的第一个增量备份,第二个增量备份,直到所选的备份。每个备份恢复时依赖创建备份时生成的metadata文件,将备份包含的文件,恢复到volume中。每个备份的恢复和全量备份的恢复方式一样。

1.5相关命令行

创建一个全量备份:

cinderbackup-create [--display-name <display-name>] <volume>

创建一个增量备份:

cinderbackup-create [--display-name <display-name>] --incremental True <volume>

恢复一个备份:

cinderbackup-restore [--volume-id <volume>] <backup>

二、使用Ceph作为backend。

按照cinder-volume所用的backend分两种情况介绍,一种是cinder-volume使用非rbd作为backend,这种情况和上面的Swift、NFS情况类似;另一种是cinder-volume使用rbd作为backend,这中情况下备份充分利用了ceph的特性,我们单独介绍。

2.1 cinder-volume使用非rbd作为backend

这种情况下比较简单,并且仅支持全量量备份。在创建备份时,首先创建一个base backup image,然后每次从源卷读入chunk_size(即backup_ceph_chunk_size,默认是128MB)大小的数据,写入到backup image,直到把整个源卷都复制完。注意,这里不支持对chunk的压缩。因为volume上的数据都会写入到创建的这个backup image上去,也就是说volume和backup是一对一的,因此也不需要metadata文件。

2.2 cinder-volume使用rbd作为backend

在这种情况下,即cinder-volume和cinder-backup都是用rbd作为backend,是支持增量备份的。增量备份的实现完全依赖于ceph处理差量文件的特性,这里对此先做个简单介绍。

所谓ceph处理差量文件的能力,即ceph可以将某个rbd image不同时刻的状态进行比较,并且将其差量导出成文件。另外,ceph也可以将这个差量文件导入到某个image中。

2.2.1 Ceph使用差量文件的三种方式

Ceph生成差量文件的三种方式

1、rbd export-diffvolumes/image1  image1diff   将volumes/image1从创建到此刻的变化保存image1diff这个文件。

2、rbd export-diff volumes/image1@snap1 image1s1diff 将volumes/image1创建时和快照snap1的不同保存在image1s1diff这个文件。

3、rbd export-diffvolumes/image1 –from-snap snap1 image1s1diff2   将现在volumes/image1和快照snap1的不同保存在image1s1diff2.

 Ceph导入差量文件的三种方式

对应上面三种生成差量文件的方式,有三种导入差量文件的方式。导入的前提是先创建一个image2,然后将diff文件导入这个image。

1、 rbdimport-diff  image1diff  volumes/image2   此时image2和生成diff时的image1相同

2、rbd import-diff  image1s1diff volumes/image2  此时image2和创建snap1后的image1相同,也就是说image2也有一个叫做snap1的快照

3、 rbdimport-diff  image1s1diff2  volumes/image2   这个可以执行的前提是image2有一个叫做snap1的快照

注意:生成diff和使用diff的1、2、3是分别对应的

2.2.2 备份的实现

现在知道了ceph是如何使用差量文件的,下面来看看如何利用这个特性实现备份,这里同样分为两种情况:

一、对一个volume第一次进行备份

1、创建一个新的base rbd image,名称格式:"volume-%s.backup.base"% (volume_id

2、将soure-rbd创建一个snap,名称格式:"backup.%s.snap.%s"% (backup_id, time.time())

3、利用第2种生成diff的方式生成diff文件

4、利用第2种导入diff的方式导入第一步生成的image中  (代码中并不会生成diff文件,而是采用类似于管道方式直接diff到目标位置)

5、备份完成

可以看出,第一次备份,也是类似于差量备份。

二、第二次及以后再备份

1、  找出soure-rbd image上最近一个满足r"^backup\.([a-z0-9\-]+?)\.snap\.(.+)$"的快照

2、  在base rbd image上查找是否有一个和第1步找到的快照相同名称的快照(正常应该是有的,见上面导入diff文件的第2种方式,没有就抛出异常)

3、  在source-rbd 创建一个snap,名称格式:"backup.%s.snap.%s" % (backup_id, time.time())

4、  利用第3种方式生成diff文件,所用的snap即第1步中找到的那个快照,也就是说每次的diff都是相对于上一次备份而言的,这也就达到了增量备份的目的。

5、  将diff文件导入到base rbd image上

6、  备份完成

由上可知,同一个volume的所有备份对应同一backup rbd image,创建备份时,会在原始卷上创建一个快照,通过比较新建快照和上一次备份的快照形成差量文件,将这个差量文件导入到backup rbd image即完成了备份。由上面ceph处理差量文件的特性可知,这个快照也会存在于backup rbd image上,也就是说每个备份对应的是backup rbd image上的一个快照。

2.2.3备份的恢复

这里分两种情况,diff方式(增量恢复)和非diff方式(全量恢复),只有满足一定条件时才能使用diff方式。

使用diff方式的条件:

1、   Cinder-volume使用rbd作为backend,并且不是恢复到创建备份的原始卷;

2、   目标卷必须和源卷相同大小,不能有扩容;

3、   备份上存在backup rbdimage(第一次备份时创建);

4、   备份上有backup id对应的snapshot

利用diff方式恢复备份,本质上也是利用了ceph处理差量文件的能力。非diff方式的恢复则同NFS、Swift类似。

非diff方式的恢复

这个其实就是全量恢复,和之前的NFS、Swift差不多,就是每次从备份读入chunk_size的数据,写入到对应的volume,知道复制完整个备份。没有metadata文件,也不支持解压。

diff方式的恢复

这个利用了ceph的特性,首先找到第一次备份时创建的base image和所选备份的snapshot,利用上面讲述的第2种生成差量文件的方式生成diff文件,将diff文件导入到新的volume(cinder-volume上新创建的volume)就完成了volume的恢复。

2.2.4相关命令行

创建一个全量备份:

cinderbackup-create [--display-name <display-name>] <volume>

恢复一个备份:

cinderbackup-restore [--volume-id <volume>] <backup>

    backup-create时先尝试创建增量备份,如果不成功,会创建全量备份,不需要指明专门的参数。


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页