Windows Azure
Windows Azure でコンシューマー デバイス用にきわめてスケーラブルなプラットフォームを構築する
Bruno Terkaly
Ricardo Villalobos
この記事では、スケーラビリティと相互運用性について取り上げます。現在広く利用され、何百万人ものユーザーが利用している可能性があるモバイル プラットフォームの多様性をサポートするアーキテクチャにはこの 2 つの特性が必要です。図 1 は、現在の開発者にとって一般的かつ困難が伴うシナリオとして、この多様性を示しています。Web ベースのサービスをモバイル デバイスに提供することは難しく、個性的で多様なツール、言語、および IDE が必要です。利用可能な Web サービスも多様化し、データのサイズもテラバイト単位になることから、高い拡張性を実現するにはこの多様性の克服が求められます。
図 1 開発者にとって課題であるモバイル テクノロジの多様性
アプリケーションの種類 | プラットフォーム | 開発環境 | 言語 |
モバイル | Windows Phone | Visual Studio | C# |
モバイル | Android | Eclipse | Java |
モバイル | iOS | Xcode | Objective-C |
クラウド ベースの Web サーバー | Windows Azure | Visual Studio | C# |
開発者は、Web アプリケーションのスケールを 2 つの異なる側面に基づいて変換する必要があります。1 つの側面はコンピューター処理、つまり、モバイル Web 要求に応答するホスティング プロバイダーが利用可能にできる Web サービス インスタンスの数です。もう 1 つの側面は、データのスケーラビリティです。あるクラウド プラットフォームは、専用のストレージ サービスを通じてデータのスケーラビリティを実現しています。これにより、開発者は、テラバイト単位のデータを何百万人ものモバイル ユーザーに拡張し、複数のサーバーに簡単にパーティション分割できます。その結果、パフォーマンスの向上、冗長性、およびペタバイト規模の容量サポートが実現されます。
できる限り多種多様なクライアントとの通信をサポートするため、相互運用可能なアプローチが必要です。データ形式からネットワーク プロトコルまで、あらゆる条件を注意深く検討する必要があります。独自のコーディングを最小限に抑え、可能な限りオープン標準を利用することが解決策となります。
今回は、マイクロソフトのクラウド プラットフォームである Windows Azure でホストされた RESTful Web サービスを使用して、相互運用性の課題と高い拡張性に関する問題を解決します。
RESTful Web サービスに基づくリファレンス アーキテクチャを 図 2 に示します。RESTful アーキテクチャは HTTP/1.x に沿って開発されているため、相互運用可能です。また、多数のクライアントに一貫性のある通信を提供します。この REST に代わるアーキテクチャが SOAP です。ただし、SOAP には低速なデータ ペイロードが大量に含まれ、処理が複雑になるため、ここでは使用しません。
図 2 オープン標準に基づくソリューション
Windows Azure では、必要に応じて簡単にスケールを増減できます。Windows Azure ポータルまたは管理 API を通じて、数 ("インスタンス数") を変更するだけで、RESTful Web サービスを簡単に拡張し、さまざまな要求に対応できます。
今回の実装では、データ形式として XML ではなく、コンパクトな形式で広くサポートされている JSON を使用します。XML を使用すると、大量のペイロードが含まれることになります。
多くのベンダーが RESTful Web サービスのクラウド ホスティング ソリューションを提供していますが、Windows Azure にはいくつかメリットがあります。まず、アジア、ヨーロッパ、および北アメリカにある、大幅に自動化された 6 つのデータセンターから選択できます。これには、24 個のコンテンツ配信ネットワーク (CDN) からのサポートも含まれます。そのため、データの局所性を高め、短い待機時間でユーザーに接続できます。
Windows Azure には、強力な開発者用ツールだけでなく、さまざまなストレージ オプションおよび処理オプションが用意されています。バイナリ ラージ オブジェクト (BLOB) から関連するストアまで、多様なストレージ メカニズムを利用できます。また、Windows Azure の ID 管理システムでは、メッセージング機能やクラウド/オンプレミスのハイブリッドの接続機能をセキュリティ保護します。
作業の開始
ここからは、アーキテクチャと実装を次の 4 つの部分に分けて説明します。
- Windows Azure ポータルを使用したアカウントのプロビジョニング
- Windows Azure クラウド プロジェクトの作成と、RESTful Web サービスを定義するコードの記述
- Windows Azure ポータルを使用したクラウド プロジェクトのアカウントへの配置
- Windows Phone、Android、および iOS (iPhone/iPad) 用のモバイル アプリケーションのビルド
では、これらの手順を見ていきましょう。最初の部分は、Windows Azure ポータルで実行します。サブスクリプションが有効であれば、windows.azure.com (英語) でアクセスできます (詳細については、azure.com を参照してください)。
第 1 部: Windows Azure ポータルでの Web サービスのプロビジョニング
Windows Azure ポータルの重要な 2 つのオプションは、新規ホステッド サービスと新規ストレージ アカウントです。
図 3 は、"ホステッド サービス" のプロビジョニングのワークフローを示しています。このプロセスにより、RESTful Web サービスを配置するマイクロソフト データセンターのエンドポイントを表す URL を取得します。Windows Phone、Android、および iOS アプリケーションの開発者は、サービスとの通信にこの URL が必要になります。
図 3 Windows Azure RESTful Web サービスのプロビジョニング
この処理をすべて完了するためのワークフローは簡単です。
- Windows Azure ポータルにログインします。
- [新規ホステッド サービス] をクリックします。アカウント名、URL、および地域 (データセンターの場所) を指定します。
- Windows Azure ポータルによって生成される URL を保存します。この URL は、RESTful Web サービスとモバイル クライアントをビルドするときに、アカウント名と共に使用します。アカウント名は第 3 部でも使用します。
注: 今回の例では、"fastmotorcycleservice" というアカウント名と "http://fastmotorcycleservice.cloudapp.net" という URL を使用しています。
次に、Windows Azure ポータルでストレージ アカウントを作成します。図 4 は、このプロセスと Windows Azure テーブルの名前と場所を示しています。6 つのデータセンターから選択できます。コストを抑え、パフォーマンスを向上するため、同じデータセンターで Web サービスとデータの両方をホストするのが賢明です。
図 4 Windows Azure ストレージ アカウントのプロビジョニング
このワークフローは、前に説明した "ホステッド サービス" のものと似ています。
- Windows Azure ポータルにログインします。
- 新しいストレージ アカウントを作成し、アカウント名と地域を指定します。
- Windows Azure ポータルによって生成および指定されるアクセス キーとアカウント名を保存します。これらは、RESTful Web サービスをビルドするときに必要になります。
以上で第 1 部は完了です。これで、RESTful Web サービスや、Windows Phone、Android、および iOS アプリケーションを作成するときに必要な Windows Azure ポータル情報を使用できるようになります。
第 2 部: Windows Azure でホストする RESTful Web サービスのビルド
Visual Studio で RESTful Web サービスをビルドするのは簡単です。[スタート] ボタンをクリックし、[すべてのプログラム]、[Microsoft Visual Studio 2010] の順にポイントします。[Microsoft Visual Studio 2010] を右クリックして [管理者として実行] をクリックし、Visual Studio を管理者として開きます。[ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。
[新しいプロジェクト] ダイアログ ボックスの [インストールされたテンプレート] の一覧で使用する言語を展開し、[Cloud] をクリックします。[Windows Azure プロジェクト] テンプレートをクリックし、プロジェクトの名前を「FastMotorcycleProject」に設定して、場所を適宜指定します。
この詳細手順については、bit.ly/VideoAzureRestfulService (英語) のビデオを参照してください。
ソリューション エクスプローラーは図 5 のようになります。
図 5 新しい Windows Azure プロジェクトの作成
図 6 は、ここでは説明しない基本手順をいくつかまとめたものです (参照用のビデオでは説明されています)。
図 6 今回説明しない基本手順
ビデオで対応される処理 | 説明 |
ASP.NET Web ロールを追加する | RESTful Web サービスをホストするために使用します |
DataConnectionString を追加する | アカウント名とアクセス キーが含まれます |
データを初期化するための基本的なスタートアップ コードをいくつか追加する | DataConnectionString を読み取るため global.asax.cs にコードを追加します |
これらの手順は、ほぼすべての Windows Azure プロジェクトに共通です。たとえば、Web ロールを使用して RESTful Web サービスをホストするのは標準の手法です。上記で Windows Azure ポータルで定義したストレージ アカウントにアクセスするには、DataConnectionString が必要です。ストレージ アカウントに使用するアカウント名とアクセス キーを構成ファイルから読み取るには、Visual Studio プロジェクト内にスタートアップ コードを含める必要があります。
準備段階が完了したら、Visual Studio の WCF サービス テンプレートを使用して、RESTful Web サービスを追加できます。
WCF サービスを追加するには、FastMotorcycleProject_WebRole フォルダーを右クリックし、[追加] をポイントして、[新しい項目] をクリックし、表示されたダイアログ ボックスでクラスの名前を「FastMotorcycleService」にします。
FastMotorcycleService.svc.cs が生成されます。このクラスのコード全体を、図 7 のコードに置き換えます。
この処理のポイントは、各種 URI と動詞を RESTful メソッドにマップする方法を通知することです。そのため、図 7 のコードには、WebGet 属性および WebInvoke 属性を追加する必要があります。
図 7 FastMotorcycleListService.svc.cs
[ServiceContract]
public class FastMotorcycleListService
{
private FastMotorcycleListDataProvider _data;
public FastMotorcycleListService()
{
_data = new FastMotorcycleListDataProvider();
}
[OperationContract]
[WebGet(UriTemplate = "/list/{owner}", ResponseFormat =
WebMessageFormat.Json)]
public List<string> GetItems(string owner)
{
return _data.GetItems(owner);
}
[OperationContract]
[WebInvoke(UriTemplate = "/list/{owner}", Method = "POST",
RequestFormat = WebMessageFormat.Json)]
public void AddItem(string owner, string item)
{
_data.AddItem(owner, item);
}
[OperationContract]
[WebInvoke(UriTemplate = "/list/{owner}/{item}", Method = "DELETE")]
public void DeleteItem(string owner, string item)
{
_data.DeleteItem(owner, item);
}
}
これらの属性は、メソッドが HTTP GET 要求に応答する必要があることをフレームワークに通知します。WebInvoke 属性は、既定で HTTP POST にマップされます。既定では、URI は、エンドポイントのベース URI にメソッド名が付加されることによって決まります。一部の専門家や REST を純粋に信奉する開発者からは、このメソッド名を動詞ではなく名詞にすべきだと主張する意見もあります。
図 8 に示す WCF の REST プログラミング モデルは、WebInvoke 属性および WebGet 属性の UriTemplate プロパティで設定可能なテンプレートを使用して、各メソッドの URI をカスタマイズできるようにします。このモデルについて次の一覧で説明します。一覧の番号は、それぞれ図 8 の番号と対応しています。
図 8 RESTful データを要求するモバイル アプリケーションのワークフロー
- モバイル アプリケーションは標準 HTTP を使用してメッセージ要求を送信します。これには、HTTP 動詞と URL を含めます。
- RESTful Web サービスが、モバイル アプリケーションのメッセージ要求 (データの要求) をインターセプトします。GetItems メソッドを呼び出し "Bruno" をパラメーターとして渡します。GetItems メソッドは、LINQ クエリを使用してデータを照会します。このとき、"Bruno" を where 句の一部として使用します。
- PartitionKey が "Bruno" に一致するレコードだけが、Windows Azure テーブル サービスから返されます。
- このデータは JSON 形式に自動変換され、モバイル デバイスに返されます。
- このデータをモバイル アプリケーションで使用可能にします。このデータは ListBox に設定したり、モバイル アプリケーション ユーザーに表示したりします。
続いて説明する 3 つのクラスはヘルパー オブジェクトで、Windows Azure テーブル サービスとやり取りするために必要です。FastMotorcycleListDataProvider、FastMotorcycleListItem、および FastMotorcycleList は、図 9 のコードからストレージや Windows Azure テーブル固有の API の詳細を抽象化するクラスです。これにより、アプリケーションが Windows Azure テーブル サービスで作成、読み取り、更新、および削除 (CRUD) 操作を実行できるようになります。
Visual Studio で、FastMotorcycleListDataProvider.cs という新しいクラス モジュールを追加し、そのコードを図 9 のコードに置き換えます。
図 9 FastMotorcycleListDataProvider クラス、FastMotorcycleListItem クラス、および FastMotorcycleList クラス
public class FastMotorcycleListDataProvider
{
private FastMotorcycleList _list;
public FastMotorcycleListDataProvider()
{
string configValue = RoleEnvironment.GetConfigurationSettingValue(
"DataConnectionString");
var account = CloudStorageAccount.Parse(configValue);
_list = new FastMotorcycleList(account.TableEndpoint.ToString(),
account.Credentials);
}
public List<string> GetItems(string owner)
{
var results = from entity in _list.Items
where entity.PartitionKey == owner
select entity;
var list = new List<string>();
foreach (var item in results)
{
list.Add(item.RowKey);
}
return list;
}
public void AddItem(string owner, string item)
{
_list.AddObject("FastBikes", new FastMotorcycleListItem(owner, item));
_list.SaveChanges();
}
public void DeleteItem(string owner, string item)
{
var entity = (from i in _list.Items
where i.PartitionKey == owner
&& i.RowKey == item
select i).Single();
_list.DeleteObject(entity);
_list.SaveChanges();
}
}
public class FastMotorcycleListItem : TableServiceEntity
{
public FastMotorcycleListItem()
{
}
public FastMotorcycleListItem(string partitionKey, string rowKey)
: base(partitionKey, rowKey)
{
}
}
public class FastMotorcycleList : TableServiceContext
{
public FastMotorcycleList(string baseAddress,
StorageCredentials storageCredentials)
: base(baseAddress, storageCredentials)
{
}
public DataServiceQuery<FastMotorcycleListItem> Items
{
get
{
return this.CreateQuery<FastMotorcycleListItem>("FastBikes");
}
}
}
第 3 部: RESTful Web サービスの配置
これは Windows Azure が本領を発揮する分野の 1 つです。RESTful Web サービス インスタンスを 100 個配置するのも、1 つだけ配置するのも同じくらい簡単です。次の手順を参照してください。
- Visual Studio で、FastMotorcycleProject を右クリックし、[パッケージ] をクリックします。
- ポータルのブラウザーに戻り、[ホステッド サービス、ストレージ アカウント、CDN] をクリックします。
- 上部のウィンドウで、[ホステッド サービス] をクリックします。
- 中央のウィンドウで、前に作成したホステッド サービスを選択します。
- 右クリックして、[新規運用環境のデプロイ] をクリックし、FastMotorcycleProject.cspkg および ServiceConfiguration.Cloud.cscfg をアップロードします (これらは最初の段階で生成されたファイルです)。
第 4 部: モバイル アプリケーションからの RESTful Web サービスの使用
ここでは、さまざまなモバイル アプリケーションで RESTful Web サービスを使用する方法について説明します。ここでは、これまでのアプローチによって実現される相互運用性に注目します。
JSONKit (github.com/johnezang/JSONKit、英語) を使用すると、iOS デバイスで RESTful Web サービスを簡単に操作できます。コードを数行追加すると、RESTful Web サービスを呼び出し、JSON 形式のデータをダウンロードして使用可能な形式に変換し、変換したデータを iPhone アプリケーションや iPad アプリケーションで使用されるテーブル ビュー コントロールにアタッチできます (図 10 参照)。
図 10 JSON データを解析する Objective-C コード
NSString *username = @"Bruno"; // Gets passed to the RESTful Web Service
NSString *serviceUri = "http://your_hosted_service_name.cloudapp.net/"+
"FastMotorcycleListService.svc/list/";
// Build the service URI (will point to our RESTful Web service
NSString *url = [NSString stringWithFormat:@"%@%@", serviceUri, username];
// Retrieve the data in the form of a JSON array
NSData *json = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
// Convert from JSON array to NSArray
// This allows us to populate the table view more easily
NSArray *itemArray = [json objectFromJSONData];
// Assign the array to the TableView
// fastbikes is the name of our TableView control
self.fastbikes = [[NSMutableArray alloc] initWithArray:itemArray];
Android の開発では Java プログラミング言語を使用します。これは昔から利用されてきた言語で、JSON データをネイティブに解析できます。図 11 に例を示します。Windows Phone SDK では、RESTful Web サービスの呼び出しと JSON 形式のデータの処理をネイティブにサポートしています。この SDK を使用すると、DataContractJsonSerializer で JSON データを簡単に処理できます。図 12 に例を示します。最後に、Android および iOS 用のより堅牢な開発ツールキットをお探しの場合は、マイクロソフトで認定されているこのリンク (github.com/microsoft-dpe、英語) を参照してください。
図 11 JSON データを解析する Android コード
// HttpClient used to talk to Web service
HttpClient httpclient = new DefaultHttpClient();
String url =
"http://your_hosted_service_name.cloudapp.net/"+
"FastMotorcycleListService.svc/list/Bruno";
// This will be the array we need to convert
// We get the data from the Web service
JSONArray listItems = null;
String jason = null;
// Set up the RESTful call to 'GET' the data
HttpGet request_http_get = new HttpGet(url);
// Read the JSON data and assign it to ListView
try
{
// Fill a response object using a request
HttpResponse response_http_get = httpclient.execute(request_http_get);
// Length represents the number of data items returned
// by RESTful Web service
long length = response_http_get.getEntity().getContentLength();
// "entity" ends up being the data coming back from Web server
HttpEntity entity = response_http_get.getEntity();
// Read the bytes, one byte at a time
InputStream stream = entity.getContent();
// Allocate a series of bytes
byte[] buffer = new byte[(int) length];
// Read bytes from RESTful Web service
// After this loop, we end up with something like ->
// ["busa","gxr1000","ninja250"]
for (int i = 0; i < length; i++)
{
buffer[i] = (byte) stream.read();
}
// Create an array of strings
jason = new String(buffer);
// Convert to JSON array for Android ListBox
// listItems ends up being a three-element JSON array (see "busa")
listItems = new JSONArray(jason);
}
catch (Exception e)
{
System.out.println(e);
}
図 12 JSON データを解析する C# コード
private void LoadList()
{
string uri =
@"http://your_hosted_service_name.cloudapp.net/"+
"FastMotorcycleListService.svc/list/Bruno";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "GET";
try
{
webRequest.BeginGetResponse(new AsyncCallback((result) =>
{
var webResponse =
(HttpWebResponse)webRequest.EndGetResponse(result);
if (webResponse.StatusCode == HttpStatusCode.OK)
{
var jsonDeserializer =
new DataContractJsonSerializer(typeof(List<string>));
List<string> items =
(List<string>)jsonDeserializer.ReadObject(
webResponse.GetResponseStream());
shoppingListBox.Dispatcher.BeginInvoke(new Action(() =>
{
shoppingListBox.Items.Clear();
foreach (var item in items)
{
shoppingListBox.Items.Add(item);
}
}));
}
}), null);
}
catch
{
// Ignored
}
}
あらゆるデバイスにアクセスする
Windows Azure でホストされている RESTful Web サービスは HTTP に基づくため、このプロトコルをサポートしているクライアント アプリケーションであれば、この RESTful Web サービスと通信できます。大多数のデバイスがこのカテゴリに分類されるため、これは開発者にとってのデバイスの可能性を広げます。今回はモバイル プラットフォームについて触れましたが、jQuery などの JavaScript 実装でも RESTful Web サービスを使用できます。UI の多様性の観点から見ると、モバイル プラットフォームで使用するパスに関係なく、常に、簡潔で開かれた HTTP ベース Web サービスのアーキテクチャ上にビルドするようにします。
Bruno Terkaly は、マイクロソフトの開発者エバンジェリストとして活躍しています。彼の深い知識は、多数のプラットフォーム、言語、フレームワーク、SDK、ライブラリ、および API を使用してコードを作成し、現場で長年の経験を積むことで得られたものです。コードの作成、ブログ、クラウド ベースのアプリケーション構築 (特に、Windows Azure プラットフォームの使用) に関するライブ プレゼンテーションに携わっています。
Ricardo Villalobos は、経験豊かなソフトウェア アーキテクトとして、サプライ チェーン管理業界の企業用アプリケーションを 15 年以上にわたって設計および作成しています。さまざまなマイクロソフト認定資格の保持者であり、ダラス大学のサプライ チェーン管理の MBA を取得しています。彼は 2010 年にマイクロソフトに入社し、Windows Azure アーキテクト エバンジェリストとして活躍しています。
この記事のレビューに協力してくれた技術スタッフの Reza Alizadeh と Wade Wegner に心より感謝いたします。