Azure Storage 是微軟 Azure 雲提供的雲端儲存解決方案,當前支援的儲存型別有 Blob、Queue、File 和 Table。
筆者在前文中介紹了 File Storage 的基本用法,本文將介紹 Queue Storage 的主要使用方法。
Queue Storage 是什麼?
Azure Queue Storage 是一個儲存大量訊息的儲存服務,這些訊息可以在任何地方通過 HTTP/HTTPS 訪問。每條訊息最大 64K,訊息的資料量幾乎不受限制 (除非超出了您的 Storage Account 的總容量) 。
下面是 Queue Storage 典型的應用場景:
1. 建立未處理任務的佇列,以便非同步的處理這些任務。
2. 把訊息從 web role 傳遞給 worker role 進行處理。
Azure Queue Storage的結構
下圖描述了 Queue Storage 的基本組織結構:
Azure Storage Account:
Storage Account 是用來管理 Azure Storage 的一個名稱空間,主要用來控制儲存資料的訪問許可權和計費。對 Blob、Queue、File 和 Table 這些 Azure 提供的儲存服務的訪問控制都是通過 Storage Account 來進行的,所以要想使用 Queue Storage,需要先建立你的 Storage Account。
Queue:
每個 Queue 都是一組訊息的集合。每一條訊息都必須屬於一個 Queue。Queue 名稱中的字元必須是小寫。
Message:
每條 Message 的最大長度為 64KB,Message 在 Queue 中停留的最長時間為 7 天。
URL format:
Queue 的 URL 地址格式為:
http://<storage account>.queue.core.windows.net/<queuename>
下面是個更真實的例子:
http://nickstorage.queue.core.windows.net/app1tasks
如果您還不熟悉 Azure Storage Account 的使用,以及如何通過 WindowsAzure.Storage 庫訪問 Azure Storage,請參考前文《Azure Table storage 基本用法》中的介紹,這裡就不重複了。
為了方便檢視 C# 程式碼執行的結果,本文使用了 MS 釋出的一個 Azure Storage 客戶端工具:Microsoft Azure Storage Explorer,文中簡稱為 Storage Explorer。下面是 Queue Storage 的一個截圖:
接下來我們通過 C# 程式碼來介紹如何操作 Queue Storage。
建立 Queue
我們先來建立一個名為 "app2tasks" 的 Queue:
// CloudStorageAccount 類表示一個 Azure Storage Account,我們需要先建立它的例項,才能訪問屬於它的資源。 // 注意連線字串中的xxx和yyy,分別對應Access keys中的Storage account name 和 key。 CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=yyy"); // CloudQueueClient 類是 Windows Azure Queue Service 客戶端的邏輯表示,我們需要使用它來配置和執行對 Queue Storage 的操作。 CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient(); // CloudQueue 表示一個 Queue 物件, 絕大多數的操作都是通過這個物件完成的。 CloudQueue queue = queueClient.GetQueueReference("app2tasks"); // 如果不存在就建立名稱為 "app2tasks" 的 Queue。 queue.CreateIfNotExists();
執行上面的程式碼,然後在 Storage Explorer 中檢視結果:
把訊息插入 Queue
現實的應用場景中肯定有一個或多個程式產生 Message 並插入到 Queue 中,接下來我們看看用 C# 如何實現:
string current = DateTime.Now.ToString(); // 把訊息插入到佇列中。 CloudQueueMessage message = new CloudQueueMessage("Hello, World. -- " + current); queue.AddMessage(message)
呼叫幾次上面的程式碼看看結果如何:
我通過三次呼叫向 Queue 中加入了三條訊息,請注意插入它們的時間,分別是 11:33:45,11:33:57,和 11.34:16。在接下來的描述中我分別稱它們為第一條訊息、第二條訊息和第三條訊息。
檢視 Queue 中的訊息
既然是佇列,肯定有隊頭和隊尾,訊息從隊頭出隊從隊尾入隊。那麼能不能檢視一下隊頭的訊息 (也就是下一條要處理的訊息,此處只是檢視並不是要處理) 呢?當然可以:
// 總是取到隊頭的訊息,沒有訊息出隊。 // 訊息在佇列中的位置、可見狀態也沒有發生變化。 CloudQueueMessage peekedMessage = queue.PeekMessage();
PeekMessage 方法總是取到處於隊頭位置的那條訊息,並且不改變佇列的狀態!
為了幫助小夥伴們更深刻地理解 PeekMessage 方法的內涵,筆者從網上找了一張解釋 peek 一詞的圖片,請注意圖片中的黃色線條:
(本圖片來自於網際網路,如有版權問題請與筆者聯絡。)
檢視 Queue 的長度
經常的檢視 Queue 的長度是個不錯的注意,因為你需要避免一些由於 Queue 過長帶來的問題:
// 獲取 Queue 的屬性。 queue.FetchAttributes(); int? cachedMessageCount = queue.ApproximateMessageCount;
更新 Queue 中的訊息
如果一條訊息已經被新增到 Queue 中了,但是又需要更新其內容該怎麼辦?我們可以找到這條訊息然後更新它的內容:
CloudQueueMessage message = queue.GetMessage(); // 執行 getmessage(), 隊頭的訊息會變得不可見。 message.SetMessageContent("Updated contents."); queue.UpdateMessage(message, TimeSpan.FromSeconds(60.0), MessageUpdateFields.Content | MessageUpdateFields.Visibility); // 更新完訊息內容的60s 之後,該訊息會重新可見,但是是在隊尾。
執行上面的程式碼後,我們發現在 Storage Explorer 中"第一條訊息"不見了。過了 60 秒之後它又重新出現在 Storage Explorer 中,但是它的內容已經變化,位置也成了隊尾:
此時我們也只能通過 ID 認出它是之前的"第一條訊息",之前"第二條訊息","第三條訊息"的位置也發生了相應的變化。
處理 Queue 中的訊息
如何處理 Queue 中的訊息呢?我們的程式大體應該遵循下面的邏輯:
使用 GetMessage 方法取出隊頭的訊息,此時該訊息會在 Queue 中 30 秒不可見(這個時常使用者可以設定,預設是 30 秒);
處理訊息;
正常處理完成後,呼叫 Delete 方法刪除訊息;
如果沒有正常處理訊息 (沒有呼叫 Delete 方法),此訊息會在 30 秒後重新出現在隊尾。
類似於下面的程式碼邏輯:
// 執行 getmessage(), 隊頭的訊息會變得不可見。 CloudQueueMessage message = queue.GetMessage(); try { //處理訊息 // 如果在30s內你沒有刪除這條訊息,它會重新出現在隊尾。 // 所以正確處理一條訊息的過程是,處理完成後,刪除這條訊息 queue.DeleteMessage(message); } catch //(訊息處理異常) { }
刪除 Queue 中的訊息
除了正常處理完訊息後把訊息從佇列中刪除,我們也可以找到一條訊息,直接刪除它。本質上和處理完再刪除是一樣的。
總結
Queue Storage 為應用之間的解耦提供了很好的解決方式。使得訊息的產生者和訊息的處理者可以互相不知道彼此的存在。為我們處理這類問題新增了一件有力的武器。