1. 与备份有关的VMWare基础知识
1.1 VMware 虚机磁盘在 ESXi 宿主机上的文件
简单来说,虚机的每个虚拟磁盘由ESXi 宿主机上的三个文件组成(这里的虚机名字是 sammy-target-win-small,下面是其第一个磁盘对应的三个文件):
- sammy-target-win-small.vmdk (配置文件,大小 633 字节)
- sammy-target-win-small-flat.vmdk (二进制文件,大小 12884901888 字节)
- sammy-target-win-small-ctk.vmdk (二进制文件,大小 78694 字节)
其中,
第一个文件保存的是该磁盘的元数据,其中包括另外两个文件的信息
# Extent description RW 25165824 VMFS "sammy-target-win-small-flat.vmdk" # Change Tracking File changeTrackPath="sammy-target-win-small-ctk.vmdk"
第二个文件是 Extent description 文件,二进制数据保存在这个文件中。下面会介绍使用API获取该文件中数据的方法。
第三个文件是 CTK 文件。下面讲到 CTK 的时候再说。
1.2 快照(Snapshot)
虚机的快照是虚机在某个时间点的状态和数据,其中,状态是指虚机的状态,包括运行状态,配置等;数据是指虚机的虚拟磁盘中的数据。快照的基本操作包括:
- 创建快照(create)
- 删除快照(delete)
- 快照合并(consolidate)
- 恢复到快照(revert)
1.2.1 创建快照
对上面的虚机创建一个快照,除了快照定义文件以外,对该磁盘,新增了三个文件:
-rw------- 1 root root 786944 Jul 11 10:55 sammy-target-win-small-000001-ctk.vmdk -rw------- 1 root root 28672 Jul 11 10:55 sammy-target-win-small-000001-delta.vmdk -rw------- 1 root root 428 Jul 11 10:55 sammy-target-win-small-000001.vmdk
第一个依然是 ctk 文件,第二个是 delta 文件,第三个是非二进制文件。然后再创建第二个快照,就成了这样子:

(RW = 读写,RO = 只读)
从数据的角度看:

(绿色部分是从虚机视角看数据;最下面的红框是 base vmdk 中的数据;中间的红框是 delta vmdk 中的数据)

现在可以简单总结一下 VMware 快照的特点:
- 快照保存虚机在某一个时间点的状态和数据
- 对一个虚机做快照,相当于将虚机当前的磁盘设为只读模式,然后创建 delta vmdk 文件,它将会接受新的数据写操作。在存在多个快照的情况下,之前的快照磁盘变为只读。
- 写损失:写的时候,遵循 Copy-on-write 机制,按照数据分块,当需要修改某一块中的数据时,先将它从父vmdk 中拷贝到 delta vmdk,然后再对它修改。
- 读损失:当读取某一块数据时,ESXi 需要判断从哪里去读:对于没有修改的数据块,从父 vmdk 读;对已经修改了的数据块,从 delta vmdk 读。可见,客户端的一次读操作,可能需要从不同的 vmdk 上读取数据。
- delta vmdk 的大小不会超过 base vmdk 的大小,因为极限情况是所有的数据都被拷贝到delta vmdk 并且都没修改了。
- 因为快照会带来读和写损失,因此一个虚机不能有太多的快照。vSphere 限定一个虚机最多有 32 个快照,但是建议最多只有 2-3 个,而且快照的保留时间不超过一天。
1.2.2 删除快照
显然,快照只是内部数据,保存的是过去某时间点虚机的状态,对外部不可见,因此,删除快照不能影响虚机当前的状态和数据。因此,这里有三种可能:
(1)快照是基于原始虚机的:delta vmdk 中的数据会向 base vmdk 合并,然后 delta vmdk 被删除。(如下图中的s1)
(2)待删除快照在虚机的数据路径上:delta vmdk 中的数据会想父快照的 vmdk 合并,然后delta vmdk 被删除。(如下图中的s2)
(3)待删除快照不再虚机的数据路径上:不需要合并,直接删除。(如下图中的 s3)

现在可以简单总结一下删除快照的特点:
- 删除快照意味着快照之后的改变会被合并进快照之前的数据,因此,虚机再也无法回到所做快照之时的状态了。
- 删除快照过程包括两个异步的操作:从 Snapshot manager 中将快照删除,vmdk 数据合并。如果第一步成功而第二步失败,那么将有残留的 delta 文件被保留下来,这是就需要下面将介绍的手工合并操作。
- 删除快照可能会打来大量的数据写操作,这期间,虚机的性能会受到负面影响
- 删除快照有时候要花费很长的时间,特别是对于长时间存在的大容量磁盘的快照。 VMware 专门出了一个KB来让用户估计所需要的时间:Estimating the time required to consolidate snapshots during the snapshot removal for VMware ESX and VMware ESXi (2053758)
- 当删除所有快照时,自从 vSphere 4 Update 2 开始起过程有了优化,不再是重定向下一层一层地合并,而是各层都直接合并到 base disk。
1.2.3 快照合并(consolidation)
上面谈到了快照删除操作的数据合并可能会失败。这种失败会带来很多问题,包括不必要的磁盘空间占用,以及虚机性能下降。因此,当出现这种情况时,vCenter 会向用户提示需要做 consolidation 了。该操作会检查虚机当前所有的 vmdk 分层,将冗余的 delta 文件先合并再删除。
1.2.4 恢复到快照
恢复到快照操作也比较好理解,就是将虚机的 base vmdk 指向目标快照的 vmdk,其结果是自从目标快照创建后的一切改动都没有了。
1.3 VMware API
VMware 提供非常丰富的 API:

其中,我们可以将与与备份相关的API分为两类,一类是控制平面的API,它们主要用做管理 vSphere 虚拟化环境;另一类是数据平面API,它们用于操作虚机的虚拟磁盘。
1.3.1 VMware API 和 SDK
VMware 通过 Web Service 向客户端提供访问接口,这些接口可用于管理虚机和其他虚拟设施,包括数据中心(datacenter),数据存储(datastore), 网络(network)等。它还提供了包括Java, .NET, Python, Perl, REST, 以及 Ruby 等几种语言在内的 SDK。对于其他语言,则需要通过 SOAP 协议访问其 web service,gSoap 是一种比较常见的用于C/C++语言编写 web service 客户端程序的套件。
详细情况请阅读 https://www.vmware.com/support/pubs/sdk_pubs.html
1.3.2 VDDK 和 VADP
VDDK 全称是 Virtual Disk Development Kit(虚拟磁盘开发包),它能帮助开发人员创建访问虚机存储的应用。VDDK 基于 Virtual disk API。
Virtual disk API,即 VixDiskLib,是一组操作 VMDK 格式的虚拟磁盘文件的函数。它的主要功能包括:
- create, convert, expand, defragment, shrink, and rename 虚拟磁盘文件
- 创建 redo logs 和删除 vmdk 文件
- 访问 vmdk 文件中任意数据,以及读取元数据
- 连接到远端 vSphe 存储,使用高级的传输方式,包括 SAN (备份程序所在的服务器能够直接通过 FC 或者 iSCSI 和虚机磁盘所在的存储连接),hotadd (虚拟磁盘附加到备份程序所在虚机成为其一个磁盘) 和 LAN (备份程序通过 LAN 访问虚拟磁盘)。
VADP 全称是 VMware Storage APIs - Data Protection(VMware 存储API-数据保护),它使用 virtual disk API 和部分 vSphre API 来创建和管理虚机的快照,支持全量和增量备份。
1.4 CBT (Changed Block Tracking 块修改跟踪)
CBT 是 VMware 在 vSphere 4.0 版本引入的为了实现增量备份的一个功能。VDAP 使用该功能,使得基于它开发的各种虚机备份应用能够做到增量备份。

相对于全量备份时将vmdk 的全部数据块都保存下来(左图),基于 CBT 的增量备份只保存自从上次备份以来的发生了变化了的数据块(右图)。ESXi 为每个开启了 CBT 的虚机的虚拟磁盘都创建了一个 ctk 文件,它用于保存变化块的元数据。该功能将会对磁盘带来一点性能损失,因为,不使用的时候,可以关闭它,但是它对备份带来的好处是显而易见的。
获取 CBT 变化块的函数的定义为:QueryChangedDiskAreas(snapshot, deviceKey, startOffSet, changeID)。其中,
- snapshot 代表当前的快照,也就是“变化”时间段的后端点;
- deviceKey 是目标虚拟磁盘的 device ID;
- startOffSet 是开始获取变化块的offset;
- changeID 是指“变化”时间段的前端点,即老的快照的 changeID。
其结果类似 “(117768192, 65536),

