テスターですが何か?

ホビープログラマ略してHPです

Azure TableStorageの高速化(1) -エンティティグループトランザクション-

leave a comment »

Twitterや、このBlogでもAzureTableStorageの遅さについて言及していますが、(とくにデータ挿入が慣れ親しんだSQLServerに比べると劇遅)ダメな子ほどかわいく思えるもので何とか速くなるのであれば速くしてあげたいとおもうのが人間というものです。このエントリーではこのAzureTableStorageの高速の手段とその効果を検証したいと思います。

高速化の手法については以下の情報を参考にさせていただきました。

Windows Azure Table – テーブル ストレージのプログラミング(http://go.microsoft.com/?linkid=9734586)

Windows Azure Table の利用 ~ 特性とパフォーマンスの検証(http://msdn.microsoft.com/ja-jp/windowsazure/hh398428)

また、この検証の際に情報をいただいた@normalianさん、@statemachineさん、@A_Ymさんに感謝です。

 

エンティティグループトランザクション

エンティティグループトランザクションとは、RDBMSのトランザクションのようにエンティティのCUD操作をアトミックに実行する機能です。以下の制約事項がありますが、KVSでトランザクション制御を行う重要な機能です。

  • 実行できる操作は最大100個
  • 最大サイズは4MB
  • 同一テーブルの同一パーティションである必要がある

詳細は、「Windows Azure Table – テーブル ストレージのプログラミング」の4.9章を確認してください。

実はこのエンティティグループトランザクションがAzureTableStorageのパフォーマンスに非常に大きく影響を与えます。このエントリーでは、エンティティグループトランザクション有無のパフォーマンスの違いを簡単に検証しようと思います。

 

検証環境

  • Webロール
  • VMサイズ: S
  • インスタンス数: 1

 

検証プログラム

WebロールのASP.NET MVC3で100件のデータをAzureTableStorageへ挿入するプログラムです。コントローラーから文字列だけを返し、画面にデータ挿入にかかった時間を表示します。

ソースコードは以下を参照してください。最初はよくサンプルで公開されているエンティティグループトランザクション無しのプログラムにしています。100個のエンティティを作成しループ内でTableServiceContextへAddObjectし、最後にSaveChangesを実行しています。

 

OreModels.cs

    [DataServiceKey("PartitionKey", "RowKey")]
    public class OreModels
    {
        public string PartitionKey { get; set; }

        public string RowKey { get; set; }

        public string Data { get; set; }
    }

OreDao.cs

   
    public class OreDao
    {
        private TableServiceContext context;

        public OreDao()
        {
            // ストレージアカウントへ接続し、クライアントを作成
            string connectionString = RoleEnvironment.GetConfigurationSettingValue("StorageConnection");
            var account = CloudStorageAccount.Parse(connectionString);
            var client = account.CreateCloudTableClient();

            context = client.GetDataServiceContext();

            // 初回アクセス時はテーブルの作成を行う
            client.CreateTableIfNotExist("OreModels");
        }

        public void AddOre(IEnumerable<OreModels> ore)
        {
            foreach (var m in ore)
            {
                context.AddObject("OreModels", m);
            }
            context.SaveChanges();
        }
    }

HomeController.cs

    public class HomeController : Controller
    {
        public string Index()
        {
            var Models = new List<OreModels>();
            OreModels OreModel;

            for (var i = 0; i < 100; i++)
            {
                OreModel = new OreModels();
                OreModel.PartitionKey = "oretachinoAzureTableStoragegakonnaniosoiwakeganai";
                OreModel.RowKey = Guid.NewGuid().ToString("N");
                OreModel.Data = "oretachinoAzureTableStoragegakonnaniosoiwakeganai" + i.ToString();

                Models.Add(OreModel);
            }

            var Dao = new OreDao();
            var sw = new Stopwatch();

            sw.Start();
            Dao.AddOre(Models);
            sw.Stop();

            return string.Format("処理時間:{0}ミリ秒", sw.ElapsedMilliseconds.ToString());
        }
    }

 

エンティティグループトランザクションなし

まずは、エンティティグループトランザクションなしの状態でプログラムを実行してみます。

1回目 21.44秒
2回目 21.04秒
3回目 21.09秒
4回目 21.34秒
5回目 20.42秒
平均 21.07秒

この結果がどのくらい遅いかというと、5エンティティ/秒です。SQLServer/SQLAzureで単純なinsert処理が5レコード/秒のスループットであれば、誰の目から見ても障害です。むしろ、現在のハードウェアでSQLServerでこのスループットをC#/VBで実現することはある意味不可能だと思います。

巷で公開されているサンプルの通りにAzureTableStorageへデータを挿入するプログラムを記述すると、事故のような遅さになってしまいます。

 

エンティティグループトランザクションあり

このサンプルプログラムをエンティティグループトランザクションありに変更してみましょう。OreDao.csのSaveChangesメソッドを以下のように書き換えるだけです。

context.SaveChanges(SaveChangesOptions.Batch);

それでは、プログラムを実行してみましょう。

1回目 0.20秒
2回目 0.14秒
3回目 0.18秒
4回目 0.21秒
5回目 0.18秒
平均 0.18秒

あれ?(つд⊂)ゴシゴシ(;゚ Д゚) …!? な結果ですよね、20秒→0.18秒ですから100倍以上高速化しています。(もとが遅すぎるだけですが)ひょっとしたらSQLAzureよりも速いかもしれません。

 

結論

AzureTableStorageのエンティティ操作の際にはエンティティグループトランザクションは必須です。SaveChangesメソッドの引数を追加するだけでパフォーマンスが100倍になるのであれば、つけない理由はありません。

今回検証用に作成したソースはこちらからダウンロード可能です。「oretachinoAzureTableStorage_1.zip」をダウンロードしてみてください。

ただ、問題だと感じるのはエンティティグループトランザクションをありにしなければエンティティ操作が極端に遅くなるという情報が、初級・中級者向けのコンテンツで全く触れられていないことです。このエントリーのはじめに紹介した「Windows Azure Table の利用 ~ 特性とパフォーマンスの検証」ではエンティティグループトランザクションの利用を強く推奨していますが、ちょっと上級者向けな気がします。

 

以下のような初心者向けのコンテンツ(自分もお世話になりました)ではエンティティ操作にエンティティグループトランザクションが利用されていません。1件のエンティティを挿入する処理なので遅さを体感できるものではないのかもしれませんが、10件のエンティティを操作すると明らかに遅いことがわかります。結果、「AzureTableStorageは遅くて使えない」という結論になり、以降見向きもされなくなってしまう可能性があることが残念でなりません。

 

10 行でズバリ!! [C#] Windows Azure のテーブル ストレージ (Table Storage) を利用する

http://code.msdn.microsoft.com/WindowsAzure-10line-1ec3afc4

 

Task 2   Creating Classes to Model the Table Schema

http://msdn.microsoft.com/en-us/windowsazure/wazplatformtrainingcourse_exploringwindowsazurestoragevs2010_topic3

 

次のエントリーでは、万単位のエンティティ操作に効果があるかもしれない高速化方法の検証を行いたいと思います。

Written by david9142

2011年10月25日 @ 12:30 AM

カテゴリー: WindowsAzure

Tagged with ,

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。