VMware虛擬磁盤編程指導(四)

4 虛擬磁盤API函數

本章提供的虛擬磁盤API的函數概述。在按字符順序介紹的API函數之後,將會重點關注每個函數如何使用,和它們在程序中的使用順序一致(除了高級傳輸函數SANHotAdd在關閉函數以後介紹)

虛擬磁盤庫函數

可以在VMDK安裝目錄的doc子目錄中找到index.html文件,使用Web瀏覽器打開它就可以查看VixDiskLib的接口參考文檔。在大多數參考手冊中,函數通過字母順序進行組織,但是在本章節中,函數通過它們如何被調用來組織。

當文檔中提到一個函數僅支持主機磁盤時,它意味着VMware工作站或其他類似產品上的虛擬磁盤鏡像。存放在VMFS分區上由ESX/ESXivCenter服務器管理的虛擬磁盤被稱爲託管磁盤“(managed disk)

本節討論的函數基於第三章中的概念和相關數據結構。

如果需要訪問VMFS上虛擬磁盤,I/O操作默認情況下都需要通過ESX/ESXi主機完成,它們管理物理磁盤存儲。如果要使用直接訪問SAN存儲的函數調用,開始時就需要調用VixDiskLib_ConnectEx()函數,正如高級傳輸接口中描述的那樣。

函數概述

4-1中按字母順序列出了虛擬磁盤API中的函數。

4-1. 虛擬磁盤庫函數

函數描述
VixDiskLib_Attach將子磁盤鏈附加到父磁盤鏈上。
VixDiskLib_Cleanup清除遺留的傳輸信息。
VixDiskLib_Clone將虛擬磁盤拷貝到指定目標,並轉換成適當的格式。
VixDiskLib_Close關閉一個打開的虛擬磁盤。
VixDiskLib_Connect連接到虛擬磁盤庫以獲取相關服務。
VixDiskLib_ConnectEx連接到高級的傳輸。
VixDiskLib_Create根據指定參數創建虛擬磁盤文件。
VixDiskLib_CreateChild針對主機磁盤創建一個子磁盤(重做日誌或差異磁盤)
VixDiskLib_Defragment對虛擬磁盤的扇區進行碎片整理。
VixDiskLib_Disconnect斷開虛擬磁盤庫的連接
VixDiskLib_EndAccess通知主機可能需要遷移一個虛擬機。
VixDiskLib_Exit釋放庫佔用的所有資源。
VixDiskLib_FreeErrorText釋放GetErrorText獲得的消息緩存。
VixDiskLib_FreeInfo釋放GetInfo分配的緩存。
VixDiskLib_GetErrorText獲取錯誤碼的文字描述。
VixDiskLib_GetInfo獲取虛擬磁盤的信息。
VixDiskLib_GetMetadataKeys獲取虛擬磁盤元數據中的所有鍵。
VixDiskLib_GetTransportMode獲取當前的傳世模式。
VixDiskLib_Grow擴展已有虛擬磁盤的大小。
VixDiskLib_Init初始化老的虛擬磁盤庫,已經被InitEx代替。
VixDiskLib_InitEx初始化新的虛擬磁盤庫。
VixDiskLib_ListTransportModes獲取可用的傳輸模式。
VixDiskLib_Open打開虛擬磁盤。
VixDiskLib_PrepareForAccess通知主機避免遷移虛擬機。
VixDiskLib_Read從打開的虛擬磁盤上讀取數據。
VixDiskLib_ReadMetadata從虛擬磁盤的元數據中讀取指定鍵的值。
VixDiskLib_Rename重新命名虛擬磁盤。
VixDiskLib_Shrik從虛擬磁盤中回收空的扇區。
VixDiskLib_SpaceNeededForClone計算克隆一個虛擬磁盤需要的空間大小(字節)
VixDiskLib_Unlink刪除指定的虛擬磁盤。
VixDiskLib_Write向打開的虛擬磁盤中寫入數據。
VixDiskLib_WriteMetadata使用鍵/值對更新虛擬磁盤的元數據。

啓動

VixDiskLib_Init()以及VixDiskLib_Connect()函數在所有的虛擬磁盤程序中都應該存在。VixDiskLib_Init()已經被VixDiskLib_InitEx()代替。

初始化庫

VixDiskLib_Init()初始化就的虛擬磁盤庫,參數中的majorVersion以及minorVersion表示VDDK的發行版本。第三、四、五個參數知名日誌、警告、錯誤的處理函數接口。DLL文件以及共享對象存放在libDir參數指定的目錄中。

VixErrorvixError = VixDiskLib_Init(majorVer, minorVer, &logFunc, &warnFunc,&panicFunc, libDir);

由於國際化的限制,在程序開始時每個進程中只能調用一次VixDiskLib_Init()函數(You should callVixDiskLib_Init() only once per process because of internationalizationrestrictions, at the beginning of your program)。應該在程序結束時調用VixDiskLib_Exit()來清除各種資源。對於多線程程序,你需要編寫自己的logFunc函數,應該默認的函數並不是線程安全的。

大部分情況下,你都需要使用VixDiskLib_InitEx()代替VixDiskLib_Init(),它允許你指定配置文件。

連接工作站或服務器

VixDiskLib_Connect()將庫連接到本地VMware主機或者遠程服務器。對於本地系統的主機磁盤,大部分連接參數都田null值。對於ESX/ESXi主機上的託管磁盤,需要指定虛擬機的名稱,ESX/ESXi主機的名稱,用戶名,密碼,以及端口。

vixError= VixDiskLib_Connect(&cnxParams, &srcConnection);

可以使用VixDiskLibSSPICreds連接參數來啓用SSPI(Security Support ProviderInterface)認證。SSPI的優點是不用再配置文件或註冊表中使用明文存儲密碼。如果要使用SSPI,需要滿足下面的條件

  • 必須之間連接到vSphere服務器或VirutalCenter2.5或更新版本的服務器。

  • 應用程序和連接必須使用兩種賬戶之一,使用以下兩種方式建立連接:

使用和代理以及vSphere服務器上的用戶名/密碼認證相同的用戶上下文。

或者使用域用戶。應用程序嘗試使用本地系統賬戶上下文進行連接將會失敗。

  • 用戶上下文在代理上必須具有管理員權限,並且屬於vSphereVirtualCenter分配的VCB備份角色。

如果啓動符合上述條件,就可以通過將USERNAME設置到__sspi__來啓用SSPI認證。對於SSPI,密碼必須設置,但是被忽略,可以設置爲空(“”null)

在結束程序前總是要調用VixDiskLib_Disconnect()

VMX說明

VMware平臺的產品中,.vmx是一個文本文件,通常存放在和虛擬磁盤磁盤文件相同的目錄中,保存虛擬機的配置。虛擬機可執行(Virtual MachineeXecutalbe, VMX)進程是虛擬機在用戶空間的一個組件。虛擬磁盤庫通過VMX進程連接到虛擬機存儲。

當指定連接參數時,推薦的vmxSpec的語法如下:

  • 虛擬機的託管對象引用(managed object reference),可以在程序中使用PropertyCollector託管對象獲得的一個封裝(opaque)對象:

moRef=<moref-of-vm>

ESX/ESXi主機上的虛擬機或磁盤快照的moRef,通常和vCenter服務器管理的虛擬機或磁盤快照的moRef不同。下面是兩個moRef,一個是ESXi,一個是vCenter服務器,引用的都是同一個快照。

moRef= 153

moRef= 271

磁盤操作

這些函數創建,打開,讀,寫,查詢,關閉虛擬磁盤。

創建新的主機磁盤(Hosted Disk)

連接到主機後,就可以使用VixDiskLib_Create()在本地創建一個新的虛擬磁盤。在createParams參數中,需要指明磁盤類型,硬件版本,扇區的容量。這個函數支持主機磁盤。對於託管磁盤,首先需要創建一個主機類型的虛擬磁盤,然後使用VixDiskLib_Clone()將虛擬磁盤轉換爲託管類型。

vixErr= VixDiskLib_Create(appGlobals.connection, appGlobals.diskPath,&createParams, NULL, NULL);

FAT32以及FAT文件系統上,VixDiskLib_Create()要求虛擬磁盤的大小不能超過4GBNTFS文件系統上,虛擬磁盤的大小不超過16TB-54KB,在ReFSexFAT文件系統,不能超過264-1。在最新的vSphere5.5以及更新版本中,將支持大於2TBVDDK文件。

包括NFS3在內的基於POSIX的文件系統不再有2GB的文件大小限制。儘管創建磁盤時採取了多種檢查以避免超大文件,但是用戶還是需要自行設置NFS2Linux2.4(EFS)上的2GB大小限制。

打開本地或遠程磁盤

連接到工作站或服務器後,VixDiskLib_Open()就可以打開一個虛擬磁盤了。如果使用SANHotAdd傳輸模式,需要有一個存在的快照才能打開遠程磁盤進行寫操作。

vixError= VixDiskLib_Open(appGlobals.connection, appGlobals.diskPath,appGlobals.openFlags, &strHandle);

可以指定以下標誌:

VIXDISKLIB_FLAG_OPEN_UNBUFFERED禁用主機磁盤緩存。

VIXDISKLIB_FLAG_OPEN_SINGLE_LINK針對主機磁盤,打開當前的磁盤鏈接,而不是真個磁盤鏈。

VIXDISKLIB_FLAG_OPEN_READ_ONLY只讀模式打開虛擬磁盤。

讀磁盤扇區

通過指定開始扇區和扇區個數,VixDiskLib_Read()從打開的虛擬磁盤中讀取一片連續的扇區。扇區的大小可以不一樣,但是<VixDiskLib.h>文件中已經定義爲512個字節,因爲VMDK文件使用這個扇區大小。

vixError= VixDiskLib_Read(srcHandle, i, j, buf);

寫磁盤扇區

VixDiskLib_Write()向打開的磁盤中寫入一個或多個扇區。這個函數的第4個參數buf,長度必須是VIXDISKLIB_SECTOR_SIZE的整數倍字節。

vixError= VixDiskLib_Write(srcHandle, i, j, buf);

關閉本地或遠程磁盤

VixDiskLib_Close()關閉打開的虛擬磁盤。

VixDiskLib_Close(srcHandle);

獲取磁盤信息

vixError= VixDiskLib_GetInfo(srcHandle, diskInfo);

VixDiskLib_GetInfo()獲取打開的虛擬磁盤的相關信息,分配並填充VixDiskLibDiskInfo結構,其中一部分信息和元數據相同。

釋放磁盤信息

這個函數釋放由VixDiskLib_GetInfo()分配的內存,避免內存泄漏。

vixError= VixDiskLib_FreeInfo(diskInfo);

錯誤處理

這些函數對於處理錯誤信息很有用。

獲取錯誤描述

VixDiskLib_GetErrorText()返回一個數字錯誤碼代表的錯誤的文字描述。

char*msg = VixDiskLib_GetErrorText(errorCode, NULL);

釋放錯誤描述

VixDiskLib_FreeErrorText()釋放保存錯誤描述信息的內存緩衝區。

VixDiskLib_FreeErrorText(msg);

元數據(Metadata)

VMware提供了一套機制來處理虛擬磁盤的元數據,但是它很少被使用。

讀取元數據鍵

VixDiskLib_ReadMetadataKeys()從虛擬磁盤的元數據中獲取所有存在的鍵,而不是鍵值。這個函數需要和VixDiskLib_ReadMetadata()配合使用。

vixError= VixDiskLib_ReadMetadataKeys(disk.Handle(), &buf[0], requiredLen, NULL);

讀取元數據值

vixError= VixDiskLib_ReadMetadata(disk.Handle(), appGlobals.metakey, &val[0],requiredLen, NULL);

從磁盤元數據中獲取指定鍵的值。本地VMDK的元數據和ESX/ESXi主機上的託管磁盤的元數據並不相同。VMFS元數據保存在一個映射文件中,包括的信息由磁盤卷標、LUN或分區佈局、鏈接個數、文件屬性、鎖等。元數據還描述了可用的裸磁盤映射的存儲封裝(encapsulation of rawdisk mapping, RDM)

下面是一個簡單的元數據表。Uuid表示虛擬磁盤的全局唯一標識符。

adapterType= buslogic

geometry.sectors= 32

geometry.heads= 64

geometry.cylinders= 100

uuid= 60 00 c2 93 7b a0 3a 03 9f 22 56 c5 29 93 b7 27

更改元數據

VixDiskLib_WriteMetadata()通過指定的鍵值對來更新虛擬磁盤的元數據。如果鍵值對不存在,則會新增一項,如果鍵存在,值將會更新。鍵可以被設置爲空,但是不能刪除。

vixError= VixDiskLib_WriteMetadata(disk.Handle(), appGlobals.metakey,appGlobals.metaVal);

克隆虛擬磁盤

計算克隆需要的空間

下面的函數計算在將磁盤轉換爲可能的格式後,克隆這個虛擬磁盤所需要的空間大小,以字節爲單位:

vixError= VixDiskLib_SpaceNeededForClone(child.Handle(), VIXDISKLIB_DISK_VMFS_FLAT,&spaceReq);

注意:VixDiskLib_SpaceNeededForClone()可能不會返回正確的結果,如當使用老的磁盤類型VIXDISKLIB_DISK_VMFS_THIN時會返回VIX_E_INVALID_ARG

拷貝數據克隆磁盤

這個函數將數據從一個虛擬磁盤拷貝到另一個虛擬磁盤,並轉換相應的參數(磁盤類型、大小、硬件)

vixError= VixDiskLib_Clone(appGlobals.connection, appGlobals.diskPath, srcConnection,appGlobals.srcPath, &createParam, CloneProgressFunc, NULL, TRUE);

磁盤鏈和重做日誌(Disk Chain and Redo Logs)

VDDK相關的術語中,下面這些詞都具有相同含義:子磁盤(child disk),重做日誌(redo log),差異鏈(delta link)。從最原始的父磁盤開始,每一個子磁盤都構成了一個從虛擬磁盤的原始狀態到當前狀態的重做日誌,且每一個時間點只有一個鏈接(From the originalparent disk, each child constitutes a redo log pointing back from the presentstate of the virtual disk, one step at a time, to the original.)。下面這個僞方程式表現了備份和快照的相對複雜度:

Backupimage < child disk = redo log = delta link < snapshot

一個備份鏡像(例如存放在磁帶上的)小於一個子磁盤,因爲備份鏡像僅僅是一個數據流。一個快照大於一個子磁盤,因爲快照還包含了虛擬機的狀態,以及VMDK中的文件系統狀態。

從父磁盤創建子磁盤

通常你從父磁盤創建第一個子磁盤,然後從這個磁盤鏈的上一個子磁盤創建更多的子磁盤。如圖4-1所示,這些磁盤通過稀疏(SPRSE)格式,記錄從開始到現在發生改變過的額磁盤扇區。

wKiom1OiU1DzSxNzAADOMlV71HQ284.jpg

VixDiskLib_CreateChild()爲一個本地磁盤創建一個子磁盤(或者重做日誌)。創建子磁盤後,通常不需要打開父子磁盤或者磁盤鏈中更早的磁盤。子磁盤的vm.vmdk文件指向重做日誌,而不是父磁盤,如本例當中的vm-flag.vmdk。要訪問原始的父磁盤,或更早的子磁盤,可以針對本地磁盤調用VixDiskLib_Attach()

vixError= VixDiskLib_CreateChild(parent.Handle(), appGlobals.diskPath,VIXDISKLIB_DISK_MONOLITHIC_SPARSE, NULL, NULL);

將子磁盤附加到父磁盤

VixDiskLib_Attach()將子磁盤附件到它的父磁盤鏈中。之後,父磁盤的句柄將失效,子磁盤句柄將表示結合之後的重做日誌的磁盤鏈(the child handlerepresents the combined disk chain of the redo logs)

vixError= VixDiskLib_Attach(parent.Handle(), child.Handle());

假如你需要訪問Child1記錄的舊的磁盤鏡像,將心的Child1a的句柄附加到Child1,它能夠提供Child1a的父句柄(Attach the handle ofnew Child1a to Child1, which provides Child1a’s parent handle),如圖4-2所示。現在就可以對Child1a虛擬磁盤進行打開、讀、寫操作。wKiom1OiUyuT-eCJAAC7JWQyvLw382.jpg

-子磁盤鏈能夠有效的利用存儲空間,因爲子VMDK僅僅記錄從上一次調用VixDiskLib_CreateChild()以來發生改變的扇區。父-子磁盤鏈同樣提供了一種重做機制,允許在程序中通過VixDiskLib_Attach()訪問任何時間點的虛擬磁盤(access to any generation)

打開磁盤鏈

對於基準磁盤B,以及子磁盤C0C1C2,打開C2可以獲得B+C0+C1+C2的全部內容,而不是鏈接的磁盤扇區(not really addition linked data sectors)。打開C1則會獲得B+C0+C1的內容。

比記錄基準磁盤以及哪個子磁盤是哪個磁盤的後裔更好的解決方案是採用修改塊跟蹤(changed blocktracking)vShpere接口中有QueryChangedDiskAreas()函數。

託管磁盤的重做日誌(Redo Logs on Managed Disk)

對於vShpere上的託管虛擬磁盤,快照主要用來保存系統狀態和進行備份操作,而克隆鏈接則是爲了View桌面的配置而創建的客戶鏡像(while linked clones are create guestimages for provisioning of View desktops)。快照通常是一個父子磁盤鏈中某一個重做日誌,而克隆鏈接通常包含基於同樣父磁盤的多個重做日誌。

vSphere5.5中,克隆鏈接架構的修改,提供了備份還原的效率(the handling oflinked clone hierarchies was changed to improve the efficiency of backup andrestore)。磁盤對象包含了一個“磁盤置備(disk backing)”,它包括一直到達基準磁盤的一個或多個父置備對象(contains one or moreparent backing objects until the base disk is reached)。這允許我們訪問父子磁盤鏈中任意位置。

對於一個乾淨的從未使用過的基準虛擬機而言,克隆鏈接結構或者快照鏈總是包含正確數量的鏈中節點的父置備對象(the linked clonehierarchy or snapshot chain always has the proper number of parent backingobjects for the nodes in the chain)

VDDK沒有任何方便的方法,能夠備份或還原克隆鏈結構以及快照鏈。備份程序如果要支持這個特點,就需要自己查找並保存這個結構。

如果基準磁盤或子磁盤有一個額外的快照,或者被用來創建克隆鏈接的重做日誌沒有被刪除,或者任何父或子磁盤需要磁盤合併或處在非法的快照狀態,就可能有額外(很多)的父置備對象。(When the base disk or a childdisk has an extra snapshot, when redo logs used to create linked clones werenever deleted, or when any parent or child disk in the chain needs diskconsolidation or is in bad snapshot state, it is possible to have extra(toomany) parent backing objects.)

還原應用絕不應該假設父置備對象的個數(restore applicationsshould never assume the correct number of parent backing objects)。它們應該遞歸查詢,直到找到基準父置備對象爲止,並確定正確的父置備隊形匹配的子節點何時還原(make sure whenrestoring leaf nodes that the correct parent backing object matches the nodebeing restored)

管理磁盤操作

這些函數重命名、擴展、整理、壓縮、刪除虛擬磁盤。

重命名磁盤

VixDiskLib_Rename()修改一個虛擬磁盤的名稱。只能在虛擬機關閉時調用此函數。

vixError= VixDiskLib_Rename(oldGlobals.diskpath, newGlobals.diskpath);

擴展本地磁盤

VixDiskLib_Grow()通過增加扇區擴展一個已存在的虛擬磁盤。這個函數只支持本地磁盤,不支持託管磁盤。

vixError= VixDiskLib_Grow(appGlobals.connection, appGlobals.diskpath, size, FALSE,GrowProgressFunc, NULL);

磁盤整理

VixDiskLib_Defragment()對一個已存在的虛擬磁盤進行碎片整理。碎片整理對稀疏類型(SPARSE)的文件有效,對平面類型(FLAG)的磁盤不做任何事情,這個函數直接返回VIX_OK。這個函數支持本地磁盤,而不支持託管磁盤。

vixError= VixDiskLib_Defragment(disk.Handle(), DefragProgressFunc, NULL);

磁盤整理合並2GB範圍內的數據,將數據遷移到更低的範圍內(Defragment consolidatesdata in 2GB extents, moving data to lower-numbered extents)。它和客戶機系統內的磁盤整理工具是不相關的,如Windows上磁盤>屬性>工具>碎片整理,以及Linux Ext2文件系統的defrag命令行。

VMware推薦由裏到外的磁盤整理:首先使用虛擬機進行磁盤整理,然後使用這個函數或者VMware的整理工具,最後使用宿主操作系統。

壓縮磁盤

VixDiskLib_Shrik()從一個虛擬磁盤中回收沒有使用的空間,未使用空間就是被標記爲0的塊。比起提前分配的FLAT類型文件,這對SPARSE類型文件更有效,能夠獲得更多空間。成功時這個函數會返回VIX_OK。這個函數支持本地磁盤,但不支持託管磁盤。

vixError= VixDiskLib_Shrink(disk.Handle(), ShrinkProgressFunc, NULL);

VMware系統工具中,“prepare”清空VMDK中未使用的塊使得“shrink”能夠回收它們。使用VixDiskLib_Write()清空未使用的塊,並使用VixDiskLib_Shrink()來回收空間。壓縮並不改變虛擬磁盤的容量,但是使得更多空間可用。

刪除磁盤

VixDiskLib_Unlink()刪除指定虛擬磁盤的所有空間,刪除磁盤數據。這和命令行中的刪除或擦除類似。

vixError= VixDiskLib(appGlobals.connection, appGlobals.diskpath);

關閉

所有的虛擬磁盤接口應用程序在程序結尾都應該調用這些函數。

斷開服務器連接

VixDiskLib_Disconnect()斷開已有連接。

VixDiskLib_Disconnect(srcConnection);

清空並退出

VixDiskLib_Exit()在退出前清空庫資源。

VixDiskLib_Exit();

高級傳輸API

針對託管磁盤,VDDK的第一個版本要求到ESX/ESXi主機的網絡訪問(LAN或者NBD傳輸)。從VDDK1.1開始,程序可以直接訪問存儲設備上的虛擬磁盤,而不需要LAN。直接的SAN訪問提高了I/O性能。有一系列的API可以用於選擇最有效的傳輸方法,包括:

VixDiskLib_InitEx()—— 初始化高級傳輸庫。你必須指定庫的位置。在你的應用中替換掉VixDiskLib_Init()

VixDiskLib_ListTransportModes()—— 枚舉出虛擬函數庫支持的傳輸方法。

VixDiskLib_ConnectEx()—— 使用你選擇的或可用的最佳傳輸模式建立連接,訪問虛擬磁盤。當前它並不檢查傳輸類型的有效性。在你的應用程序中替換掉VixDiskLib_Connect()

初始化虛擬磁盤API

VixDiskLib_InitEx()代替VixDiskLib_Init()初始化新版本的庫。參數很簡單,你需要指定真實的libDir以及新的configFile參數。對於多線程程序,你需要編寫自己的logFunc,因爲默認的日誌函數不是線程安全的。在Windows上,libDir可能是C:\Program Files\VMware\VMwareVirtual Disk Development Kit,在Linux上,libDir可能是/usr/lib/vmware-vix-disklib

VixErrorvixError = VixDiskLib_InitEx(majorVersion, minorVersion, &logFunc, &warnFunc,&panicFunc, *libDir, *configFile);

VDDK和大多數其他VMware產品中,默認情況下,日誌消息會保存在臨時目錄或日誌目錄中。

下面列出了一些configFile中當前支持的內容。指定配置的正確方式是name=value,可查看示例4-1中的配置文件例子。

  • tempDirectory =“<TempDirectoryForLogging>”

  • vixDiskLib.transport.LogLevel重寫vixDiskLib傳輸(不包括NFC)函數的默認日誌級別。默認的值是3,有效範圍是066最詳細,0不做任何記錄。

  • vixDiskLib.disklib.EnableCachevixDiskLib的緩存默認是關閉的。設置爲1可以打開緩存。當信息被重複讀取或隨機訪問時,緩存可以提高性能。備份程序中,信息通常是被連續讀取,緩存實際上降低了性能。如果使用緩存,當磁盤扇區在刷新緩存之前被其他應用程序重複寫入,備份程序獲取狀態信息就有風險。

  • vixDiskLib.linuxSSL.verifyCertificates連接到Linux虛擬機時是否檢查SSL指紋。0表示關閉,1表示打開,默認值是0

超時值存儲在32位的數值中,所以你能指定的最大超時值是2G(2,147,483,648)。超時值是以毫秒爲單位的,應用於每個磁盤句柄。NFC設置應用於NBD/NBDSSL,但不適用於SANHotAdd

下面NFC相關的選線會覆蓋多個NFC函數的默認值。示例4-1中的NFC超時對應於ESXi5.x主機上的默認值。

  • vixDiskLib.nfc.AcceptTimeoutMs覆蓋NFC接收操作的默認值(3分鐘)

  • vixDiskLib.nfc.RequestTimeoutMs覆蓋NFC請求操作的默認值(3分鐘)

  • vixDiskLib.nfc.ReadTimeoutMs覆蓋NFC讀操作的默認值(1分鐘)

  • vixDiskLib.nfc.WriteTimeoutMs覆蓋NFC寫操作的默認值(10分鐘)

  • vixDiskLib.nfcFsrvr.TimoutMs覆蓋NFC文件系統操作的默認值(0,不定時等待)。如果你指定了一個值,如果文件系統在給定的時間內空閒就會發生超時。使用默認值的風險是,在罕見的災難性通信故障時,文件系統將會保持鎖定。

  • vixDiskLib.nfcF***vrWrite.TimeoutMs覆蓋NFC文件系統寫操作的默認值(沒有超時),以毫秒爲單位。如果你指定一個值,當寫操作在指定時間間隔內沒有成功完成的話,就會發生超時。

  • vixDiskLib.nfc.LogLevel覆蓋NFC操作的默認日誌級別。默認值是1,表示僅僅記錄錯誤消息。各個值得含義如下。每一級都包含更低一級的日誌。這是NFC的最終設置。

0= 靜默(最小日誌)

1= 錯誤

2= 警告

3= 信息

4= 調試

wKioL1OiU6vxrarxAADf1b6F2fU518.jpg

日誌文件位置

Linux系統上,日誌消息會默認保存在/var/log中。Windows上,它們默認保存在臨時目錄中,這個位置可能隨時發生變化。早期的Windows系統使用C:\Windows\TempWindows XP以及2003使用C:\Documents and Settings\<user>\LocalSettings\Temp\vmware-<user>VistaWindows72008則使用C:\Users\<user>\AppData\Local\Temp\vmware-<user>

在所有版本的Windows系統上,TEMP環境變量重寫了默認的臨時文件夾位置。“臨時”實際上是名不副實的,因爲臨時文件夾中從來也沒有被刪除,除非用戶或應用程序主動刪除它們。如果TEMP或者Windows默認臨時文件夾不存在,VDDK或其他VMware軟件將會使用<localAppDir>\Temp文件夾。

如示例4-1所示,你也可以指定自己的臨時文件目錄。

枚舉可用的傳輸方法

VixDiskLib_ListTransportModes()函數返回一個以冒號分隔的字符串值,表示當前支持的傳輸方法,如“file:san:hotadd:nbd”nbd表示LAN傳輸。SSL加密NBD傳輸可用時顯示爲nbdssl

printf(“Transportmethods: %s\n”, VixDiskLib_ListTransportModes());

如果所有的網絡傳輸模式都可用的話,默認的排序是 san:hotadd:nbdssl:nbd

使用直接模式的Linux SAN模式(SAN Mode on Linux Uses Direct Mode)

Linux上的SAN傳輸,讀、寫操作都使用直接(direct)”模式(O_DIRECT),意味着讀、寫都沒有使用任何緩存。直接模式阻止其他進程訪問最新數據,避免提交寫緩存前由於進程終止造成的信息丟失。如果應用遵循以下指導進行讀寫操作,就會達到最佳的效率:

SAN中執行操作的數據偏移應該是頁大小(4096)的整數倍。

數據傳輸的緩存應該是頁邊界對齊的。

傳輸的長度應該是頁大小的整數倍。

連接到VMware vShpere

VixDiskLib_ConnectEx()將庫連接到遠程ESX/ESXi主機或者VMware vCenter服務器上的託管磁盤。對於本地系統上虛擬磁盤,它的作用和VixDiskLib_Connect()相同。VixDiskLib_ConnectEx()有三個額外的參數:

  • Boolean設置爲TRUE表示只讀的訪問,通常更快,或者設置爲FALSE表示可讀、可寫。如果採用只讀連接,之後調用VixDiskLib_Open()總是隻讀的,而不管它的openFlags參數如何設置。

  • 通過連接訪問的快照的託管對象引用(MoRef)。大多數傳輸方法(SANHotAddNBDSSL)都需要這個參數,或者用於訪問這在運行的虛擬機。你還需要設置connectParams中的vmxSpec屬性。如果直接連接到ESX/ESXi主機,就提供ESX/ESXiMoRef,如果連接到vCenter服務器,傳遞vShpereMoRef,它們是不同的。

  • 可選的傳輸模式,NULL表示使用默認的傳輸方式。如果你將SAN作爲唯一的傳輸,但是SAN並不可用,VixDiskLib_ConnectEx()不會失敗,但是第一次調用VixDiskLib_Open()函數時則會失敗

VixDiskLibConnectionParamscnxParams = {0};

if(appGlobals.isRemote) {

    cnxParams.vmName = vmxSpec;

    cnxParams.serverName = hostname;

    cnxParams.credType = VIXDISKLIB_CRED_UID;

    cnxParams.creds.uid.userName = username;

    cnxParams.cred.uid.password = password;

    cnxParams.port = port;

}

VixErrorvixError = VixDiskLib_ConnectEx(&cnxParams, TRUE, “snapshot-47”, NULL,&connection);

儘管程序在調用VixDiskLib_ConnectEx()時使用NULL作爲傳輸模式參數,以使用默認的傳輸模式,如果ESX/ESXi主機上的SAN存儲可用的話,就會選擇SAN作爲傳輸模式。那麼如果程序打開一個本地存儲上的虛擬磁盤,後續的寫操作就會失敗。這時,程序就需要指明nbdnbdssl作爲傳輸模式。

參數cnxParams中,vmxSpec指向的在ESX/ESXi主機和在vCenter服務器上的託管對象引用是不一樣的:

vmxSpec= “moid=23498”;

vmxSpec= “moid=898273”;

端口(port)參數表示vCenter服務器偵聽API請求的那個端口。設置爲nullVMDK庫將使用默認的通信端口。通常是443(HTTPS)或者902(VIX自動化)。這是數據拷貝的端口,而不是SOAP請求的端口。

獲取已選的傳輸方法

VixDiskLib_GetTransportMode()函數返回針對diskHandle選擇的傳輸方法。

printf(“Selectedtransport method: %s\n”, VixDiskLib_GetTransportMode(diskHandle));

準備和結束訪問(Prepare For Access and End Access)

VixDiskLib_PrepareForAccess()函數通知vCenter管理的主機正在打開一個虛擬機磁盤,通常在備份時打開,主機應該推遲可能會干擾虛擬磁盤訪問的虛擬機操作。創建虛擬機快照前調用此函數。在內部,這個函數會禁止vSphere中的RelocateVM_Task()方法。

vixError= VixDiskLib_PrepareForAccess(&cnxParams, “vmName”);

連接函數必須指定唯一的虛擬機。打開一個託管磁盤時,需要提供管理磁盤所在ESXi主機的vCenter服務器的有效認證憑據。第二個參數僅用於跟蹤目的,且長度不超過50個字符。它可以是虛擬機的名稱或者應用程序的名稱。如果直接在ESXi主機上調用VixDiskLib_PrepareForAccess(),系統將會拋出錯誤消息:“VDDK: HostAgent is not avCenter, cannot diskable svMotion”

每一次調用VixDiskLib_PrepareForAcccess()都應該相應的調用一次VixDiskLib_EndAccess()函數。

VixDiskLibEndAccess()函數通知主機虛擬機磁盤已經被關閉,依賴於關閉磁盤的操作現在可以啓用了,如vMotion。在關閉所有虛擬磁盤並刪除所有虛擬機快照後調用此函數。通常這個函數都在VixDiskLib_PrepareForAccess()之後調用,但是你也可以在奔潰後調用它來做一次清除操作(cleanup)。在內部,這個函數會重新啓用vSphereRelocateVM_Task()方法。

vixError= VixDiskLib_EndAccess(&cnxParams, “vmName”);

下面的代碼片段中,在備份程序中使用PrepareForAccess等待存儲遷移(Storage vMotion)完成,最多等待了10分鐘。

if(appGlobals.vmxSpec != NULL) {

     for (int i = 0; i < 10; i+) {

        vixError =VxiDiskLib_PrepareForAccess(&cnxParams, “Sample”);

        if (vixError == VIX_OK) {

            break;

        }

        else {

            Sleep(60000);

        }

    }

}

斷開連接後的清理

如果連接斷開後虛擬機的狀態沒有完全清理乾淨,VixDiskLib_Cleanup()就會移除每個虛擬機的額外狀態。它的三個參數分別用來指定連接,返回清理的虛擬機個數,以及未清理的虛擬機個數。

intnumCleanedup, numRemaining;

VixErrorvixError = VixDiskLib_Cleanup(&cnxParams, &numCleanedup,&numRemaining);

將程序升級到高級傳輸

如果要升級應用程序,以支持託管磁盤的高級傳輸方式,請參考以下步驟:

1找到所有VixDiskLib_Connect()的實例,將它們修改爲VixDiskLib_ConnectEx().

vixDiskLib示例程序在使用-mod選項時就會使用VixDiskLib_ConnectEx().

2VixDiskLib_Init()修改爲VixDiskLib_InitEx(),並確保只調用一次。

3使用VixDiskLib_PrepareForAccess()禁用虛擬機的遷移(relocation)

4在中間添加如下參數

    a TRUE用於高性能的只讀訪問,FALSE用於讀寫訪問。

    b 使用快照的moRef

    c NULL使用默認的傳輸方法(推薦)

5使用VixDiskLib_EndAccess()重新啓用虛擬機的遷移。

6在程序結束處找到VixDiskLib_Disconnect(),爲了安全起見,直接在後面加上VixDiskLib_Cleanup()

7使用新的可靠且啓用了傳輸模式的VixDiskLib重新編譯程序。

在備份或還原由VMware vSphere管理的虛擬磁盤時,高級傳輸模式非常有用。備份基於快照機制,它提供了在某個時間點的數據視圖(View),允許訪問靜態的父磁盤上數據,而子磁盤保持修改。

vSphere備份算法

經典的備份程序可參考下面的算法:

  • 最好通過vCenter服務器連接ESX/ESXi主機並查找目標虛擬機。

  • 請求ESX/ESXi主機對目標虛擬機創建快照。

  • 使用vSphere接口(PropertyCollector)抓取狀態信息(VirutalMachineConfigInfo)以及修改的塊信息(queryChangedDiskAreas)

  • 使用高級傳輸函數和VixDiskLib,訪問快照並保存數據。如果啓用了塊修改跟蹤(Changed BlockTracing),快照僅包含增量備份數據。

  • 請求ESX/ESXi主機刪除備份快照。

災難恢復或基於文件的還原算法如下:

最好通過VMware vCenter連接包含目標虛擬機的ESX/ESXi主機。

請求ESX/ESXi主機停止並關閉目標虛擬機。

使用高級傳輸函數,從備份數據中恢復快照。

對於恢復到某個時間點的災難恢復,需要將虛擬機恢復到還原的快照。對於基於文件的還原,掛載快照並還原相關的文件。

第七章設計vSphere備份解決方案將會講述更詳細的算法,包括示例代碼。

備份還原的例子

VMwarevSphere接口queryChangedDiskArea會返回一個快照和由更改ID標識的早期時間點之間發生修改的磁盤扇區。

queryChangedDiskAreas方法使用4個參數,包括一個快照引用和一個修改ID。它返回一個磁盤扇區的列表,即修改ID和快照之間的時間裏發生改變的扇區。如果將修改ID設置爲星號(*),該函數會返回所有已分配的磁盤扇區的列表,因此你的備份程序可以跳過稀疏虛擬磁盤的未分配扇區。

假設你在T1時間創建了一個初始備份,之後在T2T3時間點創建了另外的增量備份。(你也可以使用差異備份,它會消耗更多的備份時間和帶寬,但是擁有更少的還原時間。)

T1時間的完全備份

1記錄虛擬機的配置信息,VirtualMachineConfigInfo

2創建虛擬機快照,命名爲snapshot_T1

3獲得快照中每個虛擬磁盤的修改IDchangeId_T1(每個磁盤一個)

4備份queryChangedDiskAreas(…“*”)返回的扇區,避免未分配磁盤扇區。

5刪除快照snapshot_T1,並和大量的備份數據一起保存修改ID changeId_T1

T2時間的增量備份

1創建虛擬機快照,命名爲snapshot_T2

2獲得快照中每個虛擬磁盤的修改IDchangeId_T2(每個磁盤一個)

3備份queryChangedDiskAreas(snapshot_T2,… changedId_T1)返回的磁盤扇區。

4刪除快照snapshot_T2,並和備份數據一起保存changedId_T2

T3時間的增量備份

1創建虛擬機快照,命名爲snapshot_T3。這時你無法再獲得T1T2兩個時間點之間的修改列表。

2獲得快照中每個虛擬磁盤的修改IDchangeId_T3(每個磁盤一個)

3備份queryChangedDiskAreas(snapshot_T3,… changedId_T2)返回的磁盤扇區。如果執行差異備份,則需要調用queryChangedDiskAreas(snapshot_T3,… changedId_T1)

4刪除快照snapshot_T3,並和備份數據一起保存changedId_T3

T4時間的災難恢復

1使用之前保存的VirtualMachineConfigInfo中的配置參數,創建一個沒有按照客戶機操作系統的新虛擬機。你不需要格式化虛擬磁盤,因爲還原的數據包含有格式化的信息。

2T3的備份中還原數據,並記錄還原了哪些扇區。

3T2中還原增量備份的數據,跳過已經還原的扇區。如果是差異備份,跳過拷貝T2的數據。

4T1完全備份中還原數據,並跳過已經還原的扇區。從後往前還原的目的就是獲取最新的數據,而避免不需要的數據拷貝。

5打開恢復過後的虛擬機。

如果程序使用SAN傳輸模式打開遠程磁盤,它們可以寫基準磁盤,但是不能修改快照(重寫日誌,redo log)。只有在本地主機上的本地磁盤才支持打開並修改快照。

多線程的考慮

在多線程程序中,客戶程序應該講磁盤請求串行化。磁盤句柄不會綁定到單個線程,而是可以跨線程使用。你可以在一個線程中打開磁盤,然後在其他線程中使用,已提供串行化的磁盤訪問。相反的,你可以使設計好的打開-關閉線程,正如下面講述的那樣。

多線程和VixDiskLib

VDDK支持到多塊磁盤的併發I/O,但是存在一些限制:

VixDiskLib_InitEx()或者VixDiskLib_Init()只能在每個進程的主線程中調用一次。

VixDiskLib_InitEx()後者VixDiskLib_Init()函數中,不要將日誌回調函數設置爲NULL。這回導致VixDiskLib提供默認的日誌函數,而它們是非線程安全的。如果在多線程環境中使用VDDK,必須提供自己的線程安全的日誌函數。

在調用VixDiskLib_Open()VixDiskLib_Close()時,VDDK會初始化以及反初始化多個庫,在多線程環境中一些庫可能不起作用。例如下面的調用將會失敗:

線程1VixDiskLib_Open() ……VixDiskLib_Close()

線程2……………………………………….VixDiskLib_Open()…… VixDiskLib_Close()

解決方法是使用一個指定的線程進行所有的打開和關閉操作,而使用其他工作者線程進行讀、寫操作。下面顯示了兩個不同磁盤句柄的並行讀寫。針對同一個磁盤句柄的並行讀寫是不支持的。

wKioL1OiVD6jRX5XAAB3suPMuCQ831.jpg

庫調用的能力

本節說明存在的一些限制。

託管磁盤支持

不支持一些操作:

  • 如果使用VixDiskLib_Connect()打開一個託管磁盤的連接,必須提供有效的vSphere訪問認證信息。在ESX/ESXi主機上,VixDiskLib_Open()不能打開一個磁盤鏈當中的單個連接。

  • 如果要使用VixDiskLib_Create()ESX/ESXi主機上創建一個託管磁盤,首先需要創建一個本地類型的磁盤,然後使用VixDiskLib_Clone()將本地類型虛擬磁盤轉換爲託管磁盤。

  • VixDiskLib_Defragment()只能針對本地磁盤進行碎片整理。

  • VixDiskLib_Grow()只能擴展本地虛擬磁盤。

  • VixDiskLib_Unlink()只能刪除本地磁盤。

  • 直到ESXi5.1HotAdd傳輸只能用於vSphere企業版或更高版本。

本地磁盤支持

除了高級傳輸以外,大多數操作都支持,但不包括:

  • VixDiskLib_ConnectEx()擴展連接函數。

  • SANHotAdd高級傳輸。

  • 使用VixDiskLib_PrepareForAccess()VixDiskLib_EndAccess()延遲存儲遷移。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章