增量备份
摘要
通过仅备份已更改的块并避免临时快照,此功能可简化,加速并提高鲁棒性。通过支持原始来宾数据的备份和还原,而与基础磁盘格式无关,可以改善与备份应用程序的集成。
所有者
- 尼尔· 索弗(Nir Soffer)(nsoffer@redhat.com)
- 丹尼尔·埃雷兹(Daniel Erez)(derez@redhat.com)
- Eyal Shenitzky(eshenitz@redhat.com)
高级设计
此功能之前有哪些可用功能?
使用此功能之前,备份磁盘需要创建一个临时快照,按原样复制快照文件(原始来宾数据或qcow2文件数据),然后删除该临时快照。
通过在每个备份上创建一个快照,复制快照磁盘并删除以前的快照,可以进行有限版本的增量备份。但是复制的数据为qcow2格式,因此要还原它,需要先合并qcow2文件,然后再上传到存储设备。
通过此功能添加的功能
-
使用qcow2格式对磁盘执行完整或增量备份,而无需临时快照。
-
备份原始来宾数据,而不是复制qcow2磁盘的qcow2数据。
-
将原始来宾数据还原到磁盘中,再还原到原始磁盘或qcow2磁盘中。
创建虚拟机
添加磁盘时,用户应为每个磁盘启用增量备份。如果为磁盘启用了增量备份,则备份应用程序可以在增量备份期间包括磁盘。
由于增量备份需要qcow2格式,因此启用了增量备份的磁盘将使用qcow2格式而不是原始格式。有关更多信息,请参见 磁盘格式。
未标记为增量备份的磁盘可以按照过去的备份方式进行备份。
启用现有VM进行增量备份
由于不支持原始磁盘,因此用户需要创建一个包括磁盘的快照,以为磁盘启用增量备份。这将在原始磁盘的顶部创建一个qcow2层,此层可用于执行此后的增量备份。
删除现有VM上的快照
如果磁盘的基础层使用原始格式,则删除最后一个快照,将顶层qcow2层合并到基础层中,会将磁盘转换为原始磁盘,并禁用增量备份(可能应该先显示警告)。用户可以创建包括该磁盘的新快照,以重新启用后退增量备份。
磁盘格式
下表显示了启用增量备份如何影响磁盘格式。
<span style="color:#333333"><span style="color:#333333"><code>storage provisioning incremental format
====================================================================
block thin enabled qcow2
block preallocated enabled qcow2 (preallocated)
file thin enabled qcow2
file preallocated enabled qcow2 (preallocated)
--------------------------------------------------------------------
block thin disabled qcow2
block preallocated disabled raw (preallocated)
file thin disabled raw (sparse)
file preallocated disabled raw (preallocated)
--------------------------------------------------------------------
network - disabled raw
lun - disabled raw
</code></span></span>
增量备份流程
-
备份应用程序使用oVirt API查找应包含在备份中的VM磁盘。当前只能包含标记为进行增量备份(使用qcow2格式)的磁盘。
-
备份应用程序使用oVirt API开始备份,并指定VM ID,可选的先前备份ID和要备份的磁盘列表。如果未指定以前的备份uuid,则备份时指定磁盘上的所有数据都将包含在备份中。
-
系统准备虚拟机进行备份。备份期间VM可能正在运行。
-
备份应用程序将等待,直到使用oVirt SDK备份准备就绪为止。
-
准备好备份后,备份应用程序将为备份中包含的每个磁盘创建映像传输。
-
备份应用程序从ovirt-imageio获取每次图像传输的已更改阻止列表。如果更改列表不可用,则备份应用程序将出现错误。
-
备份应用程序从ovirt-imageio以原始格式下载已更改的块,并将其存储在备份介质中。如果更改的块列表不可用,则备份应用程序可以后退以复制整个磁盘。
-
备份应用程序完成图像传输。
-
备份应用程序使用oVirt API完成备份。
增量还原流
-
用户使用备份应用程序(不是oVirt的一部分)基于可用备份选择还原点。
-
备份应用程序将创建新磁盘或具有现有磁盘的快照以保存还原的数据。
-
备份应用程序为每个磁盘启动上载映像传输,指定format = raw。将原始数据上传到qcow2磁盘时,这将启用格式转换。
-
备份应用程序使用HTTP API将此还原点中包含的数据传输到imageio。
-
备份应用程序完成图像传输。
恢复快照
增量还原将不支持还原备份时存在的快照。此限制在其他系统的备份解决方案中很常见。
在关机期间处理不干净的关机或存储中断
如果虚拟机异常关闭,则磁盘上的位图可能保持无效状态。使用此类位图创建增量备份将导致还原后来宾数据损坏。
要检测处于无效状态的位图,我们可以使用位图中的使用中位,但是此信息不会暴露给管理层。
要从无效位图恢复,必须删除无效位图和所有以前的位图。下次备份将必须包含整个磁盘内容。
备份REST API
启用VM磁盘备份
在disk
实体上指定“ backup”属性:“ incremental” /“ none”(TBD:“ full”)
请求:
<span style="color:#333333"><span style="color:#333333"><code>POST /vms/vm-uuid/diskattachments
<disk_attachment>
...
<disk>
...
<backup>incremental|none</backup>
...
</disk>
</disk_attachment>
</code></span></span>
响应:
<span style="color:#333333"><span style="color:#333333"><code><disk_attachments>
<disk_attachment>
...
<disk href="/ovirt-engine/api/disks/456" id="456"/>
...
</disk_attachment>
...
</disk_attachments>
</code></span></span>
查找启用了增量备份的磁盘
对于每个VM,获取disks
列表并根据“ backup”属性进行过滤。
请求:
<span style="color:#333333"><span style="color:#333333"><code>GET /vms/vm-uuid/diskattachments
</code></span></span>
响应:
<span style="color:#333333"><span style="color:#333333"><code><disks>
<disk>
...
<backup>incremental|none</backup>
...
</disk>
...
</disks>
</code></span></span>
开始完整备份
开始完全备份。响应包括在磁盘上创建的“ to_checkpoint_id”。可以在下一个增量备份中使用它。
请求:
<span style="color:#333333"><span style="color:#333333"><code>POST /vms/vm-uuid/backups
<backup>
<disks>
<disk id="disk-uuid" />
...
</disks>
</backup>
</code></span></span>
响应:
<span style="color:#333333"><span style="color:#333333"><code><backup id="backup-uuid">
<to_checkpoint_id>new-checkpoind-uuid</to_checkpoint_id>
<disks>
<disk id="disk-uuid" />
...
...
</disks>
<phase>initiailizing</phase>
<creation_date>
</backup>
</code></span></span>
开始增量备份
由于检查点ID为“ previous-checkpoint-uuid”,因此开始增量备份。响应包括“ to_checkpoint_id”,应在下一个增量备份中用作“ from_checkpoint_id”。
请求:
<span style="color:#333333"><span style="color:#333333"><code>POST /vms/vm-uuid/backups
<backup>
<from_checkpoint_id>previous-checkpoint-uuid</from_checkpoint_id>
<disks>
<disk id="disk-uuid" />
...
</disks>
</backup>
</code></span></span>
响应:
<span style="color:#333333"><span style="color:#333333"><code><backup id="backup-uuid">
<from_checkpoint_id>previous-checkpoint-uuid</from_checkpoint_id>
<to_checkpoint_id>new-checkpoind-uuid</to_checkpoint_id>
<disks>
<disk id="disk-uuid" />
...
...
</disks>
<phase>initiailizing</phase>
<creation_date>
</backup>
</code></span></span>
获取备份信息
当备份阶段为“就绪”时,您可以开始下载磁盘。
请求:
<span style="color:#333333"><span style="color:#333333"><code>GET /vms/vm-uuid/backups/backup-uuid
</code></span></span>
响应:
<span style="color:#333333"><span style="color:#333333"><code><vm_backup id="backup-uuid">
<from_checkpoint_id>previous-checkpoint-uuid</from_checkpoint_id>
<to_checkpoint_id>new-checkpoind-uuid</to_checkpoint_id>
<disks>
<disk id="disk-uuid">
<image_id>image-uuid</image_id>
</disk>
...
</disks>
<phase>ready</phase>
<creation_date>...
</vm_backup>
</code></span></span>
完成备份
<span style="color:#333333"><span style="color:#333333"><code>POST /vms/vm-uuid/backups/backup-uuid/finalize
<action></action>
</code></span></span>
创建映像传输以进行增量还原
要将使用增量备份API备份的原始数据还原到qcow2磁盘,需要在传输中指定“ format”键:
<span style="color:#333333"><span style="color:#333333"><code>POST /imagetransfers
<image_transfer>
<disk id="123"/>
<direction>upload</direction>
<format>raw</format>
</image_transfer>
</code></span></span>
上传到快照时,请替换<disk id="123"/>
为 <snapshot id="456"/>
。
当传输格式为“原始”且基础磁盘格式为“ qcow2”时,上传的数据在写入存储时将被即时转换为qcow2格式。
不支持将“ qcow2”数据上传到“原始”磁盘。
imageio备份API
地图要求
获取零的映射和数据范围的存储。
查询选项:
- dirty = y-仅返回自备份检查点标识以来修改的范围
使用以下键返回JSON对象的列表:
- 数据:已分配范围为true,零或未分配范围为false
- 开始:范围的偏移量(以字节为单位)
- 长度:字节数
示例-获取数据和零范围
请求:
<span style="color:#333333"><span style="color:#333333"><code>GET /images/ticket-uuid/map
</code></span></span>
响应:
<span style="color:#333333"><span style="color:#333333"><code>[
{"data": true, "start": 0, "length": 1048576},
{"data": false, "start": 1048576, "length": 8192},
{"data": true, "start": 1056768, "length": 1048576},
]
</code></span></span>
示例-仅获取脏数据和零范围
请求:
<span style="color:#333333"><span style="color:#333333"><code>GET /images/ticket-uuid/map?dirty=y
</code></span></span>
响应:
<span style="color:#333333"><span style="color:#333333"><code>[
{"data": true, "start": 0, "length": 1048576},
{"data": false, "start": 1048576, "length": 8192},
]
</code></span></span>
未来的工作
-
支持原始磁盘的完整备份。Libvirt支持原始磁盘的完整备份,而无需创建新的检查点。
-
列出和删除检查点的API。
详细设计
备份前验证检查点
开始备份之前,必须将每个磁盘上的可用位图与引擎数据库上存储的检查点进行比较。如果映像中缺少位图,或者存在未知位图,则必须删除磁盘和引擎数据库上的所有检查点,并且当前备份必须是完整备份。
增量备份管道
备份增量数据时,无论底层磁盘格式如何,用户始终会读取原始来宾数据。
qemu使用内部NBD服务器公开磁盘,从而允许读取增量备份中包括的每个磁盘:
<span style="color:#333333"><span style="color:#333333"><code>http client (raw) <- imageio <- qemu <- image (raw or qcow2)
</code></span></span>
如果该虚拟机未运行,则系统将创建该虚拟机的精简版本(仅附加备份磁盘),并使用libvirt API来启动和停止备份。
我们考虑了使用qemu-nbd的替代解决方案,但是根据Eric Blake的说法,qemu-nbd不支持尚未公开位图信息,因此我们将无法提供更改阻止列表。
由于创建特殊的已暂停VM来备份非运行VM的工作量很大,因此我们可能会推迟对备份非运行VM的支持。
增量还原管道
恢复增量数据时,用户始终写入原始来宾数据。系统使用基础存储格式透明地将数据写入存储。
系统将创建qemu-nbd进程以写入每个磁盘:
<span style="color:#333333"><span style="color:#333333"><code>http client (raw) -> imageio -> qemu-nbd -> image (raw or qcow2)
</code></span></span>
准备用于增量备份的VM
-
用户使用oVirt API开始备份。引擎通过“初始化”阶段在数据库中创建备份。
-
如果虚拟机未运行,则引擎将准备精简版的虚拟机(仅附带备份磁盘),并以暂停模式在某些主机上创建虚拟机。
-
引擎使用vdsm检查点API配置和验证备份主机上的检查点,该API使用libvirt检查点API更新关于存储在引擎端的检查点的libvirt,并验证映像是否包含相同的检查点。libvirt备份API要求这样做,因为检查点信息未存储在qcow2文件中。
-
如果虚拟机正在运行,则引擎会冻结客户机上的文件系统,以确保备份一致。在客户机上的qemu-guest-agent的帮助下,刷新了待处理的I / O,应用程序进行了必要的更改以避免状态不一致。
-
引擎使用vdsm备份API开始备份,而vdsm备份API使用libvirt备份API开始备份。
-
libvirt将停用活动位图,并创建一个新的位图以跟踪备份开始后所做的更改。
-
libvirt使用qemu位图API为每个磁盘创建一个临时位图,包括此备份中包含的所有位图的合并内容。
-
libvirt启动qemu内部NBD服务器,公开每个磁盘的临时位图。
-
引擎解冻客户机上的文件系统。借助客户机上的qemu-guest-agent,将通知应用程序有关冻结的信息,并且客户机上的I / O现在可以正常继续。此时的任何写操作都将由新的活动位图跟踪,并且不会包括在增量备份中。
-
引擎将备份阶段更改为“就绪”。用户检测到更改后,即可开始传输数据。
完成备份
备份成功后,备份应用程序将成功复制所有增量数据。
-
用户要求使用oVirt API完成备份。引擎将备份阶段更改为“最终确定”。
-
引擎使用vdsm备份API结束备份,后者将使用libvirt备份API结束备份。
-
libvirt使用qemu API删除临时位图并结束备份作业。
-
如果运行特殊的“备份”精简VM,请使用现有存储API拆除VM磁盘的磁盘,然后销毁备份主机上的VM。
检查点清理
稍后将提供清理检查点的功能。
检查点可能由多个不相关或部分相关的用户生成,删除检查点不能由备份后的每个用户自动完成。
备份API应该允许指定要删除的检查点范围。可能指定应保留的检查点,删除所有较旧的快照。
暂存盘
现在,我们将在主机上使用暂存盘(由libvirt创建)。在以后的工作中,我们将考虑为备份中的每个磁盘使用qcow2格式创建暂存磁盘。磁盘必须有足够的空间以将当前数据保存在映像的顶层。
用例1-同时运行2个备份解决方案
用户正在从备份解决方案A切换到B。在过渡期间,两个系统都在执行相同数据的备份。如果其中一个系统在备份后删除检查点,则可以防止增量备份另一个系统。
用例2-使用不同的计划运行备份
用户正在配置每小时和每天备份。如果两个作业都在备份后删除了检查点,则它们可能会阻止下一个作业完成下一个备份。
引擎数据库更改
将备份列添加到base_disks表。用于标记映像以进行增量备份。
- base_disks
- 备份:(增量/无)
添加vm_backups表。该表保留有关运行备份任务的信息。在备份期间使用以跟踪和监控备份。
- vm_backups
- backup_id:UUID
- 阶段:“初始化” /“开始” /“就绪” /“完成”
- from_checkpoint_id:UUID /空
- 如果指定,请执行增量操作,包括自该检查点以来的所有检查点。
- to_checkpoint_id:UUID /空
- 新创建的检查点。
- vm_id:UUID
- creation_date:TIMESTAMP
添加vm_backup_disk_map表。该表保留每个磁盘的备份URL。为磁盘创建映像传输时,将使用该URL代替主机上的映像路径。
- vm_backup_disk_map
- backup_id:UUID
- disk_id:UUID
- backup_url:“ nbd:unix:/ tmp /.sock:exportname =“ |” nbd:// localhost:<12345> /”
添加vm_checkpoints表。该表保留由备份任务创建的检查点。在备份之前使用此信息来更新有关检查点列表的libvirt,因为此信息未存储在qcow2映像中。
- vm_checkpoints
- checkpoint_id:UUID
- 父母:UUID
- vm_id:UUID
- creation_date:TIMESTAMP
添加vm_checkpoint_disk_map表。该表保留每个检查点中包含的磁盘。在开始备份以为libvirt创建检查点xml时使用。
- vm_checkpoint_disk_map
- disk_id:UUID
- checkpoint_id:UUID
流程示例-备份
- 将行添加到vm_checkpoints
- 为每个磁盘将行添加到disk_checkpoint_map
- 为每个磁盘将行添加到disk_backup_map
- 将行添加到vm_backups
- 开始备份
- 更新每个磁盘的backup_url(从vdsm返回)
- 用户执行转移…
- 用户完成或取消备份
- 从vm_backups删除行
- 从disk_backup_map删除行
VDSM备份API
VM.start_backup
使用libvirt API开始备份
VM.stop_backkup
使用libvirt API结束备份
VM.backup_info
从libvirt返回备份信息。
VDSM检查点API
VM.redefine_checkpoints
从引擎数据库设置libvirt检查点,而不更改存储上的位图。
在开始备份之前或在启动VM之后调用一次。
如果存储中存在未知位图,或者存储中缺少位图,则Libvirt将无法重新定义检查点。
VM.delete_checkpoints
使用libvirt API删除libvirt和存储中的检查点。
Vdsm NBD API
NBD.start_server
使用qemu-nbd为单个卷启动NBD服务器,然后返回 tranfer_url
该卷链。
NBD.stop_server
使用start_nbd_server API停止启动NBD服务器。
增量备份票证示例
对于正在运行的VM,qemu将使用NBD为磁盘提供服务:
<span style="color:#333333"><span style="color:#333333"><code>{
"url": "nbd:localhost:1234:exportname=/sda"
}
</code></span></span>
对于停止的VM,我们将使用unix套接字在每个磁盘上运行一个qemu-nbd实例:
<span style="color:#333333"><span style="color:#333333"><code>{
"url": "nbd:unix:/run/vdsm/nbd/xxxyyy-nbd.sock:exportname=/sda"
}
</code></span></span>
用户界面
-
在“新建/编辑磁盘”对话框中添加“启用增量备份”复选框。
-
如果选中了“启用增量备份”并且基本映像是原始映像,则应禁用删除最后一个快照。必须禁用备份才能删除最后一个快照。
开放式问题
-
在异常关闭后启动或关闭期间存储中断后启动时,必须停用或删除标记为“使用中”的位图,并且qemu不得使用该位图来跟踪其他更改。根据John Snow的说法,使用此类位图加载qcow2将会失败,用户必须手动删除损坏的位图。这将使HA VM流和存储操作失败。(libvirt / qemu)。
-
创建快照时,应将活动位图复制到新的顶层,并且qemu应继续跟踪更改,并写入复制的位图(libvirt)。
-
处理VM在备份过程中停止-应该中止备份,从而导致映像传输失败(引擎)。
-
在脱机VM备份期间处理VM启动-应该中止备份,从而导致映像传输失败(引擎)。
-
备份期间锁定磁盘-当前图像传输已锁定磁盘,但是在创建备份时我们需要锁定磁盘。如果磁盘包含在增量备份(引擎)中,则映像传输应跳过锁定。
-
如何确定和取消失败?例如,无法删除暂存盘。系统是否应该继续跟踪项目并稍后重试以完成操作?(发动机)。
-
在块存储(vdsm)上使用预分配的qcow2时,需要为qcow2的元数据分配额外的空间。
-
需要为位图分配额外的空间,具体取决于图像的虚拟大小和位图的粒度。创建映像(vdsm)时无法计算。
-
当图像包含大量位图时,vdsm和引擎中用于限制qcow2实际大小的1.1因素可能不够。默认情况下,每个位图每TB使用2M(引擎,vdsm)。
-
使用qemu-img复制图像时是否会复制位图?如果不是,则LSM或移动磁盘之后的下一个备份必须已满(qemu-img)。
-
在活动层的LSM期间,是否以块复制的形式复制位图?如果不是,则下一个备份必须是完整的(libvirt / qemu)。
-
如何处理热插拔磁盘?我们是否可以继续跟踪分离磁盘上的更改,或者在这种情况下我们应该要求完全备份?
-
将带有位图的磁盘附加到较旧的qemu版本将使位图无效,从而创建损坏的备份。我们如何预防呢?(qemu)。
-
在实时合并(libvirt / qemu)和冷合并(qemu-img)期间是否从活动层复制位图?
-
需要libvirt API列出正在运行的VM(libvirt)中映像中的所有位图。
-
我们还需要qemu-img API来列出映像中的所有位图,以管理浮动磁盘中的位图吗?
-
预分配的qcow2与原始测试性能。https://www.jamescoyle.net/how-to/1810-qcow2-disk-images-and-performance
-
调整qcow2图像(如果需要)https://www.slideshare.net/mobile/igalia/improving-the-performance-of-the-qcow2-format-kvm-forum(2017
链接
- libvirt增量备份API概述
-
API-备份应用程序可以使用 oVirt引擎REST API 或oVirt引擎SDK 来启动和停止备份操作并获得备份阶段。
-
ovirt-engine-备份过程由ovirt-engine安排和监视 。
-
ovirt-imageio-backup应用程序将使用ovirt-imageio随机I / O API访问 ovirt-imageio以从运行VM的虚拟机管理程序传输增量备份数据 。
-
vdsm-在虚拟机管理程序上,vdsm将使用libvirt备份和检查点API来启动和停止备份,并准备临时Voluke。
-
libvirt-将使用qemu API来启动和停止备份作业,以及管理检查点。 libvirt邮件列表中正在审查增量备份的修补程序。修补程序也可以在Eric Blake的存储库中找到。
-
另请参阅KVM论坛2018的Eric演讲: 促进增量备份
-
qemu-使用脏位图跟踪更改的块。在qemu-3.0中添加了脏位图支持,并在CentOS 7.6中反向移植到了qemu-rhev。有关更多信息,请参见 qemu增量备份功能页面 和qemu源。
- 作为参考,这是VMWare CBT文档https://kb.vmware.com/s/article/1020128