VMware 虚拟化编程(10) — VMware 数据块修改跟踪技术 CBT

目录

  • 目录
  • 前文列表
  • 数据块修改跟踪技术 CBT
    • 为虚拟机开启 CBT
    • CBT 修改数据块偏移量获取函数 QueryChangedDiskAreas
    • changeId
    • 一个 QueryChangedDiskAreas 的 DEMO
  • 应用 QueryChangedDiskAreas 设计的增量差异备份算法

前文列表

VMware 虚拟化编程(1) — VMDK/VDDK/VixDiskLib/VADP 概念简析
VMware 虚拟化编程(2) — 虚拟磁盘文件类型详解
VMware 虚拟化编程(3) —VMware vSphere Web Service API 解析
VMware 虚拟化编程(4) — VDDK 安装
VMware 虚拟化编程(5) — VixDiskLib 虚拟磁盘库详解之一
VMware 虚拟化编程(6) — VixDiskLib 虚拟磁盘库详解之二
VMware 虚拟化编程(7) — VixDiskLib 虚拟磁盘库详解之三
VMware 虚拟化编程(8) — 多线程中的 VixDiskLib
VMware 虚拟化编程(9) — VMware 虚拟机的快照

数据块修改跟踪技术 CBT

CBT(Changed Block Tracking) 数据块修改跟踪技术,是 VMware 实现「增量备份」的底层支撑技术。CBT 的优势在于节约空间,它允许只备份发生了修改的数据。在 CBT 被引入之前,每次都必须要备份整个虚拟机,而不是增量备份。所谓增量备份,即仅备份两个快照时间点之间所被修改过的数据。开启了 CBT 的虚拟机会在其数据储存目录下新建一个 -ctk.vmdk 文件,用于记录数据块修改的跟踪信息。但开启 CBT 会对虚拟机的虚拟磁盘带来一些性能损失,所以默认会关闭 CBT。

CBT 的工作原理就是让 VMKernel 监控自上次快照时间点以来有那些数据块中的数据被改变了,并记录下这些被改变的数据块的偏移量,依靠这些偏移量就能够获取数据块中的修改数据了。

以下场景都支持 CBT:

  • 存储在 VMFS 上的虚拟磁盘(SAN or Local)
  • NFS 上的虚拟磁盘
  • 虚拟兼容模式的 RDM(裸设备映射)

以下场景不支持 CBT

  • 物理兼容模式的 RDM

为虚拟机开启 CBT

默认情况下 CBT 功能是禁用的,因为它会引起一个很小但是可被测量到的性能损耗。开启 CBT 的前提条件需要虚拟机版本为 7 或更高,我们可以使用 PropertyCollector 从 VirutalMachine ManagedObject 中获取这个 CBT 的属性域,如果其中含有 changeTrackingSupported 属性值,就该虚拟机支持 CBT 功能。

  • 使用程序设置 CBT
VirtualMachineConfigSpec configSpec = new VirtualMachineConfigSpec();
configSpec.changeTrackingEnabled = new Boolean(true);
ManagedObjectReference taskMoRef = serviceConnection.getService().ReconfigVm_Task(targetVM_MoRef, configSpec);
  • 手动设置 CBT
    • 右击虚拟机,选择「Edit Settings」
    • 点击「Options」
    • 点击「Advanced section」下的「General」,点击「Configuration Parameters」,开启「Configuration Parameters」窗口后,查找或添加「ctkEnabled」项,设置为「true」,并设置每个磁盘的「ctkEnabled=true」

在设置了 CBT 之后,需要重启虚拟机生效。

NOTE: vSphere WS API 能调用 configSpec.changeTrackingEnabled = new Boolean(true) 来动态的设置 CBT 状态,而不需关闭虚拟机。

CBT 修改数据块偏移量获取函数 QueryChangedDiskAreas

VMware vSphere WS API 中提供的 QueryChangedDiskAreas Method 能够帮助开发者获得虚拟机 CBT 的功能,该函数需要提供以下参数:

  • _this:目标 VirtualMachine moRef
  • snapshot:虚拟机当前的 Snapshot moRef
  • deviceKey:目标虚拟磁盘的 Id
  • startOffset:指定开始检查 CBT 的 offset,一般可以为 0
  • changeId:虚拟磁盘在某个时间点上的状态标识符,是一个格式为 <UUID>/<nnn> 的数字序列字符串,如果 <UUID> 改变了,跟踪信息就会失效。

QueryChangedDiskAreas 返回的是 DiskChangeInfo 数据对象,它包含一组 DiskChangeInfo.DiskChangeExtent 元素,分别表示已修改数据块磁盘区域的开始位移和长度,DiskChangeInfo 覆盖了整个磁盘区域的开始位移和长度。
EXAMPLE:(offset,length) 表示一个发生了修改的数据块的偏移量

(117768192, 65536)
(132120576, 65536)
(145096704, 43122688)
(265289728, 65536)
(958398464, 65536)

使用 QueryChangedDiskAreas 得到已修改数据块偏移量信息的前提条件是需要在创建快照前启用 CBT 功能,如果在启用 CBT 前调用该 Method 就会触发 FileFault 错误。

changeId

changeId 实际上就是虚拟磁盘在某个时间点的标识符。当我们调用 QueryChangedDiskAreas Method 时,除了可能会为形参 changeId 传入一串数字序列字符串之外,还可能会传入一个「*」号。

在使用 changeId 时,应该注意以下几点

  • 当虚拟机还没有快照时,虚拟磁盘的 changeId 初始值应该为 none 表示未设置的。
  • 当虚拟机创建第一个快照时,应该将传入「*」号,表示虚拟磁盘上所有的实际已分配的区域,同时忽略稀疏类型磁盘的未分配区域。需要注意的是,只有当虚拟磁盘的 changeId 初始值为 none 时,changeId=* 才会生效。换句话说,只有当虚拟机仅拥有一个快照时调用 QueryChangedDiskAreas,才能够将 changeId 设置为「*」,并且能够以此获得虚拟机的全量数据偏移量。
  • 在此之后的每次创建快照都会生成一个新的 changeId。如果 changeId 不再为 none,则表示虚拟机已经进行过至少一次快照,此后调用 QueryChangedDiskAreas 就能够得到自 changeId 标识的快照时间点以来所发生了修改的数据块偏移量,也就是增量数据偏移量。

总结一下,使用「*」时,存在下面两点限制

  • 虚拟磁盘必须存放在 VMFS 上。
  • 启动 CBT 时,虚拟机必须没有快照存在。

获取虚拟磁盘当前的 changeId
我们能够用过 VirutalMachine ManagedObject 的 vim.vm.device.VirtualDevice.VirtualDisk 配置项中找到虚拟机每一块虚拟磁盘的 backing 信息。如果 backing 的类型是下列中的一个,你就可以使用 BackingInfo 数据对象的 changeId 属性来获得其 changeId:

  • vim.vm.device.VirtualDevice.VirtualDiskFlatVer2BackingInfo
  • vim.vm.device.VirtualDevice.VirtualDiskSparseVer2BackingInfo
  • vim.vm.device.VirtualDevice.VirtualDiskRawDiskMappingVer1BackingInfo
  • vim.vm.device.VirtualDevice.VirtualDiskRawDiskVer2BackingInfo

最后总结一下,QueryChangedDiskAreas(..., "*") 实际上会返回虚拟磁盘被实际使用的(Thin)或者整个被分配的(Thick)的数据空间偏移量。CBT 的实现依赖于「虚拟磁盘的未分配区域」以及「 VMFS 的数据块延迟清零」两者的定义和特性。因此,CBT 只有在 VMFS 数据存储上才会返回有意义的结果。在其他存储类型上,要么就失败,要么就返回包含整个磁盘的单个内容。

在开启的 CBT 的前提下,第一次调用 QueryChangedDiskAreas(..., "*") 时,它会返回虚拟磁盘上所有 已经使用的 数据块区域,后续的调用则会返回 已修改的 数据块区域,而不是 已分配的 区域。

在没有开启 CBT 的前提下,在快照后调用 QueryChangedDiskAreas,则会返回 已分配的 区域,对于精简置备虚拟磁盘和延迟清零的厚置备磁盘而言,那些 已分配但未使用的 区域则会使用零值填充。也就是说这种情况下,即便是精简置备虚拟磁盘,其全量备份所得到的数据量等于为其所分配的数据量,而非实际所使用了的数据量。

一个 QueryChangedDiskAreas 的 DEMO

String changeId; //Already initialized: changeId, snapshotMoRef, the VM
ManagedObjectReferencesnapshotMoRef;
ManagedObjectReferencetheVM;
int diskDeviceKey; //Identifies the virtual disk.
VirutalMachine.DiskChangeInfochanges;
long startPostion = 0;
do {
       changes =theVM.QueryChangedDiskAreas(snapshotMoRef, diskDeviceKey, startPostion,changeId);
       for (int i = 0; i < changes.changedAread.length;i++) {
              long length =changes.changedArea[i].length;
              long offset =changes.chagedArea[i].startOffset;
              //
              // Go get and save disk data here
       }
       startPosition = changes.startOffset +changes.length;
} while (startPosition< diskCapacity);

在这个 DEMO 里,QueryChangedDiskAreas 被反复调用,同时开始检查位置 startPosition 在虚拟磁盘中不断往后移动。这是因为对于大型虚拟磁盘而言,ChangedDiskArea 数组很可能会占用大量的内存。

NOTE:需要注意的是,QueryChangedDiskAreas 获得的是已修改数据块的偏移量,而非实际的已修改数据。

应用 QueryChangedDiskAreas 设计的增量/差异备份算法

假设在 T1 时间点创建了一个初始的全量备份,之后在 T2、T3 时间点分别创建了增量备份。当然,你也可以使用差异备份,只是它会消耗更多的备份时间和带宽,但是拥有更少的还原时间。

  • T1 时间的全量备份

    1. 记录虚拟机的配置信息 VirtualMachineConfigInfo。
    2. 创建虚拟机快照,命名为 snapshot_T1。
    3. 获得并保存快照中各个虚拟磁盘的 changeId,changeId_T1。
    4. 备份调用 queryChangedDiskAreas(…, “*”) 所返回的已修改数据块扇区对应的数据。
    5. 删除快照 snapshot_T1。
  • T2 时间的增量备份
    1. 创建虚拟机快照,命名为 snapshot_T2。
    2. 获得并保存快照中各个虚拟磁盘的 changeId,changeId_T2。
    3. 备份调用 queryChangedDiskAreas(snapshot_T2, …, changedId_T1)返回的已修改数据块扇区对应的数据。
    4. 删除快照snapshot_T2。
  • T3 时间的增量备份
    1. 创建虚拟机快照,命名为 snapshot_T3 (此时你无法再获得 T1 到 T2 两个时间点之间的以修改数据块列表)
    2. 获得并保存快照中各个虚拟磁盘的 changeId,changeId_T3。
    3. 备份调用 queryChangedDiskAreas(snapshot_T3, …, changedId_T2)返回的已修改数据块扇区对应的数据。如果你希望执行差异备份,则调用 queryChangedDiskAreas(snapshot_T3, …, changedId_T1)。
      4删除快照snapshot_T3。
  • T4 时间的灾难恢复
    1. 使用之前保存的 VirtualMachineConfigInfo 中的配置参数,创建一个没有 GuestOS,没有虚拟磁盘的新虚拟机。
    2. 从 T3 的增量备份中还原数据,并记录还原了哪些扇区。
    3. 从 T2 中还原增量备份的数据,跳过 2 中已记录(已还原)的扇区,并记录还原了哪些扇区。如果 T3 是差异备份,则跳过此步骤。
    4. 从 T1 完全备份中还原数据,并跳过 2、3 中已记录(已还原)的扇区。
    5. 打开恢复过后的虚拟机。

NOTE:从后往前还原的目的就是获取同一数据块上最新的数据,从而避免不需要的数据拷贝。

时间: 2024-08-04 12:59:38

VMware 虚拟化编程(10) — VMware 数据块修改跟踪技术 CBT的相关文章

VMware 虚拟化编程(15) — VMware 虚拟机的恢复方案设计

目录 目录 前文列表 将已存在的虚拟机恢复到指定时间点 恢复为新建虚拟机 灾难恢复 恢复细节 恢复增量备份数据 以 RDM 的方式创建虚拟磁盘 创建虚拟机 Sample of VirtualMachineConfigSpec Demo of VirtualMachineConfigSpec 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化编程(2) - 虚拟磁盘文件类型详解 VMware 虚拟化编程(3) -VMwa

VMware 虚拟化编程(13) — VMware 虚拟机的备份方案设计

目录 目录 前文列表 备份思路 备份算法 备份细节 连接到 vCenter 还是 ESXi 如何选择快照类型 是否开启 CBT 如何获取备份数据 如何提高备份数据的传输率 备份厚置备磁盘和精简置备磁盘有什么区别 Thin 精简置备虚拟磁盘 Thick-Lazy 延迟置零的厚置备虚拟磁盘 Thick-Eager 立即置零的厚置备虚拟磁盘 有什么磁盘类型是无法进行备份的 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化编

VMware 虚拟化编程(11) — VMware 虚拟机的全量备份与增量备份方案

目录 目录 前文列表 全量备份数据的获取方式 增量备份数据的获取过程 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化编程(2) - 虚拟磁盘文件类型详解 VMware 虚拟化编程(3) -VMware vSphere Web Service API 解析 VMware 虚拟化编程(4) - VDDK 安装 VMware 虚拟化编程(5) - VixDiskLib 虚拟磁盘库详解之一 VMware 虚拟化编程(6)

VMware 虚拟化编程(9) — VMware 虚拟机的快照

目录 目录 前文列表 VMware 虚拟机的快照 快照的执行过程 删除快照 快照类型 Quiseced Snapshot 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化编程(2) - 虚拟磁盘文件类型详解 VMware 虚拟化编程(3) -VMware vSphere Web Service API 解析 VMware 虚拟化编程(4) - VDDK 安装 VMware 虚拟化编程(5) - VixDiskLib

VMware 虚拟化编程(3) —VMware vSphere Web Service API 解析

目录 目录 前文列表 VMware vSphere Web Services API VMware vSphere Web Services SDK vSphere WS API 中的托管对象 Managed Object 托管对象引用 Managed Object References 托管对象属性收集器 PropertyCollector 连接 vCenter 并获取 MO 最后 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VM

VMware 虚拟化编程(14) — VDDK 的高级传输模式详解

目录 目录 前文列表 虚拟磁盘数据的传输方式 Transport Methods Local File Access NBD and NBDSSL Transport SAN Transport HotAdd Transport 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化编程(2) - 虚拟磁盘文件类型详解 VMware 虚拟化编程(3) -VMware vSphere Web Service API 解析 V

VMware 虚拟化编程(12) — VixDiskLib Sample 程序使用

目录 目录 前文列表 vixDiskLibSample 安装 Sample 程序 Sample 程序使用方法 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDiskLib/VADP 概念简析 VMware 虚拟化编程(2) - 虚拟磁盘文件类型详解 VMware 虚拟化编程(3) -VMware vSphere Web Service API 解析 VMware 虚拟化编程(4) - VDDK 安装 VMware 虚拟化编程(5) - VixDiskLib 虚拟磁盘库详

VMware 虚拟化编程(5) — VixDiskLib 虚拟磁盘库详解之一

目录 目录 前文列表 VixDiskLib 虚拟磁盘库 虚拟磁盘数据的传输方式 Transport Methods VixDiskLib_ListTransportModes 枚举支持的传输模式 VixDiskLib_InitEx 初始化 VixDiskLib 库 VixDiskLib_ConnectEx 连接到 virtual disk library VixDiskLib_Disconnect 断开 VixDiskLib 的连接 VixDiskLib_Cleanup 断开连接之后的清理 Vi

VMware 虚拟化编程(7) — VixDiskLib 虚拟磁盘库详解之三

目录 目录 前文列表 VixDiskLib 虚拟磁盘库 VixDiskLib_GetMetadataKeys VixDiskLib_ReadMetadata 获取虚拟磁盘元数据 VixDiskLib_WriteMetadata 更新虚拟磁盘元数据表 VixDiskLib_Create 创建新的寄宿磁盘 Hosted Disk VixDiskLib_Clone 克隆 VMDK File 创建新的托管磁盘 Managed Disk VixDiskLib_Unlink 删除 VMDK File Vix