GitHub/Windows Azure Storage Libraries for .NET 3.0.0

3.0.0では、GitHub上の Windows Azure Storage の .NET Client ライブラリの場所が変わりました。

leaf by Takekazu Omi, on Flickr

Storage の .NET Client ライブラリは、2.1までは、Windows Azure SDK for .NET github:azure-sdk-for-netにありましたが、3.0からは、Storageは独立してWindows Azure Storage Libraries for .NET github:azure-storage-netになりました。2.1系は継続して、Windows Azure SDK for .NET github:azure-sdk-for-netでメンテされるようです。現在2.1系の最新は、2.1.0.4です。

今後Windows Azure SDK for .NETは、Windows Azure Configuration ManagerWindows Azure Management Librariesの場所ということになりそうです。

最初は、Windows Azure SDK for .NET という名前で、中身がStorageのライブラリで始まって、そのうち Configuration Manager が追加、Management Libraries が追加され、Media関連はディレクトリはあるけど別レポジトリ、とだんだん膨れてわかり辛くなってきたところだったので整理するにはいいタイミングだった気がします。

Breaking Changes

Windows Azure Storage 2013-08-15 の Minute Metricsで、3.0の変更点が分からないと書きましたが、レポジトリのBreakingChanges.txtに記載がありました。

3つあります。簡単にまとめます。

  1. テーブルの操作にDataServiceContextを使った場合、OperationContextのresponse received eventは no longer fired(もはや起こらない)
  2. ContinuationToken の WriteXml()/ReadXml()が変更されました。詳細は原文を参照してください。
  3. ServiceProperties では、uploadされたものだけが変更されます。例えば、CORSの設定だけをすると、Logging と Metering 関連の設定は変更されません。

ServicePropertiesのプロパティが変更された件などは、上記 Breaking Changes に書いてありませんので互換性に関しては注意が必要だと思います。

まとめ

このレポジトリの移動に関してWindows Azure Storage Release - CORS、JSON、Minute Metrics の紹介に下記のような記述があります。

これらの機能に対応した、Windows Azure Storage Client Library を github:azure-storage-net にリリースします。

今までのレポジトリを見てソースが上がってこないので、3.0のソースは公開されないのかと思って困惑していましたが、無事ソースも確認できて安心しました。

Windows Azure Storage 2013-08-15 の Minute Metrics

Windows Azure Advent Calendar 2013 - Qiita [キータ]の 5 日目の記事です。最初Javaネタを書こうと思ってたのですが、11/27にWindows Azure Storageの新しいバージョン(x-ms-version:2013-08-15)が公開され盛り上がっているのでストレージネタに切り替えました。

新バージョンに付いては以前に書いているので、それを見て下さい。

Windows Azure Storage Team Blog で、新しいWindows Azure Storageのリリースが紹介されています。Windows Azure Storage Release - Introducing CORS, JSON, Minute Metrics, and More

立派な訳が出てるので、こちらも合わせてどうぞ。

久しぶりのストレージ のリリースで機能盛り沢山なのですが[1]、その中でもパフォーマンスジャンキー注目の Minute Metrics (分単位メトリックス)を紹介します。機能紹介だけだと面白くないので脱線しながら書きますのでお楽しみ下さい。

DEAD END by takekazu, on Flickr

Minute Metrics (分単位メトリックス)とは

今まで、Windows Azure StorageのMetricsは時間集計でした。Storage Analytics Metrics の詳細新しい 2013-08-15 version のMinute Metrics では、5分以内に 分単位の集計(Minute Metrics) が参照できるようになりました。それに伴って下記のテーブルが追加されています。

  • $MetricsHourPrimaryTransactionsBlob
  • $MetricsHourPrimaryTransactionsTable
  • $MetricsHourPrimaryTransactionsQueue
  • $MetricsMinutePrimaryTransactionsBlob
  • $MetricsMinutePrimaryTransactionsTable
  • $MetricsMinutePrimaryTransactionsQueue

Hourと付いているのは、以前の $MetricsTransactionsBlob、$MetricsTransactionsTable、$MetricsTransactionsQueue の名前が変わったものです。古い名前のものもありますが、Minute Metrics の導入に伴って命名規則が整理されたようです。今のところ Windows Azure Portal では分単位の設定はできませんが、将来サポートされるそうです。

名前を見ていて面白いのは、Primary という文字列が入っていることです。もしかしたら、GEO replication 先のメトリックスも見れるようになるんじゃないかと思って、「$MetricsMinuteSecondaryTransactionsTable」って名前でテーブルを参照してみました。

エラーには成らなかったのですが、下記のようなレスポンスでTableは空のようです。[2]

HTTP/1.1 200 OK
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 9e39e71e-70ea-41b3-be3e-b7a6231315b0
x-ms-version: 2013-08-15
X-Content-Type-Options: nosniff
Date: Thu, 05 Dec 2013 12:00:39 GMT

83
{"odata.metadata":"http://waac2013omi001diag.table.core.windows.net/$metadata#$MetricsMinuteSecondaryTransactionsTable","value":[]}
0

ちなみに、$で始まる適当な名前でリクエストを流すと400 Bad Requestで、リソースに不正な文字が含まれているというエラーになります。

HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 272dce2f-ac46-46b7-b59d-b0338cefa78b
x-ms-version: 2013-08-15
X-Content-Type-Options: nosniff
Date: Thu, 05 Dec 2013 11:57:59 GMT

DE
{"odata.error":{"code":"InvalidResourceName","message":{"lang":"en-US","value":"The specifed resource name contains invalid characters.\nRequestId:272dce2f-ac46-46b7-b59d-b0338cefa78b\nTime:2013-12-05T11:58:00.5348125Z"}}}
0

メトリックス系のテーブルは下記のようにListTableでも帰ってこないので存在するかどうかは難しいところですが、エラーにならないところを見ると特別扱いされているようで期待してしまいます。

var tables = tableClient.ListTables("$Metrics");

Minute Metrics (分単位メトリックス)を有効にする

Minute Metricsを有効にするには、xms-version:2013-08-15 を指定して、Set Service Properties REST APIを使います。今回は、Widnows Azure Storage Client 3.0.0を使います。今のところWidnows Azure Storage Client 3.0.0のドキュメントがほぼ存在しないのですが、nugetで入れるとデフォルトでは入ります。設定は、ServiceProperties に、Version、MetricsLevel、RetentionDays(保存期間)を入れて、CreateCloud(Blob|Table|Queue)ClientのSetServicePropertiesを呼ぶだけです、簡単ですね。下記のコードだと、Loggingと時間集計メトリックスの設定も同時にやっています。Minute MetricsのRetentionの期間は従来と同じで日付なのでデータ量には要注意です。従来の時間単位集計に比べて60倍のデータが蓄積されます。[3]

private static void SetStorageAnalytics(CloudStorageAccount account)
{
    var serviceProperty = new ServiceProperties
    {
        Logging = new LoggingProperties
        {
            Version = "1.0",
            LoggingOperations = LoggingOperations.All,
            RetentionDays = 7,

        },
        HourMetrics = new MetricsProperties
        {
            Version = "1.0",
            MetricsLevel = MetricsLevel.ServiceAndApi,
            RetentionDays = 7
        },
        MinuteMetrics = new MetricsProperties
        {
            Version = "1.0",
            MetricsLevel = MetricsLevel.ServiceAndApi,
            RetentionDays = 1
        }
    };
    account.CreateCloudBlobClient().SetServiceProperties(serviceProperty);
    account.CreateCloudTableClient().SetServiceProperties(serviceProperty);
    account.CreateCloudQueueClient().SetServiceProperties(serviceProperty);

}

このコード書いていてServicePropertiesのプロパティで「あれ?」と思いました。以前は、ServicePropertiesは、LoggingProperties と MetricsProperties の2つのプロパティを持っていたのですが、3.0では MetricsProperties が無くなって HourMetrics になってしまっているようです、Table側は古い名前も残してあるのに、ライブラリは Braking Changesにしてしまったようですね。このあたりの判断は難しいところなのでしょうが、古い名前もあっても良い気がします。

2.1.0.4 ServiceProperties.cs

nugetから無条件で最新版として入るのに前のバージョンと互換性が無いっていうのは大胆な気がしますが、なんらかの事情でちょっとドキュメントが遅れているだけなのでしょう。

実行してリクエスト、レスポンスを覗いてみます。

http request

PUT http://waac2013omi001diag.blob.core.windows.net/?comp=properties&restype=service&timeout=90 HTTP/1.1
User-Agent: WA-Storage/3.0.0 (.NET CLR 4.0.30319.34003; Win32NT 6.3.9600.0)
x-ms-version: 2013-08-15
x-ms-client-request-id: 56bffee5-4626-4835-b254-af38a1520242
x-ms-date: Thu, 05 Dec 2013 12:39:54 GMT
Authorization: SharedKey ********************************************************
Host: waac2013omi001diag.blob.core.windows.net
Content-Length: 626
Connection: Keep-Alive

<?xml version="1.0" encoding="utf-8"?><StorageServiceProperties><Logging><Version>1.0</Version><Delete>true</Delete><Read>true</Read><Write>true</Write><RetentionPolicy><Enabled>true</Enabled><Days>7</Days></RetentionPolicy></Logging><HourMetrics><Version>1.0</Version><Enabled>true</Enabled><RetentionPolicy><Enabled>true</Enabled><Days>7</Days></RetentionPolicy><IncludeAPIs>true</IncludeAPIs></HourMetrics><MinuteMetrics><Version>1.0</Version><Enabled>true</Enabled><RetentionPolicy><Enabled>true</Enabled><Days>1</Days></RetentionPolicy><IncludeAPIs>true</IncludeAPIs></MinuteMetrics><Cors /></StorageServiceProperties>

http response

HTTP/1.1 202 Accepted
Transfer-Encoding: chunked
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 650e2253-9e51-43e5-90bd-6077ef43ef31
x-ms-version: 2013-08-15
Date: Thu, 05 Dec 2013 12:39:47 GMT

0

リクエストで、ServicePropertiesに設定した内容を投げていますがXMLなんですね。ここはJSONじゃないのかと思ったけど、そんなにトラフィックが多いところじゃないので問題ないですね。シンプルでいい感じです。

Minute Metrics (分単位メトリックス)の結果

細かい確認ができていないのですが、結果自体はテーブル名が違うだけで従来の時間集計と同じものが出てるようです。パーテションキーが単位で採番されています。

Minute Metricsの例
PartitionKey RowKey TotalIngress TotalEgress AverageE2ELatency AverageServerLatency
20131205T0303 user;All 393 59079 352 53
20131205T0303 user;QueryEntities 393 59079 352 53
20131205T0304 system;All 8057 9452 20 19
20131205T0304 user;All 2188 15747 46.833333 5.166667
20131205T0304 user;QueryEntities 1478 14291 68.5 6.25
20131205T0304 user;QueryTables 710 1456 3.5 3
20131205T0305 system;All 24161 28398 14.333333 13.333333
20131205T0305 user;All 2041 13787 268.5 5.75
20131205T0305 user;GetTableServiceProperties 338 584 2 2
20131205T0305 user;QueryEntities 1703 13203 357.333333 7
20131205T0306 system;All 32239 37972 17.25 16
20131205T0307 system;All 23475 27904 15 14.5

表だと厳しいのでcsvをどうぞ (zip)

まとめ

Minute Metrics は出てくるまで少々遅延(5分ぐらい?)があるようですが、分単位のメトリックスが見れるのは助かります。簡単な負荷テストの結果を確認するのにも使えます。今回はStorage Clinet 3.0を使いましたが、現時点ではGitHubにコードが出ていない、変更点のドキュメントが無いなど少々使いづらいところがあります。もし新機能にこだわりが無いなら、あの嫌らしいCastのBUGも治ってますし2.1.0.4 を使うのが良いと思います。今回のように、Minute Metricsの設定がしたいというなら、Storage Clinet 3.0 が必要です。あと、ServicePropertiesに、CorsPropertiesが追加されているので、CROS が使いたい場合も3.0が便利だと思います。

訂正 2013/12/06

訂正です。Storage Clinet 3.0は、現時点ではGitHubにコードが出ていないと書きましたが、正式名称 Windows Azure Storage Libraries for .NET のソースはgithub:azure-storage-netで公開されています。



[1]日本リージョン、IaaSのGAなど大きな話題が続いている Azure 全体に比べると地味ですね。
[2]レスポンスのbodyがJSONですね、このバージョンからJSONがサポートされています。
[3]当たり前ですね

Windows Azure SDK for Ruby Release 0.6.0

Windows Azure SDK for Ruby 0.6.0 がリリースされました。2013/04/25に 0.5.0 が出て以来7ヶ月ぶりのリリースです。RubyGemsから入ります

INISTALL > gem install azure

新機能

0.6.0では、主にmanagement APIの追加とBUG修正が行われたようです。

  • service management API のライブラリとして下記のものが追加されています。
    • Virtual Machine
    • Virtual Machine Image
    • Virtual Network
    • Cloud Service
    • Storage
    • Sql Database
    • Location and Affinity Group

get_blob_properties のBUG修正

5月にPRを出した修正も取り込まれてリリースされました。これで、Blobのプロパティを取ったらBodyが付いてくるという大きな問題は解決されたことになります。

これで出すに出せなかったやつが出せるようになります。

Storage Client 2.1.0.4 以降での Cast問題の修正

Storage Client 2.0.3以前と、最新のWindows Azure Storage の組み合わせで発生していたTable Query での Cast 問題が最新(2.1.0.4, 3.0.0 2013/11/29 現在)では解決されているようです。正式なアナウンスはまだ有りませんが、必要な方は以下の検証結果を参考にしてください。

red takekazu, on Flickr

issueの再現

まずは、問題が報告されているStorage Clinet 2.1.0.3で再現することを確認します。再現コードはTable Query での Cast 問題で提示されているものを使います。

static IEnumerable<T> GetEntities<T>(CloudTable table)  where T : ITableEntity, new()
{
    IQueryable<T> query = table.CreateQuery<T>().Where(x => x.PartitionKey == "1");
    return query.ToList();
}

nugetで、問題のあるバージョンのライブラリをインストールします:

Install-Package WindowsAzure.Storage -Version 2.1.0.3

実行結果

Table Query での Cast 問題で報告されている通り、http requestのtraceのGET URLに$filter=castの文字列が入ってしまっており、http responseのtraceでは、400 Bad Requestになっているのが確認できました。x-ms-versionは、 2012-02-12 です。

http requestのtrace:

GET http://asdpojasldfj001.table.core.windows.net/people?$filter=cast%28%27%27%29%2FPartitionKey%20eq%20%271%27&timeout=90 HTTP/1.1
User-Agent: WA-Storage/2.1.0.3 (.NET CLR 4.0.30319.34003; Win32NT 6.3.9600.0)
x-ms-version: 2012-02-12
Accept: application/atom+xml,application/xml
Accept-Charset: UTF-8
MaxDataServiceVersion: 2.0;NetFx
x-ms-client-request-id: af7cf5c3-c287-4c1f-a9fe-ee0b6c374317
x-ms-date: Fri, 29 Nov 2013 23:25:01 GMT
Authorization: SharedKey asdpojasldfj001:*********************************************
Host: asdpojasldfj001.table.core.windows.net

http responseのtrace:

HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Content-Type: application/xml;charset=utf-8
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: abf14b12-7a80-4b75-a652-604c56bdb817
x-ms-version: 2012-02-12
X-Content-Type-Options: nosniff
Date: Fri, 29 Nov 2013 23:25:01 GMT

131
<?xml version="1.0" encoding="utf-8"?><error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><code>InvalidInput</code><message xml:lang="en-US">One of the request inputs is not valid.
RequestId:abf14b12-7a80-4b75-a652-604c56bdb817
Time:2013-11-29T23:25:02.0389849Z</message></error>
0

2.1.0.4 での修正確認

nugetの履歴によるとnuget.org: Windows Azure Storage2013/11/27 に、2.1.0.4と、3.0.0が同時にリリースされています。同じコードをライブラリのバージョンだけ変更して実行します:

Install-Package WindowsAzure.Storage -Version 2.1.0.4

実行結果

GET URLがスッキリして、結果は 200 OK が帰ってきています。FIXされているようです。

http requestのtrace:

GET http://asdpojasldfj001.table.core.windows.net/people?$filter=PartitionKey%20eq%20%271%27&timeout=90 HTTP/1.1
User-Agent: WA-Storage/2.1.0.4 (.NET CLR 4.0.30319.34003; Win32NT 6.3.9600.0)
x-ms-version: 2012-02-12
Accept: application/atom+xml,application/xml
Accept-Charset: UTF-8
MaxDataServiceVersion: 2.0;NetFx
x-ms-client-request-id: e9319d53-b9eb-41c6-9a93-63566842984e
x-ms-date: Fri, 29 Nov 2013 23:33:17 GMT
Authorization: SharedKey asdpojasldfj001:*********************************************
Host: asdpojasldfj001.table.core.windows.net

http responseのtrace:

HTTP/1.1 200 OK
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: application/atom+xml;type=feed;charset=utf-8
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: d1056e7a-f0ff-4ab4-b5a4-4b546eb48515
x-ms-version: 2012-02-12
X-Content-Type-Options: nosniff
Date: Fri, 29 Nov 2013 23:33:17 GMT

96A
<?xml version="1.0" encoding="utf-8"?><feed xml:base="http://asdpojasldfj001.table.core.windows.net/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><id>http://asdpojasldfj001.table.core.windows.net/people</id><title type="text">people</title><updated>2013-11-29T23:33:18Z</updated><link rel="self" title="people" href="people" /><entry m:etag="W/&quot;datetime'2013-11-28T10%3A24%3A23.5715047Z'&quot;"><id>http://asdpojasldfj001.table.core.windows.net/people(PartitionKey='1',RowKey='1')</id><category term="asdpojasldfj001.people" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /><link rel="edit" title="people" href="people(PartitionKey='1',RowKey='1')" /><title /><updated>2013-11-29T23:33:18Z</updated><author><name /></author><content type="application/xml"><m:properties><d:PartitionKey>1</d:PartitionKey><d:RowKey>1</d:RowKey><d:Timestamp m:type="Edm.DateTime">2013-11-28T10:24:23.5715047Z</d:Timestamp><d:Data>foo</d:Data></m:properties></content></entry><entry m:etag="W/&quot;datetime'2013-11-28T10%3A21%3A02.0298712Z'&quot;"><id>http://asdpojasldfj001.table.core.windows.net/people(PartitionKey='1',RowKey='2')</id><category term="asdpojasldfj001.people" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /><link rel="edit" title="people" href="people(PartitionKey='1',RowKey='2')" /><title /><updated>2013-11-29T23:33:18Z</updated><author><name /></author><content type="application/xml"><m:properties><d:PartitionKey>1</d:PartitionKey><d:RowKey>2</d:RowKey><d:Timestamp m:type="Edm.DateTime">2013-11-28T10:21:02.0298712Z</d:Timestamp><d:Data>foo</d:Data></m:properties></content></entry><entry m:etag="W/&quot;datetime'2013-11-29T23%3A16%3A04.1332012Z'&quot;"><id>http://asdpojasldfj001.table.core.windows.net/people(PartitionKey='1',RowKey='3')</id><category term="asdpojasldfj001.people" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /><link rel="edit" title="people" href="people(PartitionKey='1',RowKey='3')" /><title /><updated>2013-11-29T23:33:18Z</updated><author><name /></author><content type="application/xml"><m:properties><d:PartitionKey>1</d:PartitionKey><d:RowKey>3</d:RowKey><d:Timestamp m:type="Edm.DateTime">2013-11-29T23:16:04.1332012Z</d:Timestamp><d:Data>foo</d:Data></m:properties></content></entry></feed>
0

おまけの 3.0.0 での修正確認

同じことを最新の 3.0.0 でやりました。バッチリ動きます。x-ms-versionが 2013-08-15になって結果がjsonになっています:

Install-Package WindowsAzure.Storage -Version 2.1.0.4

http requestのtrace:

GET http://asdpojasldfj001.table.core.windows.net/people?$filter=PartitionKey%20eq%20%271%27&timeout=90 HTTP/1.1
User-Agent: WA-Storage/3.0.0 (.NET CLR 4.0.30319.34003; Win32NT 6.3.9600.0)
x-ms-version: 2013-08-15
Accept-Charset: UTF-8
MaxDataServiceVersion: 3.0;NetFx
Accept: application/json;odata=minimalmetadata
x-ms-client-request-id: 5b6e366f-dde8-4ec0-b433-10fac62c117d
x-ms-date: Fri, 29 Nov 2013 23:17:23 GMT
Authorization: SharedKey asdpojasldfj001:*********************************************
Host: asdpojasldfj001.table.core.windows.net

http responseのtrace:

HTTP/1.1 200 OK
Cache-Control: no-cache
Transfer-Encoding: chunked
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8
Server: Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: fa6db02e-b080-4bc4-8761-1016920fb1b0
x-ms-version: 2013-08-15
X-Content-Type-Options: nosniff
Date: Fri, 29 Nov 2013 23:17:22 GMT

168
{"odata.metadata":"http://asdpojasldfj001.table.core.windows.net/$metadata#people","value":[{"PartitionKey":"1","RowKey":"1","Timestamp":"2013-11-28T10:24:23.5715047Z","Data":"foo"},{"PartitionKey":"1","RowKey":"2","Timestamp":"2013-11-28T10:21:02.0298712Z","Data":"foo"},{"PartitionKey":"1","RowKey":"3","Timestamp":"2013-11-29T23:16:04.1332012Z","Data":"foo"}]}
0

ソースコード上の修正点

2.1.0.4はgithub上でコードが公開されているので、レポジトリ上の修正点を確認しましょう。

ChangeLogでは:

Issues fixed in 2.1.0.4 :
  - Tables: Do not send the cast operator in the table query filter string.

microsoft-azure-api/Services/Storage/Lib/Common/Table/Queryable/ExpressionWriter.cs で、2.1でExpressionをURLに展開するときのUnaryの処理にcastを使ってしまっていたのを削除したようです。

修正のCommitは、XSCL 2.1.0.4 - Hotfixで、ソースは、ExpressionWriter.csです。

残念ながら、3.0.0は、まだコードが公開されていないので確認することができません。

まとめ

2.1.0.4/3.0.0では、Table Query での Cast 問題の問題はFIXされています。そのうちアナウンスは出ると思いますが、必要な場合は試してみてください。Windows Azure Storage Known Issues 2013/11で報告されていた幾つかの問題の中で、Cast問題はスマートに回避するのが難しいものだったので、これで解決されて助かります。これ以外のものはどちらということ利用者側のコードに問題がある場合に起きる問題な気がします。

本題とは外れますが、今回の場合では、363 byte(json) と、2,436 byte (xml)とhttp responseのbodyのサイズが大きく違い期待以上に良好な結果になっています。今回はデータが非常に小さいのでmeta 情報部分が冗長なxmlのオーバーヘッドが目立つ結果になっているのでしょうが、それにしても大きな違いです。