7 开发vShpere备份解决方案

本章的内容包如何针对vSphere上的虚拟机编写备份和还原软件。你可以查看第一节以获取关于程序的结构的有关帮助。关于如何实现底层的备份代码,请阅读其他章节。你需要熟悉虚拟机、快照、ESXivCenter以及Java

设计和实现概要

vSphere上,备份通常需要创建快照,以有效的获得虚拟机的一个静态的镜像。快照是一个虚拟机在特定时间点上的视图,允许快速、干净的备份操作。快照还提供了一种叫做变更块跟踪的增量备份机制。

为了备份vSphere上的虚拟机,VMware建议使用两种开发语言的解决方案。首先,使用Java开发备份程序,完成主机的通信、创建临时快照、记录虚拟机配置、删除快照等任务,然后使用C++C来编写VDDK程序,将快照的虚拟磁盘数据传输到备份介质上。

还原时,VMware推荐两种语言的开发方案。首先使用Java关闭虚拟机或者重新创建目标虚拟机,并还原相关的配置。然后使用C++C编写VMDK程序,将备份介质上保存的数据传输到虚拟磁盘。

备份过程

下面是关于vSphere虚拟机备份的一般步骤:

1连接需要备份的虚拟机所在的ESXi主机。这个步骤还需要判断主机上的虚拟机的组织和描述信息。

2使用vSphereAPI通过主机创建目标虚拟机的快照。虚拟机将会继续运行,而快照则是一个静态的视图。

3获取虚拟磁盘数据和虚拟机的配置信息(vim.vm.ConfigInfo)

4ESXi主机上,使用VDDK(CC++程序)打开并读取虚拟磁盘和快照文件。将它们和配置信息一起复制到备份媒体。

5使用vSphereAPI,通过主机删除备份快照。

服务器通信

在一个典型的包含多ESXi主机的vSphere部署中,通过vCenter服务器管理你这些ESXi主机,并且可以在主机之间移动虚拟机(vMotion)来实现负载均衡,或者关闭一些ESXi主机来节约电能。VMware建议备份应用和vCenter服务器进行通信,而不是独立的ESXi主机。

vCenter服务器对vSphereWeb服务的开发者而言,提供了位置的透明性。vCenter服务器跟踪虚拟机在ESXi主机之间的迁移,将SDK的操作指向当前运行虚拟机的ESXi主机。使用vSphere Web服务接口,可以备份一个虚拟机上的所有虚拟磁盘。

当使用vSphereSDK进行操作时,vCenter和独立的ESXi主机是一样的处理。使用vCenter管理器,就不需要直接连接到独立的ESXi主机。本章剩下的内容对vCenter服务器或者ESXi主机都有效。

为了减少vSphere使用的资源,VMware建议最小化连接或会话的数量。对任何和vSphere进行通信的程序来说,最好的方法都是创建一个会话,并在所有需要和vSphere交互信息的模块中共享。这意味了如果你的应用支持多线程,你的程序需要使用访问控制块来对连接的访问进行互斥。

你的应用程序在登陆到vSphere后需要一个“会话(session)”对象,所有的vSphereSDK操作都从这个会话开始。使用vSphere API,你可以创建“会话有效(Session specific)”的对象,使用其他会话的应用程序不会知道这个对象。

托管对象的信息容器(Information Containers as Managed Objects)

VMware的文档介绍了关于托管对象(managed object)和它的句柄(handle)的概念,称为托管对象应用(managed object referenct, moRef)。你可能对使用一些繁琐的方式获取管理对象的配置和状态信息很感兴趣。通过服务器连接创建很多繁琐内容具有很多缺点,它很慢。有一个新的机制能够有效的获取这些状态信息:PropertyCollector

管理对象的更多信息

vSphereAPI和对象模型的相关文档描述了大量的托管对象。有五种基本的托管对象类型,它们描述了服务器的组织结构,其他的托管对象可以看作是这五种基本对象的详细扩展。

目录(Folder)

数据中心(Datacenter)

计算资源(ComputeResource)

资源池(ResourcePool)

虚拟机(VirtualMachine)

所有管理对象都有一个moRef指向它们的父托管对象。父对象的moRef允许你重新组织vSphere SDK导出的对象结构。通常情况下,这个结构类似于下面这行的树形结构:

根目录(Root Folder) > 数据中心(Datacenter) > 计算资源(ComputerResource) > 资源池(ResourcePool) > 虚拟机(VirtualManchine)

这个主题可能会改变,取决于你是连接到vCenter还是直接连接到ESXi主机,但是整体组织和上面的类似。每个托管对象都有一个名称(Name)属性。

你想要备份的虚拟机以及相关的快照(扩展托管对象VirtualMachineSnapshot)都通过moRef来指定。

托管对象应用(Managed ObjectReferences)

托管对象引用(moRef)实际上就是一个句柄,而不是托管对象本身。可以确定的是,moRef总是保存着一个唯一的值,这个唯一值仅和你连接的vSphere实例有关。例如,如果vCenter服务器管理一个ESXi主机簇,每一个ESXi主机都会维护自己的托管对象引用命名空间,并且vCenter必须维护一个托管对象引用命名空间来表示所有的服务器。当一个ESXi主机通过vCenter来表示时,vCenter必须保证这个托管对象引用的唯一性。vCenter在自己的命名空间中创建这个唯一的托管对象引用,它和ESXi针对相同的托管对象生成的引用是不同的。

vSphere示例(vCenter或者ESXi)尝试在会话间保存虚拟机的moRef,但是不能保证它们的一致性。例如,注册和反注册可能会修改虚拟机的moRef。因此,无法保存一个moRef并期望它在未来的会话或不同的vCenter服务器中仍然有效。

不同vCenter的唯一ID

在一个vCenter服务器上,moRef唯一的标识一个虚拟机。如果你需要在多个vCenter服务器间跟踪并保存虚拟机备份,你可以喝instanceUuid一起使用moRef。你可以通过下面的链接查看instanceUuid的信息:

https://<vcserver>/mob/?moid=ServiceInstance&doPath=content.about

直接连接到ESXi时,主机地址和moRef唯一的标识一个虚拟机。然而这个moRefvCenter返回的可能不同(this moRef could be differentfrom the one that vCenter Server returns, hence the fallback to instanceUuid.)。

获取状态和配置信息

为了保存在还原时需要用到的虚拟机配置信息,你可以使用PropertyCollector获取虚拟机的配置信息。

PropertyCollector是一种在应用的高层更加高效的机制,获取所有感兴趣的托管对象。它提供了方法能够更新这些对象的先前状态发生变化的内容(It has methods forproviding updates that indicate only changes to the previous state of theseobjects)。有两种方法可以获得这些更新:

  • 轮询检查修改。结果要么是“没有变化”,要么是一个包含变化的对象。这种方法的优点是除了轮询和报告外,不需要消耗网络流量。

  • 等待更新基本上是一个PropertyCollector的阻塞调用。你需要使用一个线程来等待这个调用来防止阻塞。这种机制的优点是直到一些修改需要被通知之前,通信不需要流量。

PropertyCollector相当强大,但是需要格外关注它的细节,其中备份相关的特性在“底层备份细节”一节中描述。接下来的内容关注PropertyCollector的详细内容。

PropertyCollector数据

本文档假设二你需要保持对vCenter服务器上的配置数据的修改的持续关注,且计划使用PropertyCollector的更新跟踪功能。

PropertyCollector需要两个相当复杂的参数:PropertySpec以及ObjectSpecObjectSpec告诉PropertyCollector从哪去查找需要的数据。vSphere中的配置信息是以目录树的形式组织的,ObjectSpec必须描述怎样遍历树以获取数据,结果就是一系列复杂的、嵌套的、递归的指令。幸运的是,一旦你决定了获取数据的位置,用于决定vSphere对象结构的ObjectSpec就是一个静态的对象。请查看“理解ObjectSpec”一节中代码例子。

PropertySpec是需要获得的属性信息的列表。制定一个列表以包含所有需要的信息可能会花些功夫,但是一旦完成了,它同样也是个静态的对象。

PropertyCollector返回的数据是一个称为PropertyFilterUpdate的容器类,它包含一个ObjectSet,其中有一个一个的对象属性改变列表。这个容器中的每一项都由下面键中的一个来标识:enter(add)leave(delete),以及modify。第一个数据请求时,会包含所有数据,每一项都被标记为enter”。

PropertyCollector返回的结果是随机排序的。因为所有的对象都有一个“父”属性,你可以使用“parent”属性在内存中重建一棵树,来重建这个组织结构。根目录是一个唯一没有“父”属性的目录。

有用的属性信息

PropertyCollector返回的数据中,你可以从虚拟机托管对象中找到备份有关的大部分信息,包括:

  • 虚拟磁盘名称,类型,容量。

  • 虚拟机类型和配置创建虚拟机时会有用。这些信息包括内存大小和CPU的个数。

  • 显示名称这些名称显示在vSphere客户端之类的VMware产品上。你需要保存这些名称,并在你的产品和Vmware产品之间保持一致性。

VMware支持多种虚拟磁盘的实现。虚拟磁盘的实现方式很重要,因为:

  • 还原时,你需要使用和源虚拟机一样的磁盘类型来创建虚拟磁盘。

  • 通过直通型原始磁盘映射(RDM)支持的磁盘通常会绕过ESXi的存储堆栈(A disk backed by a pass-throughraw device mapping(RDM) mostly bypasses the ESXi storage stack)。你不能对这种类型的磁盘创建快照。你不能通过本文档中介绍的方法,使用快照备份直通型原始磁盘映射磁盘。

执行备份操作

当你的程序获得了能够备份的信息后,就可以执行备份了。备份过程分为三个步骤:

  • 在目标虚拟机上创建临时快照。

  • 从目标虚拟机上获取备份数据,并保存备份数据。

  • 删除临时快照。

备份的前提

要完成备份,程序需要表7-1中所示的相关权限。

wKiom1PsJb7wR6nhAACOOgcc_8o650.jpg

创建临时快照

创建快照的底层细节在“创建快照”一节进行了描述。将quiesce标识设置为TRUE使文件系统处于静置状态,否则快照将呈现出一种过渡期的系统状态,还原这种数据可能会有破坏性。另一个memory标识允许你在快照中包含开机状态下的虚拟机的内存状态。备份不需要这些,所有设置为False

修改块跟踪(Changed Block Tracking)

vSphere 4开始提供的这个特性,为虚拟磁盘的增量或差异备份提供了基础。你的应用程序可以只备份QueryChangedDiskAreas返回的修改的数据。硬件版本为7或更新的虚拟机支持修改块的跟踪。这些虚拟机的托管对象中包含一个changeTrackingSupported属性。更多详细内容请查看“虚拟磁盘修改块跟踪”一节。

获取备份数据

你创建的虚拟机快照就是虚拟磁盘的备份“版本(versions)”。为了标识这些磁盘,需要获得刚刚创建的快照的moRef。从这个快照的moRef中,你可以获取磁盘的名称和路径。“备份虚拟磁盘”一节进行了具体的描述。

需要时VixDiskLib来读取虚拟磁盘的数据。这个库向编程人员隐藏了如果从虚拟磁盘和它的重做日志获取数据的细节。例如,备份时你调用VixDiskLib_Open()VixDiskLib_Read()函数。VixDiskLib允许以扇区为边界访问磁盘数据,传输的大小是扇区大小的整数倍。

访问ESXi主机上的磁盘时,VixDiskLib 1.0通过网络传输虚拟磁盘的数据。新的VixDiskLib包含了增强的API,你可以请求到虚拟备份应用的更有效的数据路径,如直连SAN访问或者热添加磁盘(direct SAN access or HotAddingdisk to a virtual backup appliance)。这些有效的路径仅需要少量的代码修改,例如,使用VixDiskLib_ConnectEx()代替简单连接。

虚拟磁盘的另一部分信息是元数据:描述虚拟磁盘配置信息的一系列键值对。元数据信息可以通过VixDiskLib函数VixDiskLib_GetMetadataKeys()VixDiskLib_ReadMetadata()获得。你需要和备份数据一起保存这些元数据,因为你需要重新创建虚拟磁盘。

VixDiskLibAPI运行备份应用执行虚拟机的完全备份。更新的VixMntapi库可以获取虚拟磁盘中的客户机操作系统的信息,所以你的备份应用可以判断操作系统的类型。这允许将卷挂载到设备节点,这样你的应用就可以执行面向文件的备份和还原。

删除临时快照

备份过程的最后操作就是删除临时快照。这个快照不再需要,且会影响虚拟机的性能,以及占用存储空间。

还原过程

你的软件可以按照下面两种情况的一种:恢复到保存状态,或者灾难恢复。

将已存在的虚拟机还原到原状态

1连接到服务器,关闭目标虚拟机。

2通过服务器访问虚拟磁盘。如果使用高级传输模式(SANHotAddNBDSSL),你还必须在还原数据前创建快照。

3使用VixDiskLib从备份数据中传输磁盘镜像。可用时返回并删除快照(Revert-to and deletesnapshot, if applicable)

重新创建虚拟机(灾难恢复)

1连接服务器

2使用从vim.vm.ConfigInfo备份的配置信息创建新的虚拟机和虚拟磁盘。

3使用VixDiskLib将磁盘数据传输到新创建的虚拟磁盘。虚拟磁盘数据包括磁盘格式信息,所以你不需要再在虚拟磁盘上创建任何类型的文件系统。

还原操作

下面分别描述了两种情况下的还原操作:

  • 将现有的虚拟机还原到旧的状态

  • 创建新的虚拟机

还原的前提

要完成还原操作,调用程序需要获得表7-2中的权限。

基于安全方面的原因,程序对正在运行的虚拟机的磁盘没有写权限。在关闭之前,你需要判断虚拟机的运行状态。

运行状态信息能够存PropertyCollector中获得,并且如果你保持这个信息持续更新,你的应用程序总是会知道虚拟机的运行状态。要改变运行状态,你必须要有虚拟机的moRef。通过服务器连接,在PowerOnVm_Task调用中传递这个moRef,对于虚拟机的关闭,调用PowerOffVM_Task方法。

wKiom1PsJZqypgxKAACA2yQulco971.jpg

将已有虚拟机还原到先前状态

下面的步骤将虚拟机还原到一个保存的特定状态:

  • 1 关闭虚拟机(如果它不处于关闭状态)

  • 2 要使用高级传输模式(SANHotAddNBDSSL),你必须在还原虚拟机数据之前创建一个快照。

  • 3 还原虚拟机磁盘的数据。如果在备份时没有已经存在的快照,仅有备份时创建的快照,那么只还原基准磁盘。

还原磁盘数据需要你获得虚拟磁盘的当前名称,这个过程和“从目标虚拟机获取备份数据”一节中描述的相似,除非你直接从虚拟机而不是从快照获取信息。备份磁盘数据的目标必须是实际的磁盘名称(包括一些序列号),因为当前虚拟机的磁盘可能从一个或多个快照继承而来。

还原磁盘数据需要使用VixDiskLibVixDiskLib_Write()函数打开虚拟磁盘,你的应用程序可以利用它写数据。VixDiskLib函数以偶数扇区为边界传输数据,且传输长度必须显示扇区大小的偶数倍。

虚拟磁盘已经存在,所有不需要还原“从目标磁盘获取备份数据”一节中提到的配置信息。

  • 4 对于SAN传输模式,还原并删除在步骤2中创建的磁盘。这些步骤执行失败,会导致虚拟机不能开机。

创建新虚拟机

从备份数据创建虚拟机的步骤如下:

  • 1 创建虚拟机

创建虚拟机时,需要使用在备份时保存的虚拟机配置信息。还原软件的使用者应该可以重新命名虚拟机,因为他们可能需要克隆或迁移虚拟机。你还需要考虑提供一个机会给他们修改虚拟机的布局(如在不同的数据存储中保存虚拟磁盘)。在创建虚拟机的同时创建虚拟磁盘。这个过程相当复杂,请查看后续的“备份过程的底层实现”一节。

  • 2 还原虚拟磁盘数据

这个过程和还原虚拟磁盘的内容相似,除了以下内容:你必须要在还原虚拟磁盘的备份数据之前,调用VixDiskLib_WriteMetadata()函数写入所有的磁盘配置键/值对数据。然后调用VixDiskLib_Write()函数还原虚拟磁盘数据,和之前介绍的步骤3一样。

  • 3 打开虚拟机的电源。

访问虚拟磁盘文件

对于备份程序来说,可能有必要访问虚拟磁盘的单个文件或一组文件。例如,数据保护程序可能需要按要求还原单个的文件。

你可以在和VixDiskLib一起发布的VixMntApi库中找到相关的接口来实现这个功能。VixMntApi允许虚拟机的磁盘或卷在需要时被挂载并检查。VixMntApi提供了文件系统级的访问,而VixDiskLib提供了扇区级的访问。

挂载虚拟磁盘

1找到快照中所有虚拟磁盘的位置名称。

2调用VixDiskLib_Open()函数打开所有的虚拟磁盘。你会得到一些VixDiskLib的句柄,你应该保存在一个数组中。

3调用VixMntapi_OpenDiskSet()函数,并传递你在步骤2中获得的VixDiskLib句柄,以创建一个VixDiskSetHandle

4VixDiskSetHandle作为参数,调用VixMntApi_GetVolumeHandles()获得一个VixVolumeHandle句柄的指针指向磁盘集中所有卷。

5调用VixMntApi_GetOsInfo()来判断相关操作系统的类型,并决定从哪查找重要的信息。

6对于重要的卷,调用VixMntApi_mountVolume()以及VixMntApi_GetVolumeInfo(),它们揭示了卷是如何组成的。

7如果你想要了解客户机操作系统如果看待这些卷上的数据,你可以从VixMntApi_GetVolumeInfo()返回的VixVolumeInfo结构中获取相关信息。例如,你可以使用VixVolumeInfo::symbolicLink作为代理路径访问虚拟磁盘的文件系统,并可以使用普通的打开、读、写调用。

一旦完成了挂载卷的文件访问,需要调用VixMntapi来关闭你刚刚创建的抽象层,这些调用包括:

对每一个卷句柄调用VixMntApi_DismountVolume()函数。

VixMntapi_FreeOsInfo()以及VixMntapi_FreeVolumeInfo()函数。

VixMntApi_CloseDiskSet()函数。

之后就剩下开始时获取的VixDiskLib的句柄,你需要正确的释放它们。

更多VADP细节

前面的章节介绍了怎样联系vSphere并从它获取信息,以及如何备份、还原虚拟磁盘。下面的章节将会从底层细节描述相同的信息。