約 2 年前にこの連載を開始したとき、Java™ 開発 2.0 は主に 2 つの (非常に興味深い) 傾向による結果であると説明しました。その傾向とは、(1) 開発者がオープンソースのツールとフレームワークを利用してアプリケーションをまるごと構築するようになっていること、(2) アプリケーションのデプロイメントおよび実行を含め、あらゆるレベルでソフトウェア開発のライフサイクルを管理するために必要なアプリケーション・インフラストラクチャーを貸し出す (または借りる) ようになっていることです。
連載の最初の頃に、Java による Web 開発用のクラウド・プラットフォームとして Google App Engine と Amazon EC2 の 2 つを取り上げました (「参考文献」を参照)。この 2 つは、それぞれ独自の方法で Java 2.0 の可能性を具現化しています。GAE は PaaS (Platform as a Service) オファリングですが、EC2 は IaaS (Infrastructure as a Service) です。EC2 はいわば、オンデマンドの仮想環境であり、ここには好きなものを何でもインストールすることができます。GAE はそれよりも好みにうるさく、Python および Java による Web アプリケーション開発専用にセットアップされています。
EC2 に比べ、GAE はこれまでクラウド・ベースのアプリケーションをより短期間で簡単に開発するための手段となってきました。しかし、ここ数年の間、PaaS 市場の動きが非常に活発になっています。PaaS の概念が広く採用されるようになっているなか、そろそろ PaaS の人気が爆発する頃だと言っている人もいます (「参考文献」を参照)。そんな中、Amazon が近頃 Elastic Beanstalk という独自の PaaS を発表したのも当然と言えるでしょう。
GAE と Beanstalk は、どちらも Java アプリケーション開発用に調整されたクラウド・プラットフォームです。GAE と同じく、Beanstalk では一定の形を持たない極めてスケーラブルな環境 (Beanstalk の場合は EC2で駆動された環境) に、開発者が WAR ファイルをデプロイします。けれども GAE とは異なり、Beanstalk では開発者がアプリケーション環境をカスタマイズすることができます。この点が、ソフトウェア開発者にとって確かな魅力 (そして多くの場合は実用にかなった魅力) となっています。
例えば、Beanstalk では GAE とは違って、アプリケーションをホストするノードの数を自由自在に制御することができます。そのため、水平スケーリングを簡単かつ効率的に実施することができます。しかも、どの Java ライブラリーを使用することもできます。Java ライブラリーに関しても、GAE では選り好みが激しくなっています。汎用の PaaS タスクに関しては、Beanstalk はノード間のロード・バランシング、デプロイメント成果物のバージョン管理、さらにはリモート端末から EC2 インスタンスへの下位レベルでのアクセスも行えます。レポート作成機能が組み込まれているので、アプリケーション環境の正常性およびパフォーマンスは随時チェックすることができます。
GAE に勝る Beanstalk の利点は、根本的に異なるクラウド・ベースのサービス・モデルに根差しています。GAE は現在、厳格な PaaS であり、GAE を使用することにした場合、開発者が決めなければならないことはそれほどありません。これは、シナリオによっては良い結果となります。GAE で選択できるデータストアは 1 つ (Bigtable) だけで、Java ライブラリーの選択肢もわずかな数です。将来的には変わってくる可能性がありますが、現時点では、例えば Hibernate を使って Web アプリケーションを構築することはできません (「参考文献」を参照)。また、Web アプリケーションをいったんデプロイすると、アプリケーションの制御の自由がかなり限られてきます。実際、クラウドのスケーリングという点では一切制御することができません。基本的に GAE では、スケールアップを Google に一任することになるからです。この分野での Google の専門技術を考えれば、これはある意味当然と言えますが、開発者や企業によっては、アプリケーションをもっと制御できるようにする必要があります。しかもそれは、クラウド内での制御です。
データ機密性の保護措置が欠けていることも、一部の人々にとっては不満の種となります。GAE Web アプリケーションを構築するときには、データがどこに置かれるかは不明です。データに絶対的な重要性があるドメインや、データの機密性が最重要事項となるドメインでは、Bigtable の架空の抽象化に送信するだけでは安心とは言えず、問題がないとも言えません。場合によっては、まさにこの理由だけで GAE が選択肢から外されることさえあります。
Beanstalk の詳細を探るには、その機能のデモンストレーションをするための Web アプリケーションが必要です。そこで、これから Magnus という名前のアプリケーションを構築します。Magnus はモバイル機器から位置情報データを取得して、そのデータをデータストアに永続化するアプリケーションです。一度に何百万ものモバイル機器が接続することを前提に、Magnus はその人気の急増に応じて素早く簡単にスケーリングできるようにしなければなりません。そこで、水平スケーリングを使用して、アプリケーションのインスタンスが必要なときに、すべてのインスタンスを確実に使えるように Beanstalk を微調整します。
アプリケーションの構築はこの記事の論点ではないので、手早く片付けます。まず Java ベースの Play フレームワークを使って単純な REST エンドポイントを構築します。このエンドポイントに、モバイル機器の位置を示す地理的座標を記述した JSON 文書をモバイル機器自らが送信することになります。Play は自らのことを、「肥大化したエンタープライズ Java スタック」に置き換わるフル・スタックであると謳っています。このフレームワークを迅速にセットアップして稼働状態にするのは容易です。私は、そのシンプルなルーティング・システムも気に入っています。ステートレス・モデルを使用して、RESTful なアプリケーションを簡単に構築できるようになっている Play では、私独自の永続モデル (MongoDB を使用する永続モデル) を簡単に組み込むことができます。
このサンプル・アプリケーションでは、同じく PaaS のプロバイダーである MongoHQ がホストする MongoDB インスタンスに位置座標を保管します。したがって私が行う作業は、データストアを作成して、そのデータストアに HTTP を介して文書を追加するまでのところです。後の作業は、MongoHQ がすべて引き受けてくれます。
このサンプル・アプリケーションでは、アカウント管理用の Web インターフェースは省略します。実際のシナリオでは、エンド・ユーザーが Magnus サービスのアカウントを作成します。その場合、私はアカウントの位置情報を記述する JSON 文書に、追加のアカウント情報を組み込むことになると思います。しかし、サンプル・アプリケーションで位置情報をアカウントに関連付けるには、URL で十分です。
例えば、アカウント12345 に関連付けられた機器があり、現在その機器が、カナダのケベック州にあるとします。この場合、サンプル Web アプリケーションには、リスト 1 のような JSON 文書が送信されます。
リスト 1. 位置情報を記述する単純な JSON 文書
{
"name":"location payload",
"latitude":"46.49",
"longitude":"71.11",
"timestamp":"02-02-2011 14:43"
}
|
この文書は、HTTP PUT 呼び出しを使って以下の URL に送信されます。この URL は、アカウントの位置情報に対応します。
リスト 2. アカウントの位置情報に対応する RESTful な URI
http://some.web.address.com/location/12345 |
アカウントの位置情報は、リスト 2 に記載した URI にあるリソースです。つまり基本的には、HTTP PUT によってアカウント 12345 の位置情報をこのアドレスに更新していることになります。レスポンスは、リクエストを確認応答する JSON 文書です。
位置情報文書を作成するには、Morphia を使用することにします。これは、POJO (Plain Old Java Object) を MongoDB にマッピングする ORM 風のライブラリーです。リスト 3 に、POJO で作成した位置情報文書を記載します。
リスト 3. 位置情報文書の作成
@Entity(value = "locations", noClassnameStored = true)
public class Location {
@Id
private ObjectId id;
private String accountId;
private double latitude;
private double longitude;
private Date timestamp;
public Location(String accountId, Date timestamp, double lat, double lon) {
this.accountId = accountId;
this.timestamp = timestamp;
this.latitude = lat;
this.longitude = lon;
}
public void save() throws Exception {
Mongo mongo = new Mongo("gnome.mongohq.com", 34256);
Datastore datastore = new Morphia().createDatastore(mongo, "magnus",
"username", "password".toCharArray());
datastore.save(this);
}
}
|
MongoHQ への接続情報はハードコーディングしていることに注意してください。実際には接続情報をハードコーディングすることはしないはずですが、デモンストレーションをするのが目的であれば、これで問題ありません。
すべてを結び付けるのは、Play の単純なコントローラーおよびルート定義です。コントローラーは、JSON リクエストを受信するエンドポイントとして機能します。ルート定義は、リスト 4 に記載するとおりです。
リスト 4. Play のルート定義
PUT /location/{id} Application.saveLocation
|
上記の定義では、/location/{some id} のパターンと一致する URI への HTTP PUT
リクエストはすべて、Application クラスの saveLocation メソッドにルーティングするように規定しています。
saveLocation は、リスト 5 からわかるとおり、単純なメソッドです。
リスト 5. saveLocation メソッド
public static void saveLocation(String id, JsonObject body) throws Exception {
double latitude = body.getAsJsonPrimitive("latitude").getAsDouble();
double longitude = body.getAsJsonPrimitive("longitude").getAsDouble();
String when = body.getAsJsonPrimitive("timestamp").getAsString();
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm");
Date dt = formatter.parse(when);
new Location(id, dt, latitude, longitude).save();
renderText("success");
}
|
Play は、リクエストされた URL の末尾の ID (つまり、12345) と JSON 本体を渡します (そのためには JSON
バインディングを作成する必要がありました。これについては、Play Web サイトに説明が記載されています)。すると、このコードはすぐに、JSON 文書からデータ
(つまり、緯度、経度、時刻) を取得し、Location インスタンスを作成して保存します。コードの最後で指定しているのは、レスポンスです。今のところ、これは単なるテキスト・ストリングのレスポンスですが、後で変更して、新しいバージョンをデプロイします。このコードには含まれていませんが、実際のアプリケーションではエラー処理も必要であることに注意してください。
現時点で、サンプル・アプリケーションには 1 つの到達可能なエンドポイントがあります。このエンドポイントは、JSON
リクエストしか受け入れません。これに対処するには、いくつかのツールが必要になってきます。それとは別に、アプリケーションをデプロイした後にすべてが機能することを確認できるように、ブラウザーでアクセスできる通常のエンドポイントも用意したいと思います。そこで、Play
の Application クラスに index
メソッドを実装して (このメソッドは、ルート・パスにアクセスするとデフォルトで呼び出されます)、何らかのテキストがすぐに返されるようにします。具体的には、renderText("Magnus Web is live"); を Application クラスの indexメソッドに追加します。
最後のステップとして、Beanstalk をデプロイするために WAR ファイルを作成します。このファイルは基本的には、見せ掛けの Tomcat コンテナーです。Play
では、コマンド play war -o ../magnus --zip を実行するだけで、この Play のサンプル・アプリケーションが含まれる magnus.war というファイルが作成されます。
これによって、将来大きな成功を収めることになる、機密性を心配する必要のない私の位置情報収集アプリケーションがビルドされます。次のステップは、人々が自分の位置情報を継続的に提供することが賢明なことであると認識するようになった暁に必要となる、Beanstalk の大々的なスケーラビリティーがアプリケーションに備わっていることを確実にすることです。
皆さんが Beanstalk にサインアップしていることを前提として、まずは AWS Management Console (AWS 管理コンソール) にログインしてください。管理コンソールから「Elastic Beanstalk」タブを選択し、「Upload your own application (独自のアプリケーションをアップロードする)」オプションをクリックした後、「Launch Application (アプリケーションの起動)」ボタンをクリックします。すると、いくつかの情報を求めるダイアログが表示されます (図 1 を参照)。
図 1. 新規 Beanstalk アプリケーションの作成
このダイアログに、アプリケーションの名前を入力してください。入力した名前は、アプリケーションの URL としても使用されます。また、WAR ファイルも指定する必要があります。「Continue (続行)」ボタンをクリックすると、アプリケーションが起動する間、AWS 管理コンソールが再び表示されます。アプリケーションが起動するまでには、時間がかかる場合があります。私の経験では、最大 10 分かかったこともあります。
アプリケーションが完全にデプロイされて、Amazon側での構成がすべて完了すると、アプリケーション名の隣に緑色のボックスが表示されます。緑色の表示は、アプリケーションを実行する準備ができていることを意味します (図 2 を参照)。
図 2. Magnus の準備完了!
Amazon によって提供された URL、magnus.elasticbeanstalk.com をクリックすると、アプリケーションが実行中であることがわかります。図 3 に示されている内容は、「簡単なヘルス・チェック」のセクションで追加したコードによる結果であることに注意してください。
図 3. Magnus 実行中!
Beanstalk Management Console (Beanstalk 管理コンソール) 右下の「Environmental Details (環境の詳細)」セクションに表示された「Edit Configuration (構成の編集)」リンクをクリックすると、Beanstalk の実力が見えてきます。このリンクをクリックすると表示されるダイアログには、実に賢明な選択肢を含んだ豊富なオプションが揃っています。
図 4. 環境の構成内容の編集
Beanstalk は、アプリケーション・インスタンスのメモリーの量、I/O パフォーマンス、ローカル・ストレージなど、さまざまな上位レベルのデプロイメント・オプションを提供します。さらに、アプリケーションのロード・バランサーや自動スケーリングを構成することも可能です。後者は水平ノードを制御するオプションで、これを使って、実行させたいアプリケーションのインスタンス数、および各新規インスタンスのトリガー方法を決定します。
自動スケーリングは、アプリケーションのスケーラビリティーを開発者の手に直接委ねる、Beanstalk の並外れて強力な側面です。自動スケーリングに考えられる設定としては、例えば着信トラフィックなどの基準に応じて新規インスタンスを起動するように設定することができます。トラフィックが低下すれば、アプリケーションは元のスケールに戻ります。しかもこの過程はすべて、手動による介入なしで行われます。まさに、エラスティック・コンピューティングそのものです!
Magnus が Web 上で有効になったところで、サンプル・アカウントに位置情報を追加してアプリケーションをテストしてみましょう。ここでは間に合わせとして、ツールを使用して JSON 文書をエンドポイントに送信します。RESTClient は HTTP PUT を使用して JSON 文書をサンプル・アプリケーションに送信します。ここまでのところ、図 5 に示されているように万事順調に運んでいます。
図 5. RESTClient がレポートする着信ペイロード
最後のサニティー・チェックは、JSON 文書が MongoDB に永続化されているかどうかを調べることです。こう言うと、皆さんの記憶に蘇ってくると思いますが、MongoDB は MongoHQ で実行されています。
図 6. Magnus の位置情報文書を示す MongoHQ のインターフェース
エンドポイントのレスポンスは、アプリケーション開発の初期フェーズでは単純なものにしておきましたが、これからアプリケーションに少し変更を加え、再デプロイします。
Beanstalk は GAE と同じく、バージョン管理されたデプロイメントをサポートします。したがって、複数のバージョンをデプロイすることはできても、随時「有効」なのは 1 つのバージョンだけです。この機能により、例えばデプロイメントが失敗した場合にロールバックするなど、必要に応じて、あるバージョンから別のバージョンに容易に変更することができます。
Beanstalk コンソールの「Application Details (アプリケーションの詳細)」セクションの左上隅近くにある「Versions (バージョン)」タブをクリックしてください。この操作によって、サンプル・アプリケーションの最初のリリースが表示されるはずです。
図 7. Beanstalk によって表示されたアプリケーションのバージョン
これから私のローカル・マシンで、Application クラスの saveLocation メソッドを変更します。具体的には、メソッドの最後の行が renderJSON("{success}"); となるようにします。これによって、レスポンスが単純なテキスト・ストリングの代わりに、単純な JSON 文書を返すことになります。
「Upload New Version (新規バージョンのアップロード)」ボタンをクリックすると、お馴染みのダイアログが表示されます (図 8 を参照)。このダイアログで、WAR ファイルのバージョン・ラベルを入力します。
図 8. Magnus の再デプロイメント
図 8 に示されているように、私は WAR ファイルのアップロードだけを行い、デプロイメントはしないように指定しました。WAR ファイルがアップロードされていれば、後からいつでも「Versions (バージョン)」タブからファイルをデプロイできるからです。
図 9. Magnus の再デプロイメントと新規デフォルト・バージョンの作成
目的のバージョンの隣にあるチェック・ボックスをクリックすると、後は「Deploy Version (バージョンのデプロイ)」ボタンをクリックするだけで、そのバージョンを有効なバージョンにすることができます (図 9 を参照)。
Beanstalk を終了したいとしたら、もちろん、それも可能です。それには管理コンソールの右側にある「Actions (アクション)」ドロップダウン・ボックスから、「Terminate this Environment (環境の終了)」を選択します。この場合、バージョン管理された WAR ファイルを削除することも忘れないでください。これを忘れると、削除するまで S3 でのスペース使用料が請求されることになります。
図 10. Beanstalk の終了
豆の木を上ったり下りたりする (伸縮自在な Beanstalk)
Elastic Beanstalk は、開発者が Amazon の EC2 インフラストラクチャーに容易にアクセスする手段となります。しかも、私たちが GAE で受け入れるようになった制約を遥かに超えて、自由にインフラストラクチャーを構成できるようになっています。位置情報ベースのサンプル・モバイル・アプリケーションでデモンストレーションしたように、Play のような比較的新しい Java Web フレームワークでも問題なく使用できるだけでなく、MongoHQ.com で実行される MongoDB インスタンスを使って文書を永続化することもできます。
サンプル・アプリケーションでは、データベースや Tomcat のインスタンスを起動する必要も、さらにはポートが開いていることを確認する必要も一切ありませんでした。プロセスは単純で、時間もかかっていません。さらに嬉しいことに、このサンプル・アプリケーションはトラフィックが急増した場合、フロント・エンドのロード・バランサーによって 4 つのインスタンスにまで自動的にスケーリングします。しかも、このロード・バランサーを構成する必要はありませんでした。その一方、バージョン管理されたデプロイメントでの私の限られた経験によって明らかなように、なるべく自分で制御したいのであれば、そうすることもできます。使い始めにかかった合計コストは、これ以上抑えることは不可能な額でした。つまり、$0.00 です。
Amazon の Beanstalk は、新たに登場してきている PaaS の選択肢の 1 つに過ぎません。これらの選択肢によって、Java 2.0 の全体像はより豊かに、そしてより刺激的になっています。賢い革新的な企業がこの成長を続ける分野で新しいニッチ市場を開拓し始めているなか、急速な、しかも最小限のコストでのエンタープライズ環境への展開は、今後も続くはずです。
学ぶために
- 連載「Java
開発 2.0」: この developerWorks の連載では Java 開発の様相を塗り替える技術とツールを詳しく探っています。最近の記事では、Amazon
EC2 (2009年10月)、Google
App Engine (2009年8月)、MongoDB
(2010年9月)、Bigtable
(2010年5月) を話題に取り上げました。
- Java
technology zone technical podcast series: Andrew Glover
が管理するこの先進的なポッドキャストでは、尊敬する開発者たちから必要な情報を直接入手できます。シリーズ 1 で、CloudBees
に関する Sacha Labourey へのインタビュー (2010年12月)、Google
App Engine に関する Max Ross へのインタビュー (2010年11月)、MongoDB
に関する Eliot Horowitz へのインタビュー (2010年9月) を聴いてください。
- 「Salesforce
To Acquire Ruby PaaS Heroku」(John Waters 著、Application Development
Trends、2010年12月): 技術の傾向を注意深く見守る人々によると、2011年は PaaS への注目が非常に高くなっている年です。最近の SalesForce.com による 2 億ドルでの Heroku 買収が、このことを証明しています。
- 「Domain-model
persistence with Morphia and MongoDB」(John D'Emic 著、developerWorks、2010年1月):
Morphia を使って、MongoDB にマッピングされた Java ドメイン・モデルを維持、ロード、削除、クエリーする方法を学んでください。
- developerWorks Cloud computing:
クラウド・コンピューティングについて、技術や業界関係者をはじめ、その詳細を調べてください。
- Java Technology
bookstore で、この記事で取り上げた技術やその他の技術に関する本を探してください。
- developerWorks Java technology
ゾーン: Java プログラミングのあらゆる側面を網羅した記事が豊富に用意されています。
製品や技術を入手するために
- Amazon Elastic Beanstalk:
リファレンス・マニュアルを読んで、GAE に代わる Amazon の PaaS、Elastic Beanstalk にサインアップして早速使い始めてください。
- Play フレームワーク: Web 開発者によって構築された Java
フレームワークを自称する Play は、開発者の生産性に重点を置き、RESTful なアーキテクチャーをターゲットとしています。
- MongoDB: このとてつもなくスケーラブルなドキュメント指向のデータベースは、C++
で作成されていますが、JSON スタイルの文書を使用して保管することから Java に対応します。
- MongoHQ: MongoDB がホストする、クラウド内でのデータベース・ストレージです。
議論するために
- developerWorks
コミュニティーに参加してください。ここでは他の developerWorks
ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。

Andrew Glover は、ビヘイビア駆動開発、継続的インテグレーション、アジャイル・ソフトウェア開発に情熱を持つ開発者であるとともに、著者、講演者、起業家でもあります。また、easyb BDD (Behavior-Driven Development) フレームワークの創始者、そして『継続的インテグレーション入門 開発プロセスを自動化する47の作法』、『Groovy in Action』、『Java Testing Patterns』の 3 冊の本の共著者でもあります。詳細は彼のブログにアクセスするか、Twitter で彼をフォローしてください。