Windows Azure は Auto Scale の夢を見るか? ひとりでもやってやるです編

※この投稿は Windows Azure Advent Calendar jp: 2011 の17日目です。 ただいま17日の27時過ぎですキリッ(ごめんなさい・・・)
しょっぱなからぶっ飛んだネタが展開されたAdvent Calendarですが、ネタ方向ではいいのが思いつかなかったので淡々と機能紹介でもすることにしますw

ということで Microsoft Enterprise Library 5.0 Integration Pack for Windows Azure – Autoscaling Application Block 、通称WASABiを簡単に紹介した前回に続き、実際に触ってみてAuto Scaleはどんなものか見てみようと思います。正式リリースしましたしね。
今のところ英語情報しかありませんし、全部把握できてるわけではないので細かいところで間違いがあるかもしれませんのであくまで参考まで。
ちゃんと元ドキュメント見て実装等は自己責任で宜しくお願いします。

という逃げ口上もしたうえで早速。

1. WASABi 概要

WASABiは Enterprise Library Integration Pack for Windows Azure に含まれる Windows Azure 用のオートスケール用アプリケーションブロックです。その他にも追加されたばっかりの"Topaz"と呼ばれる Transient Fault Handling Application Block などいろいろあります。

WASABiの内部はさらに細かくブロック分けされており、必要に応じて独自の処理を実装できるようになっています。
たとえばロギングの部分やルールの評価、アクションなど。

既定では以下のルールに従って評価しアクションを実行できます。

  • 静的ルール(Constraint Autoscaling Rules)
    • 静的ルールではスケジューリングなどが行えます。
      たとえば指定日や指定時刻だけインスタンス数を増やすなど。
      また無尽蔵にスケールしないように最大インスタンス数や最小インスタンス数を定義することもできます。
  • 反応的ルール(Reactive Autoscaling Rules)
    • 反応的ルールでは以下の値の最大値や最小値、直近の値、平均値などを算出して評価します。
      ルールとしては例えばキューの直近の値が50を超えたら指定アクションを実行(インスタンスを増やす等)といった記述が可能です。
    • パフォーマンス
      • 対象ロールのパフォーマンス(Azure Diagnosticsで出力されるパフォーマンスカウンタ)の値を見て判断することができます。
    • キュー
      • 指定したAzure Storage Queueの値(キュー数)を見て判断することができます。

 

  • アクション
    • スケール
      • スケールは対象のインスタンスを増減させることができます。
    • 設定変更
      • 対象ロールのサービス設定(.cscfgに記述される値)を変更することができます。
      • アプリケーション側でサービス設定変更のイベントをトラップし、設定値を確認することでいろいろな処理が可能です。
        たとえばメンテナンスモードに入ったり。。(スケールと違いアプリケーション側で対応する処理を考えて実装する必要がありますが)
    • 通知
      • 通知は指定されたメールアドレスにメールを送信することができます。

また対象のロールを複数まとめてグループ化することもできます。

対象ロールの設定やルールについてはXMLファイルで定義します。
WASABiの設定そのものはWASABiを実行する(WASABi本体のAutoScalerが実行される)アプリケーションの設定ファイル(app.config)に記述します。
ルール等の設定ファイルはローカルで保持することもできますが、Azure Storage Blobに保存して共有することができます。
また設定ファイルそのものも指定間隔で取得・評価するので融通が利くようにBlobに保存するのがよいかもしれません。

ソースも公開されてるので内部動作を確認したり独自実装しやすいのもポイントですね。
バイナリおよびソースはダウンロードセンターから入手することもできますし、NuGetで入手することもできます。
単純に利用したいだけならNuGetが便利です。

あ、ちなみにライセンスはMs-PLです。また全体的に怪しい日本語(※このBlog)が嫌な人はMSDNのデベロッパーガイドを見てくださいw

2. WASABi を使ってみる

ではサンプル的にWASABiを触ってみたいと思います。
今回はオートスケールしたい対象としてWebロールなWebアプリケーションと、監視を行うWorker Roleで実装したいと思います。

※既にEnterprise Library 5.0 Optional Update 1を.msi経由でインストールしてる場合は注意が必要です。詳しくはリリースノート参照。

2.1 準備

サンプルを動作させる前に以下の準備をしておきます。

  • Enterprise Library Configuration Tool
    • Enterprise LibraryではApp.configに各設定を行うためのGUIツールが用意されています。※別に手書きでもいいですけど。。
    • 今回はEnterprise LibraryのものではなくAutoScalingブロック用のConfiguration Toolを使用します。

2.2 Webロールの作成

ではまずさくっとオートスケール対象となるWebロールを作りましょう。以下略。

Webアプリケーションのほうは適当に負荷がかかるように「お、落ち着いて素数を数えるんだ」にします。

ここでのポイントはロールエントリーポイント内でパフォーマンスカウンタをDiagnosticsで転送するように指定してるところでしょうか。
今回のサンプルではProcessor Timeだけ転送するようにします。

public class WebRole : RoleEntryPoint
{
	public override bool OnStart()
	{
		DiagnosticMonitorConfiguration dmc = DiagnosticMonitor.GetDefaultInitialConfiguration();

		dmc.Logs.BufferQuotaInMB = 4;
		dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromSeconds(30);
		dmc.Logs.ScheduledTransferLogLevelFilter = LogLevel.Warning;

		dmc.PerformanceCounters.BufferQuotaInMB = 4;
		dmc.PerformanceCounters.DataSources.Add(
			new PerformanceCounterConfiguration()
			{
				CounterSpecifier = @"\Processor(_Total)\% Processor Time",
				SampleRate = TimeSpan.FromSeconds(2)
			}
			);
		dmc.PerformanceCounters.ScheduledTransferPeriod = TimeSpan.FromSeconds(30);

		DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", dmc);

		return base.OnStart();
	}
}

あとAzureプロジェクトのほうできちんとAzure Storageの設定をしておきます。(パフォーマンスカウンタ転送させるので)

できたらデプロイしておきましょう。

 

2.3 Workerロールの作成(AutoScalerが動作するロール)

次はオートスケール対象を見てスケールさせたりする、WASABi本体(ホスト)を作ります。

さくっとWorkerロールでね。

プロジェクトを作ったらNuGetを使ってWASABiをプロジェクトに追加します。

検索欄でWASABiと検索すれば出てきます。ソース見たい人はソースも入手できますね。

依存するものとしては以下のようなものがあり、一緒に追加されます。

インストール後、プロジェクトにいろいろファイルが追加されます。

2つの.xsdファイルはAutoScalerが参照する設定ファイルのスキーマ定義です。

 

2.4 ルールの作成

では次にWASABi本体(AutoScaler)が参照するオートスケールのルール等を作成しましょう。別にソリューションアイテムにする必要もないのですが、属性とかインテリセンスが利くのでVisual Studioで編集します。

まずAutoscalingServiceModel.xmlのほうから。

<?xml version="1.0" encoding="utf-8"?>
<serviceModel xmlns="http://schemas.microsoft.com/practices/2011/entlib/autoscaling/serviceModel">
	<subscriptions>
		<subscription name="YourSubscription"
					  subscriptionId="<サブスクリプションのID>"
					  certificateStoreLocation="LocalMachine"
					  certificateStoreName="My"
					  certificateThumbprint="<ManagementAPIで使う証明書の拇印>">
			<services>
				<service dnsPrefix="<対象のホストサービスのDNSプレフィックス>"
						 slot="Production"
						 scalingMode="Scale">
					<roles>
						<role alias="MvcWebRole1"
							  roleName="MvcWebRole1"
							  wadStorageAccountName="wadStorageAccount"/>
					</roles>
				</service>
			</services>
			<storageAccounts>
				<storageAccount alias="wadStorageAccount"
								connectionString="<WindowsAzureStorageへの接続文字列>">
					<queues>
						<queue alias="autoscaletestqueue"
							   queueName="autoscaletestqueue"/>
					</queues>
				</storageAccount>
			</storageAccounts>
		</subscription>
	</subscriptions>
</serviceModel>

このXMLファイルでターゲットのサブスクリプションやホストサービス、ロール、Azure Storageへの接続文字列などを定義します。

注意点はManagement APIで利用する証明書の拇印でしょうか。ご存知かと思いますがManagement APIを使う場合、管理ポータルに追加した証明書の対となる秘密鍵付証明書が必要です。で、ここではその証明書の拇印を指定します。

感の良い方はわかると思いますが、AutoScalerがスケールする際にManagement APIを利用するので、AutoScalerが何らかの形でこの秘密鍵付証明書にアクセスできないといけません。このコンフィグ例だとローカルコンピュータの個人用証明書ストアを参照するように設定しています。(この辺は後述)

さて次はAutoscalingRules.xmlファイルのほうです。

<?xml version="1.0" encoding="utf-8"?>
<rules xmlns="http://schemas.microsoft.com/practices/2011/entlib/autoscaling/rules">
	<constraintRules>
		<rule name="default"
			  rank="10"
			  enabled="true">
			<actions>
				<range target="MvcWebRole1"
					   min="1"
					   max="5" />
			</actions>
		</rule>
	</constraintRules>
	<reactiveRules>
		<rule name="High Queue Length" enabled="true">
			<when>
				<all>
					<greaterOrEqual operand="QueueLength_05Minutes" than="5"/>
				</all>
			</when>
			<actions>
				<scale target="MvcWebRole1" by="1"/>
			</actions>
		</rule>
		<rule name="CPU_Busy"  enabled="true">
			<when>
				<all>
					<greaterOrEqual operand="PerfCounter" than="80"/>
				</all>
			</when>
			<actions>
				<scale target="MvcWebRole1" by="1"/>
			</actions>
		</rule>
	</reactiveRules>
	<operands>
		<queueLength alias="QueueLength_05Minutes"
					 queue="autoscaletestqueue"
					 aggregate="Max"
					 timespan="00:05:00" />
		<performanceCounter aggregate="Average"
							alias="PerfCounter"
							performanceCounterName="\Processor(_Total)\% Processor Time"
							source="MvcWebRole1"
							timespan="00:05:00"/>
	</operands>

</rules>

大体見ればわかる感じですが、静的なルールとしてロールの最大・最小インスタンス数を定義してるのと、ReactiveRulesで先ほど設定したパフォーマンスカウンタの値やキューの状態を見てアクションを定義しています。

細かな要素や属性の内容はドキュメントを参照してもらうとして、ここではキューの最大値が5異常、CPU利用率の平均が80%以上の場合にインスタンスを1つ増やすようにしています。

もちろん減らしたり、条件をANDやORで複数定義することもできます。他のアクションとしてWindows Azureの対象ロールのサービス設定を変更したり、メール送信もできます。

あと注意点としてはoperandsのtimespanは5分以上を指定することでしょうか。5分間でMaxなのかAverageなのかを判断するのですが5分未満を指定するとAutoScalerが例外吐きますので注意。

さてこれで2つのファイルが作成できました。

今回はこれらの設定ファイルをBlobに置いておこうと思いますので、Azure Blobに適当にコンテナを作ってUploadしてください。

ContentTypeはtext/xmlにしておいてください。一応。

あ、XMLの中身についてはリファレンスを見るのが良いかと思います。

2.5 AutoScalerの設定

さて次はWASABi本体であるAutoScalerの設定です。

AutoScalerはアプリケーション設定ファイル(app.config)を見ますので、こちらにもろもろ追加していきます。

App.configを選択して「Edit configuration file」を選択します。

Enterprise Library Configurationが起動するので「Blocks」-「Add Autoscaling Settings」を選択します。

項目が追加されたら、もろもろ設定してきましょう。注意点としてはStorage Account Connection Stringはちゃんと設定すること(各項目にあるので)とかでしょうかね。

今回はサービス設定ファイルに定義されてるDiagnostics用の接続文字列を使うことにします。

また、Rules StoreおよびService Information Storeは今回それぞれBlobを使いますが、ここで設定する値は先ほどBlobにUpした内容と合わせてください。

Execution LeaseはAutoScalerが複数台動作する際に、1つのAutoScalerだけが実行するように制御するために利用します。

最終的にはこんな感じに。

保存してApp.configに上書きすればOK。

最後にAutoScalerを起動するようにWorkerロールのロールエントリポイントを修正します。

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.WindowsAzure.Autoscaling;

namespace WorkerRole1
{
	public class WorkerRole : RoleEntryPoint
	{
		private Autoscaler autoscaler;

		public override void Run()
		{
			autoscaler = EnterpriseLibraryContainer.Current.GetInstance<Autoscaler>();
			autoscaler.Start();

			while (true)
			{
				Thread.Sleep(10000);
				Trace.WriteLine("Working", "Information");
			}
		}

		public override bool OnStart()
		{
			CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
			{
				configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
				RoleEnvironment.Changed += (sender, arg) =>
				{
					if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
					.Any((change) => (change.ConfigurationSettingName == configName)))
					{
						if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
						{
							RoleEnvironment.RequestRecycle();
						}
					}
				};
			}); 
			
			return base.OnStart();
		}

		public override void OnStop()
		{
			autoscaler.Stop();
		}
	}
}

コード貼り損ねてる可能性があるので一応画像でも。

基本はAutoScalerのインスタンス作ってStartメソッド呼ぶだけです。

あとは証明書ですが、秘密鍵付証明書ってどうやって配布するの?というところですがリモートデスクトップ接続とかと同じようにホストサービスの証明書として登録しておけばインスタンス起動時に自動的に配布されるようにAzureはなってます。

ということで、これまでもろもろ設定してきた拇印の証明書を管理ポータルから追加しておきましょう。

で、この証明書ですがLocalMachineの個人用ストアに保存されます。ですが普通ここにはアクセスできなかったりするのでWorkerロールを特権で動作するようにしておきましょう。

もうちょっとやりようはいろいろあるとは思いますけど(要は証明書の配布とアクセスができればいいので)、ま今回はこんな感じで。

さて、これで一応準備は完了。さくっとデプロイしてみましょう。

 

2.6 動作確認

初期状態はこんな感じです。

ターゲットが1インスタンスで動作してます。

Azure Storageは

実行してるよファイルが指定したとおりできてます。Queueも見てみましょう。

AutoScaletestqueueは今回のテスト用に用意した動作確認用のキューです。このキューに入ってる数をみてスケールするようなルールを今回は作ってます。

RequesttrackerはApp.configで指定したトラッキング用のキューですね。

Tableには観測してる値が入ります。今回のルールだとQueueLengthとパフォーマンスカウンタの値がそれぞれ入ります。で平均値や最大値なんぞを見るわけですね。

さてそれでは実際にテストしてみましょう。まずは対象のQueueにメッセージをどんどん入れていきます。今回は5以上でスケールアウト(1インスタンス増加)するルールですね。

ルールの評価タイミングが来ると、設定したルールに従い合致すればアクションが実行されます。アクションが実行されるとRequestTrackerキューにメッセージが入ります。(※そのように設定した場合)

また、実際にアクションで指定したとおり対象ロールのインスタンス数が1つ増えます。

最終的には2インスタンス(+1インスタンス)となります。

さていったんメッセージたくさん入れたキューを綺麗にして、次はCPU負荷のルールを見てみたいと思います。

「お、落ち着いて素数を数えるんだ」に対してたくさんリクエストを投げて、過負荷な状態を作ってみます。

※本当はもっとたくさんリクエスト投げてます

で、100%近い負荷をかけるとルールが評価されてアクションが実行されます。

今回も+1インスタンスするルールにしてるので、先ほどの2インスタンスから+1で3インスタンスにスケールしました。

という感じでなんとなく動作の雰囲気はわかって頂けたでしょうか。

 

今回はスケール対象のロールとWASABiが動作するWorkerロールを分けましたが、スケール対象がWorkerロールでWASABiもホストする(同居する)というのももちろんあり得ます。その場合はOnStartじゃなくてRunメソッド内でAutoScaler.Startを呼ぶ必要があるとかいろいろあるので詳しくはドキュメントを参照ください。

3. おまけ

3.1 デバッグについて

Windows AzureのCompute EmulatorはManagement APIをサポートしていませんので、実際にスケールさせるアクションを確認することができませんので注意が必要です。 ま、しょうがないですね。

またAutoScalerそのものは単体で動作させることができるのでテストやオンプレミスなアプリケーションで動作確認を行うことが可能です。

たとえばコンソールアプリでも適切にApp.configを構成すればAutoScalerのStartメソッドで起動することができます。

あとは延々とループして待機しておけばルールに従って処理してくれます。

※Azureのサービス設定から接続文字列をとってきたりできないので固定値にするなど注意が必要

 

3.2 WASABiCmdlets

正式リリースと同時にCmdletsも用意されました。

ルールの有効・無効を行ったり、設定変更したりできるようですね。結構便利かも。

 

4. まとめ

WASABiを使うとオートスケールの実装が意外と簡単にできることがわかりました。

ただ注意点としてはオートスケール機能があるだけですべての問題が解決する銀の弾丸ではないので気を付けたいですね。

今のAzureの仕組みだとスケールするのに若干(数分~数十分)時間がかかるので瞬時に対応、というわけにはいきません。

なんにせよインスタンス数の増減を行うということは今の状態が適切ではないという判断なので、何が適切なのかといったベースラインをきちんと把握することが大事です。

基本的にこのあたりはアプリケーション毎で変わりますし、どうしたいか?というビジネス的な判断も入りますので導入・運用はよく考えて行いましょう。

でもまぁ結論としては、Windows Azure はオートスケーリングが夢ではなく現実のものとなったわけです。これがいい夢なのか普通の夢なのかはたまた正夢なのかは自分次第ってことでしょうかw

Enterprise Library配下なのでフィードバックやカスタマイズもしやすいですしね。みなさん自身のオートスケールを実装するのもいいんじゃないでしょうか!

というわけで Advent Calendar 17日目でした。おつかれさまでした。

Appendix

コメントを残す

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

WordPress.com ロゴ

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

Twitter 画像

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

Facebook の写真

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

Google+ フォト

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

%s と連携中