Azure 基礎:Table storage


Azure Storage 是微軟 Azure 雲提供的雲端存儲解決方案,當前支持的存儲類型有 Blob、Queue、File 和 Table。其中的 Table 就是本文的主角 Azure Table storage。

Azure Table storage 是一個在雲端存儲結構化 NoSQL 數據的服務。它不僅存取速度快,而且效費比高。MSDN 上的說法是:成本顯著低於傳統 SQL!
筆者最近在項目中用 Table storage 實現了一個日志表,在此和大家分享一下 Table storage 的基本用法。

Azure storage account

就概念上來講,Table storage 只是 Azure 提供的存儲服務的一種。其他的存儲服務還有 Blob、Queue、File 等。對這些存儲服務的訪問控制都是通過 storage account 來進行的。所以要想使用 Table storage 需要先創建你的 storage account。具體創建過程不是本文重點,請參考 MSDN。但你需要去了解一下 Access keys,它就是你訪問 storage account 的用戶名和密碼:

創建 Table storage 的對象

在使用 Azure Table storage 的相關對象前,我們需要安裝對應的包。其實很簡單,只需在 Visual Studio 的 Package Manager Console 中輸入:

Install-Package WindowsAzure.Storage

Visual Studio 會自動安裝 WindowsAzure.Storage 包及其依賴的所有包,安裝完成后的 packages.config 文件看起來像這個樣子:

安裝完相關的包以后,我們就可以使用其中的類型了。

CloudStorageAccount 類表示一個 Azure storage account,我們得先創建它的實例才能訪問屬於它的資源。

// 注意連接字符串中的 xxx 和 yyy,分別對應 Access keys 中的 Storage account name 和 key。
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=yyy");

// CloudTableClient 類是 Windows Azure Table Service 客戶端的邏輯表示。我們使用它來配置和執行對 Table storage 的操作。
CloudTableClient cloudTableClient = storageAccount.CreateCloudTableClient();

CloudTable 類表示一張數據表。

// 創建一個實例去引用 Table storage 中的一張表,我們測試用的表名叫 "MyLogTable"。
CloudTable logTable = cloudTableClient.GetTableReference("MyLogTable");
// 如果不確定表是否被創建過,可以調用 CreateIfNotExists 方法。
logTable.CreateIfNotExists();

這樣在后面的操作中就可以確保 MyLogTable 表是存在的。

有了 logTable 對象我們就可以向表中插入數據了。但是等等,好像少了點什么。我們開篇第一句中就說明了,Table storage 存儲的是結構化的數據,所以我們還要先定義存儲的數據的類型。

定義日志類

在定義我們自己的數據類型時,有一個強制性的要求,必須繼承自 TableEntity 類型:

internal class MyLogEntity : TableEntity
{
    public MyLogEntity() { }
    public MyLogEntity(string pkey, string rkey)
    {
        this.PartitionKey = pkey;
        this.RowKey = rkey;
    }

    public DateTime LogDate { get; set; }
    public string LogMessage { get; set; }
    public string ErrorType { get; set; }
}

在我們的設計中,PartitionKey 用來存放產生日志的年份和月份(例如201607),RowKey 用來存放產生日志的天和時分秒毫秒(例如160934248492)。日志數據主要是 LogDate,LogMessage 和 ErrorType。

把數據插入到 Table storage

終於可以向表中插入數據了,試一下先:

DateTime now = DateTime.Now;
string partitionKey = now.ToString("yyyyMM");
string rowKey = now.ToString("ddHHmmssffff");
MyLogEntity logEntity = new MyLogEntity(partitionKey, rowKey);
logEntity.LogDate = now;
logEntity.LogMessage = "test message";
logEntity.ErrorType = "error";
// TableOperation 類表示對一個表進行的操作,可以插入一行或多行數據,刪除數據,更新數據等。
TableOperation insertOperation = TableOperation.Insert(logEntity);
logTable.Execute(insertOperation);

看起來還不錯,我們用 Visual Studio 自帶的 Cloud Explorer 查看一下 MyLogTable 中的內容:

OK,數據已經成功插入到 MyLogTable 表中。接下來我們看看如何批量的插入數據。

TableBatchOperation batchOperation = new TableBatchOperation();
for (int i = 0; i < 10; i++)
{
    DateTime now = DateTime.Now;
    string partitionKey = now.ToString("yyyyMM");
    string rowKey = now.ToString("ddHHmmssffff");
    MyLogEntity logEntity = new MyLogEntity(partitionKey, rowKey);
    logEntity.LogDate = now;
    logEntity.LogMessage = "test message" + i.ToString();
    logEntity.ErrorType = (i%2) == 0 ? "error" : "warning";
    batchOperation.Insert(logEntity);
    Thread.Sleep(10);
}
logTable.ExecuteBatch(batchOperation);

這次我們把 TableOperation 類換成了 TableBatchOperation 類,然后一次插入十條數據。去檢查一下結果,OK 十條數據全部插入成功!
下面讓我們把循環中的 10 改成 200 試試:

怎么收到一個 InvalidOperationException 呢?看看紅框中的內容,原來批量操作是有一些限制的:
1.    每個批量操作的數據上限是 100 條記錄。
2.    每個批量操作中的數據都必須保持相同的 partition key。
請大家在使用批量操作時務必注意這些限制條件!

查詢操作

對於日志數據的操作,最重要的就是查詢。我們通過幾個具體的用例來介紹 Table storage 的查詢操作。

查詢所有的記錄

這是最簡單的查詢方法,一般是想要導出全部數據時才會這么干:

TableQuery<MyLogEntity> query = new TableQuery<MyLogEntity>();
foreach (MyLogEntity entity in logTable.ExecuteQuery(query))
{
    Console.WriteLine("{0}\t{1}\t{2}\t{3}", entity.PartitionKey, entity.RowKey, entity.LogMessage, entity.ErrorType);
}

查詢某年的某個月的記錄

要查詢某個月的所有記錄也是比較容易的,因為我們設計的 PartitionKey 就代表了某個月份:

TableQuery<MyLogEntity> query = new TableQuery<MyLogEntity>().Where(
    TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "201607"));
foreach (MyLogEntity entity in logTable.ExecuteQuery(query))
{
    //...
}

請注意 TableQuery.GenerateFilterCondition 方法,我們創建了一個過濾條件:PartitionKey 等於 "201607"。這個查詢會把所有 PartitionKey 為 "201607" 的記錄都找到!

查詢某一條記錄

如果我們已經知道了一條記錄的 PartitionKey 和 RowKey,就可以通過這兩個條件直接查詢到這條記錄的詳情:

TableQuery<MyLogEntity> query = new TableQuery<MyLogEntity>().Where(
    TableQuery.CombineFilters(
        TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "201607"),
        TableOperators.And,
        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, "161148372454")));
foreach (MyLogEntity entity in logTable.ExecuteQuery(query))
{
    //...
}

這次我們使用了組合條件。雖然這里只使用了條件運算操作 TableOperators.And 和 QueryComparisons.Equal,你完全可以嘗試其它的條件類型。唯一要注意的是:對於 PartitionKey 和 RowKey,QueryComparisons 的操作對象都是字符串。

我們還需要更多的查詢條件,比如查詢某一天產生的所有日志。在 MyLogTable 表中,這需要查詢以 "xx" 字符串開頭的 RowKey。我會單獨在一篇文章中和大家分享相關內容,因為它並不像看起來的那么簡單。
接下來我們介紹如何更新和刪除日志表中的數據,當然這么做並不恰當,我們這里只是借用日志表介紹更新和刪除操作而已。

更新記錄

TableOperation retrieveOperation = TableOperation.Retrieve<MyLogEntity>("201607", "161148372454");
TableResult retrievedResult = logTable.Execute(retrieveOperation);
MyLogEntity updateEntity = (MyLogEntity)retrievedResult.Result;

if (updateEntity != null)
{
    updateEntity.LogMessage = "new log message";
    TableOperation updateOperation = TableOperation.Replace(updateEntity);
    logTable.Execute(updateOperation);
}

這次我們先用 TableOperation.Retrieve 方法獲得一條數據的詳情,然后更新它的 LogMessage 屬性,最后使用 TableOperation.Replace 方法把新的內容更新的到 Table storage 中。

刪除記錄

實際上刪除一條記錄和更新一條記錄一樣麻煩,不同點是把 TableOperation.Replace 方法換成 TableOperation.Delete 方法:

TableOperation retrieveOperation = TableOperation.Retrieve<MyLogEntity>("201607", "161148372454");
TableResult retrievedResult = logTable.Execute(retrieveOperation);
MyLogEntity deleteEntity = (MyLogEntity)retrievedResult.Result;
if (deleteEntity != null)
{
    TableOperation deleteOperation = TableOperation.Delete(deleteEntity);
    logTable.Execute(deleteOperation);
}

刪除表

刪除表和創建表一樣簡單(可比刪除一條記錄容易多了):

logTable.DeleteIfExists();

總結

本文通過對一個日志表的操作介紹了 Azure Table storage 的一個典型應用場景和基本的使用方法。從操作的代碼上看和傳統的 sql 表操作差別還是挺大的。希望對朋友們了解 Azure Table storage 能有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM