[Windows Azure][IT鐵人賽系列] Day 14 - Storage Service (1): BLOB Storage

BLOB Storage顧名思義,是專門用來儲存二進位檔案使用的儲存服務,基本上檔案的格式沒有任何的限制,只要是可以轉換成二進位資料(binary data)的檔案都可以儲存,也就是我們常說的非結構化(unstructured)資料,舉凡一般的文字檔案到大型的影音檔案都可以使用。

BLOB Storage的概念和檔案系統非常類似,每個儲存帳戶都有獨立的URL命名空間,而命名空間下則是容器(container),資料則存放在容器內,容器的概念就像是資料夾一樣,所以一個儲存在BLOB中的檔案的URL會是:

http://[storagename].blob.core.windows.net/[container name]/[blob name]

image

在BLOB Storage中支援兩種不同類型的資料,一種是劃分為資料塊(data block)的BLOB格式,檔案由固定大小的資料塊組成,用戶端在操作此類型的BLOB時,可將資料劃分成數個資料塊後分批上傳,最後再使用API將這些資料塊組織成一個完整的檔案,Storage在處理資料塊時會使用兩階段認可程序(Two-phrase Commit),每個資料塊在上傳時都要經過服務認可才算成功,也就是說如果有資料塊傳輸失敗時,服務會要求用戶端重傳,直到全部傳輸完成後,再將所有的資料塊認可成一個完整的檔案。一個使用資料塊保存的BLOB檔案最多可擁有50,000個區塊,而一個區塊最大的長度為4MB,所以等於最大可以存放200GB的資料量。另一個BLOB格式則是分頁型(page)的BLOB,這個格式很類似於電腦中的記憶體,它是由連續位址組合而成的,用戶端可以自由的決定要寫入哪一段位址,服務也不會特別去檢查是否完成就會直接認可,在速度上分頁型的BLOB會比資料塊型的BLOB要來的快,可用大小也比資料塊的大,最高可用到1TB的資料量,適合需要連續寫入資料的需求,而Windows Azure Drive也是使用這個類型的BLOB來實作的。

不論是Block或是Page BLOB,對外都是以REST API來開放功能,對於.NET開發人員來說更幸褔了,因為Windows Azure SDK內建了StorageClient組件,封裝了REST API,開發人員只要使用物件即可操作BLOB的資料。若要開發使用BLOB Storage的應用程式,請在專案中加入Microsoft.WindowsAzure.StorageClient.dll的參考,然後在程式中引用Microsoft.WindowsAzure.StorageClient命名空間。

BLOB服務的入口由CloudBlobClient類別提供,透過CloudStorageAccount.CreateCloudBlobClient()擴充方法可取得它,然後使用GetContainerReference() 取得CloudBlobContainer物件,這個物件代表BLOB的容器,裡面即有列舉內部的檔案的方法可使用,可參照下列程式碼:

private void InitializeBlobStorage()

{

   CloudStorageAccount storageAccount =

      CloudStorageAccount.FromConfigurationSetting("FileDataSource");

   this._blobClient = storageAccount.CreateCloudBlobClient();

}

private void LoadBlobContainers()

{

   this.tvContainerView.Nodes.Clear();

   CloudBlobContainer rootContainer = this._blobClient.GetContainerReference("/");

   TreeNode node = new TreeNode("根目錄");

   node.Value = rootContainer.Uri.ToString();

   IEnumerable<CloudBlobContainer> containers = this._blobClient.ListContainers();

   foreach (CloudBlobContainer container in containers)

   {

      TreeNode containerNode = new TreeNode(container.Name);

      containerNode.Value = container.Uri.ToString();

      node.ChildNodes.Add(containerNode);

   }

   this.tvContainerView.Nodes.Add(node);

   this.cmdAddContainer.Enabled = (string.IsNullOrEmpty(this.tvContainerView.SelectedValue));

   this.cmdUpload.Enabled = (!string.IsNullOrEmpty(this.tvContainerView.SelectedValue));

}

private void LoadBlobs()

{

   if (string.IsNullOrEmpty(this.tvContainerView.SelectedValue))

      return;

   CloudBlobContainer container =

      this._blobClient.GetContainerReference(this.tvContainerView.SelectedValue);

   IEnumerable<IListBlobItem> blobs = container.ListBlobs(

      new BlobRequestOptions() { UseFlatBlobListing = true });

   this.gvBlobList.DataSource = blobs;

   this.gvBlobList.DataBind();

}

而若要處理BLOB檔案,則可以使用CloudBlockBlob物件,透過GetBlockBlobReference()可取得它的參考,再利用它的UploadByteArray()或UploadFile()或UploadStream()等方法上傳資料,如下列程式碼:

protected void cmdUpload_Click(object sender, EventArgs e)

{

   string blobName = null;

   if (string.IsNullOrEmpty(this.txtBlobName.Text))

      blobName = this.fuFile.FileName;

   else

      blobName = this.txtBlobName.Text;

   CloudBlobContainer container =

      this._blobClient.GetContainerReference(this.tvContainerView.SelectedValue);

   CloudBlockBlob blob = container.GetBlockBlobReference(blobName);

   blob.UploadByteArray(this.fuFile.FileBytes);

   blob = null;

   this.LoadBlobs();

}

BLOB服務除了可以儲存檔案外,它也可以將檔案分享給應用程式以外的用戶端,每個BLOB檔案都有一個URL,只要擁有這個URL就可以取得檔案,但如果檔案需要做存取控制的話,則可以透過Shared Access Signature來限制,利用Container本身的開放限制以及檔案本身的授權戳記限制,可以達到控制檔案存取範圍的需求。Shared Access Signature本身很複雜難懂,但.NET開發人員只要利用StorageClient組件中的功能,即可很輕鬆的取得帶有Shared Access Signature的URL,例如下列程式碼:

CloudBlobContainer container = this._blobClient.GetContainerReference(this.txtContainerName.Text);

container.CreateIfNotExist();

BlobContainerPermissions blobPermission = new BlobContainerPermissions();

blobPermission.PublicAccess = BlobContainerPublicAccessType.Container;

blobPermission.SharedAccessPolicies.Add("TimePolicy", new SharedAccessPolicy()

{

   Permissions = SharedAccessPermissions.List | SharedAccessPermissions.Read,

   SharedAccessStartTime = DateTime.Now,

   SharedAccessExpiryTime = DateTime.Now.AddDays(10)

});

container.SetPermissions(blobPermission);

container = null;

當然,BLOB如果只能記錄檔案,那麼似乎也太少了,如果想要增加一些描述性的資料的話,若還要依賴Table Storage,那兩邊的同步性似乎問題就不小,但還好的是,BLOB storage允許每個檔案擁有自己的描述性資料,稱為Metadata,只要在加入或更新BLOB資料時,都可以寫入Metadata 資料,讓檔案的描述資訊更加完整。Metadata是由鍵值對 (name-value pair)來組成,BLOB Storage要求Metadata的鍵值名稱必須要是符合C# identifier規範,否則會在serialize階段擲出例外而失敗。

由於篇幅限制,BLOB功能無法非常完整的交代,有興趣的讀者可參考MSDN邊做邊學的Windows Azure Platform系列文章,市面上也有兩本中文書可以參考,也可以上網下載Windows Azure Training Kit,裡面有很多範例程式與Hands-on Labs可以體驗。

最後要說明的是,BLOB使用上會有些許限制:

  • BLOB組成的字串中不可以有URL路徑不允許的字元出現,否則系統會回傳HTTP 400(Bad Request)的錯誤。
  • 容器的名稱可以是英文半型與數字,以及『-』字元組成的名稱,但『-』字元不可以出現在第一個或最後一個字元,同時長度必須在3至63個字元之間,而且全部都要是小寫(不可以出現大寫字元)。
  • 由於BLOB儲存服務以及容器等,都是Flat階層(即沒有明確的階層化),所以可以用『/』來當BLOB資料的名稱的一部份,以模擬出有資料夾的URL(例如可以用『a/mydata/mydata.txt』作為BLOB資料的名稱),同時也最好不要使用『.』來結尾,這有可能會讓一些URL解析器失效(例如.NET的Uri物件)。

 

Reference:

http://msdn.microsoft.com/en-us/windowsazure/wazplatformtrainingcourse_exploringwindowsazurestoragevs2010_topic4#_Toc303848591