評価してください: 

Windows Azure Table の利用 ~ 特性とパフォーマンスの検証

3. Windows Azure Storage 検証結果

更新日:2011 年 9 月 30 日
執筆者:株式会社リード・レックス
近江 武一
高木 俊一

目次

※この内容は 2011 年 4 月時点での情報を元に執筆されたものです。


ここでは、データ作成のパフォーマンスに絞って、いくつかのパターンでパフォーマンスを比較します。Windows Azure Table では一貫性を保証していますが、書き込み性能が心配です。また、実際にデータを入れてスケールするのかも確認する必要があります。

ページのトップへ


データ サイズの影響

Windows Azure Table に対して、Web Role インスタンスの VM サイズを Small (S) または Extra Large (XL) にし、単一スレッドで、データ サイズを 1 KB から 128 KB まで変えて、単一パーティションに各 10 万件の挿入を行いました。Windows Azure コンピューティングと Windows Azure ストレージは、同一データセンター (North Central US) 内で、同じアフィニティー グループに属しています。

結果を見ると、下記のような傾向があることがわかります。

  1. 処理速度は平均値の左側がピークとなって裾野が遅い方に広がった山のように分布しています。
  2. エンティティ サイズが大きくなると、ピークが低くなり、山が右 (遅い方) に移動します。
  3. VM サイズによる違いはあまりありません。
  4. KB/s で見たときのスループットは、エンティティ サイズ増加にしたがって (ほぼ線形に) 右上がりとなりますが、傾きは 1/2 程度です。4 KB では 1 件のデータ挿入あたり 46 ~ 48 ミリ秒、その 16 倍のデータ サイズである 64 KB でも処理時間は 91 ~ 100 ミリ秒 と、約 2 倍程度にしかなっていません。
  5. 2 KB と 8 KB のエンティティ サイズの時の結果が、全体の傾向と違いますが、基本的には一度に書きこむ単位が大きい方が良い性能が出ることがわかります。

今回のような簡単なテストでは、インスタンス サイズによる違いはあまりないようです。このテストは単一スレッドで行ったので、ストレージにリクエストを出した後は実行することが無く、GC やストレージとのターンアラウンドがボトルネックになったのだと考えられます。

コラム 1

2 K と 8 K での傾向の違いについて

今回のテスト プログラムの作りとデータ サイズが小さいことが相まって TCP/IP レイヤーの遅延 ACK 設定の影響を大きく受けたのが原因でした。

今回の 2 K のエンティティの挿入では、ストレージ サービスからのレスポンスの TCP/IP のレイヤーでデータ長さは、3974 バイト 、データは受信時に、1460 バイト、1460 バイト、1054 バイトの 3 つのセグメントに分割されて転送されていました。Azure OS の遅延 ACK の設定 (TcpAckFrequency) は、2 となっているので、クライアントは、3 つめのセグメントの送信を受けた後すぐに Ack を送らずに TCPACK 遅延タイマー分 (200 ミリ秒) 待ってしまうような状況になることがあります。これが全体的な遅延の原因でした。

この場合でも、必ず遅延タイマー分を待つわけではなく、実測で 20% ほどの処理で 200 ミリ秒 余計にかかっており、結果として平均時間ではかなり遅くなって見えるという結果になっています。

今回の検証プログラムでは、1 つの TCP/IP 接続で 1 つの小さいエンティティの挿入しか行わずに、一つ一つストレージ サーバーの応答待ちながら処理していくような作りになっていることもあり、大きく遅延 Ack の影響を大きく受けてしまったようです。
バッチ処理などで、大量にデータ処理をする場合には、サーバーにまとめて送って、結果もまとめて受けとることをお勧めします。それには、バッチリ クエストを使ってください。

VM サイズ: S
データ
サイズ
平均
[ms]
最小
[ms]
最大
[ms]
70%
[ms]
80%
[ms]
90%
[ms]
スレッドバッチ サイズ
[エンティティ]
スループット
[エンティティ/s]
スループット
[KB/s]
135151850303545112625.64
28615201550225270111122.22
440151490354560112495.24
812515512023526530011862.02
16502040104045551120313.73
3269201893045501101113426.67
647530154060751151113820.51
1281134518001051301751191122.81
VM サイズ: XL
データ
サイズ
平均
[ms]
最小
[ms]
最大
[ms]
70%
[ms]
80%
[ms]
90%
[ms]
スレッドバッチ サイズ
[エンティティ]
スループット
[エンティティ/s]
スループット
[KB/s]
140153310404565112423.81
2721513004570265111326.67
4371514253540551126102.56
8841512105590280111188.89
16532012805565801119296.30
32542012555060751118561.40
645325136050557011181122.81
128844024070758511511111471.26

表 1 データ サイズに関するベンチマーク結果


図 7 VM サイズ が S の場合の 処理時間分布


図 8 VM サイズが XL の場合の処理時間分布


図 9 VM サイズが S の場合の処理時間、スループット


図 10 VM サイズが XL の場合の処理時間、スループット

ページのトップへ


バッチ モードを使った一括処理

次に、同様な環境下で、エンティティ サイズを 4 KB8 にし、エンティティ グループ トランザクション (EGT) を使って、複数のエンティティをバッチ処理して比較しました。(なお、バッチ サイズが 1 の場合のみ、バッチ リクエストではありません。)

全体的な傾向としては、一度のリクエストで処理されるエンティティ数を増やすと、全体の処理時間は増えますが、エンティティあたりの処理時間は減少します。例えば、VM サイズが XL でバッチ サイズ 4 を処理する時間 (108 ミリ秒) を基準とした場合、4 倍の 16 エンティティをバッチ処理しても、232 ミリ秒 (約 2 倍)、また 16 倍の 64 エンティティの場合も 511 ミリ秒 (約 5 倍) の時間しかかかりません。

また、バッチに含まれるエンティティが増えると、ピークが低くなり、山がなだらかになります。
これも、インスタンス サイズの影響はあまり受けていません。おそらく、単一スレッドのためインスタンスの能力には余裕があると思われます。

また、その一方でデータ サイズに関するベンチマーク結果と同一リクエスト サイズで比較すると、下記のようになります。

データ サイズ
[KB]
バッチ サイズ平均処理時間
[ms]
スループット
[KB/s]
備考
64194667 
416273232 
41592102EGT を使わずに 16 回
処理した場合の参考値

表 2 VM サイズが XL の場合のエンティティ グループ トランザクションの効果

この結果から、パーティション内で複数エンティティに分割するよりも、単一エンティティ内にデータを集約した方が、データ挿入処理のパフォーマンスが向上すると言えます。
そのため、まとめて読み書きされるようなデータではエンティティをなるべく分割せずに、全体を 1 エンティティで表現した方が、データ挿入についてはより良いパフォーマンスが得られると言えます。

VM サイズ: S
バッチ
サイズ
平均
[ms]
最小
[ms]
最大
[ms]
70%
[ms]
80%
[ms]
90%
[ms]
バッチ サイズ
[エンティティ]
スループット
[エンティティ/s]
155201610556585117
4113351410115135185434
162536018602903504451663
323549575654154956453290
646191704656569581099064103
100      100
VM サイズ: XL
バッチ
サイズ
平均
[ms]
最小
[ms]
最大
[ms]
70%
[ms]
80%
[ms]
90%
[ms]
バッチ サイズ
[エンティティ]
スループット
[エンティティ/s]
1431512430405065122
4108301540105130195435
162325549852753254151668
3233490411154104756003294
645111901058054066087064124
100      100

表 3 バッチ サイズに対するベンチマーク結果


図 11 VM サイズが S の場合の、エンティティ グループ トランザクションのスループット


図 12 VM サイズが XL の場合の、エンティティ グループ トランザクションのスループット

8本ドキュメントでは、従来アプリケーションでの実績から 4 KB を選択し測定しました。

ページのトップへ


マルチ スレッドを使った同時処理

マルチ スレッドでのエンティティ挿入処理について、スレッド数を変化させ、パフォーマンスへの影響を検証しました。エンティティ サイズは 4 KB、バッチ リクエストは利用していません。

ページのトップへ


単一パーティション

ベンチマーク結果において、VM サイズ M の 64 スレッド、および VM サイズ XL の 64、128 スレッドの条件で、共に 556 エンティティ/s のスループットとなりました。特に XL では、64 スレッドおよび 128 スレッドでスループットの変化がなく、556 エンティティ/s が性能上限のようです。それに対し、VM サイズ S では、最大で 476 エンティティ/s に留まり、どのスレッド数においても 556 エンティティ/s のスループットまでは行きませんでした。このことから、CPU コア数が 1 である VM サイズ S では、CPU ボトルネックにより単一パーティションの性能を使い切ることができないと考えられます。

この結果は、Windows Azure ストレージのパフォーマンス ターゲット9 で示されている、1 パーティションあたり 500 エンティティ/s のトランザクション性能と比較しても妥当な結果だと思われます。また見方を変えると、64 スレッドによる同時アクセスで単一パーティションの性能を使い切ってしまうと言えます。

VM サイズ: S
スレッド平均
[ms]
最小
[ms]
最大
[ms]
70%
[ms]
80%
[ms]
90%
[ms]
スループット
[エンティティ/s]
1283902042750430515675333
641291559480125145195476
328215159558095120370
16641540406575100238
858153500556585133
45115270050557574
24615282040507041
VM サイズ: M
スレッド平均
[ms]
最小
[ms]
最大
[ms]
70%
[ms]
80%
[ms]
90%
[ms]
スループット
[エンティティ/s]
1283421549465380460600370
641111573820115135175556
3285153418580100135370
1657152935606585256
853152935556585145
45615301060709567
24715487545608040
VM サイズ: XL
スレッド平均
[ms]
最小
[ms]
最大
[ms]
70%
[ms]
80%
[ms]
90%
[ms]
スループット
[エンティティ/s]
1282402045055260305385556
64104154815110130160556
32711516607585110476
1657151795606585256
859151715607090128
44915516050608078
24515510045557042

表 4 マルチ スレッド (単一パーティション)


図 13 VM サイズが S の場合の、単一パーティション、マルチ スレッド


図 14 VM サイズが M の場合の、単一パーティション、マルチ スレッド


図 15 VM サイズが XL の場合の、単一パーティション、マルチ スレッド

9 Windows Azure Storage Abstractions and their Scalability Targets (英語)

ページのトップへ


パーティション分割

書き込み先が複数パーティションになるように変更し、同じようにデータ挿入処理を行いました。
このテストでは、パーティション毎に負荷が分散されて、単一パーティションより良い結果を出ることを期待しました。ですが、ベンチマーク結果では単一パーティションのベンチマークと全く変わらない結果となりました。この件については、別途文末脚注で考察します。

VM サイズ: XL
スレッド平均
[ms]
最小
[ms]
最大
[ms]
70%
[ms]
80%
[ms]
90%
[ms]
データ サイズバッチ サイズスループット
128223205189024528535541556
64112151050012014518041556
32651510185708010541476
165715246055709041278
853152839050608541139
4451541154555704183
2471533855060754140

表 5 パーティション分割後


図 16 マルチ スレッド (複数パーティション)

ページのトップへ


複数インスタンスからのアクセス

上記のマルチ スレッドのプログラムを使って、スレッド数 16 の条件で、複数インスタンスからデータ挿入処理のベンチマークを行いました。

この結果を見ると、4 インスタンスの場合で 970 エンティティ/s、8 インスタンスの場合で 1808 エンティティ/s と、1 インスタンスのときの性能上限を突破しています。また、インスタンス数を増加させても平均処理時間は 70 ミリ秒 弱で一定であると共に、スループットがインスタンス数に比例 (傾き 1) して向上しており、インスタンス数に対して綺麗にスケールしました。

今回のテストでは、パフォーマンスの上限に達していない10 が、パーティション サーバー間でうまくロード バランスされればこのような結果になり、ロード バランスされないと、前述したシングル インスタンス マルチ スレッドのような 500 エンティティ/s 程度になると言えます。

コラム 2

同じプログラムでスレッドを増やした場合と、インスタンスを増やした場合の違い

今回の検証プログラムでは大量にオブジェクトを作成しており、それが原因でマルチ スレッドの場合のパフォーマンスが頭撃ちになっていました。試しに、Azure OS 上で別プロセスを起動して別 AppDomain で処理をさせたところ、マルチインスタンスと同様な傾向になりました。実際の大規模バッチに置いては、オブジェクトの生成を減らす工夫やパーティショニングが重要になります。

バッチが上手く分散処理 (パーティショニング) されるようになっていれば、複数のプロセスや、Azure の複数のインスタンスを使って並行実行することができ、パフォーマンスの向上が見込めます。

インスタンススレッドデータ サイズバッチ サイズ平均スループット
81641691808
4164168970
2164170476
1164167238

表 6 インスタンスによる影響


図 17 複数インスタンスでのスケール

10 Windows Azure Storage Abstractions and their Scalability Targets によると、ストレージ アカウント当たり、最大 5,000 エンティティ/s

ページのトップへ


データ件数によるパフォーマンスの変化

VM サイズが M のインスタンスを 8 個用意して、4 億件 (400 x106) のデータを挿入するテストを行い、時系列でパフォーマンスの変化をみました。このとき、パーティションは、4 億個出来ています。
その結果、パフォーマンスはほとんど変動なく、データ増加によるパフォーマンス劣化は認められませんでした。


図 18 大量データ

ページのトップへ


Windows Azure Table の特性と検証結果のまとめ

  1. データ サイズ

    データ サイズがストレージ性能へ及ぼす影響は小さいです (2 KB、8 KB は要注意)

  2. スループット

    エンティティ グループ トランザクションを使うと、スループットが上がります。トランザクションが必要ない場合も、使えるときは積極的に使うべきです。
    同一テーブルに異なったクラスを保存できる (スキーマレス) ので、関連するデータは同一パーティション キーにして同じテーブルに入れるとよいです。
    スループット、レイテンシー、コストの兼ね合いで、バッチ サイズを選ぶべきです。

  3. スケーラビリティ

    スケーラビリティを考えると、パーティションを分割するべきです。
    パーティション分割のペナルティは、複数パーティションをまたぐアクセスだけです。

  4. VM サイズ

    VM サイズの選択は、アプリケーションがどれぐらいメモリ、CPU を使うのかで決めます。今回のテストでは、S サイズだと、スレッド数が多くなると頭打ちになる傾向がありました。M サイズ 1 インスタンスで、ストレージの単一インスタンスのパフォーマンス上限に達しました。それ以外は、VM サイズによる違いは認められませんでした。

  5. パーティションを分けてもパフォーマンスが頭打ちのときは、要注意です。

    今回のような書き込みが大量に発生するバッチなどのパターンで、問題が起きることがあるかもしれません。

おすすめ

  1. トランザクションが必要なデータは、同一テーブル、同一パーティションに入れます。
  2. パーティションは積極的に使ったほうが分散されます。
  3. 更新は、まとめて行なったほうが良いです。

ページのトップへ