この連載では数ヶ月前に、Amazon が Java アプリケーション開発用に提供している Elastic Beanstalk という PaaS (Platform-as-a-Service) を実際に使用しながら紹介しました。その記事で示したように、極めて柔軟な Beanstalk は、処理を行う上でほとんどあらゆるツールを組み合わせて使用することができます。そのため、Play を使用して迅速な開発を行うとともに、MongoHQ という別の PaaS で MongoDB インスタンスを管理することができました。この 2 つの PaaS インフラストラクチャーを組み合わせると、アプリケーションの保守のほとんどを行なってくれるため、素晴らしいクラウド用モバイル・アプリケーションの構築に専念できるというわけです。
MongoHQ PaaS は前述のプロジェクトでは極めて有効に機能しましたが、データを従来の RDBMS に保管するとしたら、どうでしょうか。結局のところ、ほとんどの Java 開発者はリレーショナル・データベースのコードを作成するほうが楽に感じるものです。また、多くの NoSQL データストアでは必然的に ACID を諦めることになりますが、すべてのプロジェクトにその余裕があるわけではありません。
今月は、Amazon Web Services ファミリーに加わった素晴らしい多用途のサービス、Amazon Relational Database Service (RDS) の導入方法を説明します。Amazon RDS を使用するのは、MongoHQ でホストされた MongoDB インスタンスを実行するのと同じくらいに簡単です。そのリレーショナル性を管理するのはまったく難しいことではありませんが、スケーリングに関してはいくつかの興味深い問題が出てくるはずです。けれども、前もってスキーマを定義しておけば、後は順調に進みます。
Amazon RDS (Relational Database Service) は、オンデマンドでスケーリング可能なクラウド・ベースの MySQL インスタンスを提供するアプリケーション開発用の PaaS です。RDS が単にクラウド内で稼動する MySQL のインスタンスでしかないのであれば、私はこの記事を書いてはいません。2009年に、MySQL を実行する Amazon EC2 イメージを利用する方法についての記事をすでに書いているからです (「参考文献」を参照)。
RDS に一見の価値を与えているのは、これが Amazon によって管理、運用されている PaaS であり、Elastic Beanstalk とほとんど同じサービスおよび柔軟性を提供するという点です。バックアップ、複製、さらにはパッチまでもが Amazon によって提供されます。しかも、RDS は完全にスケーラブルです。ほんの数回クリックするだけで、アプリケーションのストレージ容量を増やすことができます。Amazon では、アベイラビリティー・ゾーン間で RDS を複製するオプションも提供しています。つまり、アベイラビリティー・ゾーンが機能停止した場合や、ある時間帯にゾーンで保守作業が予定されている場合でも、引き続きデータを提供することができるということです。さらに、データベースの読み取り専用インスタンスをプロビジョニングして、大容量のアプリケーションまたはピーク期間の読み取り速度を向上させることもできます。
MySQL と連動するように作られているアプリケーションは、そのまますぐに RDS を利用できるので、データベースがクラウド内にある限り、アプリケーションを変更する必要はありません。また RDS では、AWS の他のサービスと同じように従量課金制モデルを採用しているため、RDS を利用すれば、ハードウェアやライセンスに先行投資することなく、使用した容量、ストレージ、そして帯域幅の分だけ料金を支払えばよいのです。
AWS では、コマンドラインまたは AWS 管理コンソールを使って各種のサービスをプロビジョニングできるようになっています。AWS 管理コンソールは、RDS のさまざまな側面について選択可能なオプションを示してくれることから、私はどちらかというと、コマンドラインよりもコンソールを使用しています。そこで、この手順では AWS 管理コンソールのコンソールで「RDS」タブを選択し、「Launch Instance (インスタンスの起動)」ボタンをクリックするところから作業を開始します。
画面には、MySQL データベース・インスタンスの詳細を設定するためのダイアログが表示されます。このダイアログで、例えばマシンのサイズ、MySQL のバージョン、データベースのインスタンスに割り当てるストレージの量などを指定することができます。注目する点として、AWS にはデータベースを複数のアベイラビリティー・ゾーンにデプロイするというオプションがあります。その場合には必然的にクラスターが作成されるため、ある特定のアベイラビリティー・ゾーンが機能停止したとしても、他のゾーンがそのゾーンを確実にカバーします。
図 1 に示されているように、インスタンスを設定するには、データベースのスキーマ名、管理ユーザー名、パスワードを指定する必要があります。
図 1. RDS インスタンスのセットアップ
「Continue (続ける)」をクリックすると、データベースの概要を構成する別のダイアログが表示されます。このダイアログでは、データベースの JDBC URL の一部として使用される名前を構成するだけでなく、MySQL がリッスンするポートを変更して、データベースを置くアベイラビリティー・ゾーンを選択することもできます (図 2 を参照)。
図 2. RDS インスタンスの構成
次に表示されるのは、AWS にデータをバックアップさせるための設定と、保守のスケジュールに関する設定ついての管理オプションです (図 3 を参照)。
図 3. RDS の管理オプション
「Continue (続ける)」をクリックして構成内容を確認した後、RDS インスタンスを起動します。インスタンスが起動するまでには数分かかることもあるので、今のうちに、コーヒーでひと息つくか、Twitter で最新の情報をチェックしてください。RDS がいったん起動すれば、後は素早く事が運びます。
インスタンスが起動された後、お好みの SQL 管理ツールでインスタンスにアクセスする前に、もう 1 つ行わなければならない作業があります。AWS を操作した経験があるとしたら意外なことではないはずですが、デフォルトではある程度ロックが掛かっているため、明示的にインスタンスへのアクセスを許可しなければなりません。
RDS のセキュリティー制約はかなり強力であり、RDS と通信するための IP、または IP の範囲を指定できるようになっています。しかし、この記事では簡単のため、どの IP でも私のインスタンスと通信できるようにしたいと思います。そのためには、RDS の「DB Security Group (DB セキュリティー・グループ)」ペインで、CIDR/IP 制約を編集して 0.0.0.0/0 にしてください。これは基本的に、すべての IP が許可されることを意味します。このステップを図 4 に示します。
図 4. RDS セキュリティーの設定
このステップを完了したら、RDS のインスタンスをリブートします (AWS Management Console のダッシュボードでインスタンスを右クリックすると、リブートするためのオプションが表示されます)。
実行中の RDS インスタンスを選択すると、「Description (説明)」ペイン (図 5 を参照) にいくつかの重要な詳細情報が表示されます。そのなかでも、今ここで最も関係してくる情報は、エンドポイントです。この URL を使用して、MySQL インスタンスに接続することになります。
図 5. RDS ダッシュボード
これで、お好みのデータベース管理ツール (または、お望みであればコマンドライン) を使用して、RDS インスタンスにアクセスできるようになりました。私がこれから使用するのは、ほとんどの GUI 指向のツールと同じくテーブルとデータを表示するための巧みなインターフェースを備え、さらにクエリー・コンソールを提供している Sequel Pro です。データベース・インスタンスに接続するためには、データベースのユーザー名、パスワード、そしてエンドポイント URL を知っている必要があります。
Amazon の Elastic Beanstalk を紹介した私の記事 (「参考文献」を参照)
を読んでいれば、その記事のために私が作成した Magnus というモバイル用クラウド・アプリケーションについてはご存知のことでしょう。Magnus
用のコレクションとして、私は MongoDB に Account と Location の 2 つを作成しました。Account という名前の1
つのコレクションを作成して、そこに、それぞれに Location 文書を埋め込んだ文書を含めることもできましたが、2 つのコレクションを使用することによって、このアプリケーションのシナリオで世界中のモバイル機器から送られてくるはずのアカウントの位置情報を永続化することができました。
Amazon RDS のデモンストレーション用にも同じ関係をモデル化しますが、今回は、昔ながらの方法でモデル化します。Magnus は、世界中にまたがる位置情報が頻繁に更新されるアプリケーションです。このようなアプリケーションの場合、特に RDS が多数のアベイラビリティー・ゾーンでクラスタリングできることを考えると、RDS に切り替えることにメリットがあるはずです。また、RDBMS の領域には、例えばデータを論理パーティションに分割するシャーディングなどの手法もあります。したがって、地理的位置を基準にアカウントおよび位置情報をシャーディングすることもできます。ただし、クラスタリング、複製、シャーディングにはいずれも利点と欠点があるので、個々のストラテジーに着手する前に、それぞれの利点および欠点を十分に考慮しておかなければなりません。
Magnus で SQL を使えるようにするには、まず初めに 2 つのリレーショナル・テーブルを定義する必要があります。これらのテーブルには、(ご想像のとおり) それぞれ
account、location という名前を付けます。リスト 1 に、account テーブルの定義を示します。
リスト 1. account テーブル
CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) |
リスト 2 に記載する location テーブルには、account テーブルへの外部キーを指定します。このようにすることで、account テーブルとその各種 location テーブルとの間に 1 対多の関係をセットアップします。
リスト 2. location テーブル
CREATE TABLE `location` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account_id` int(11) DEFAULT NULL, `latitude` double DEFAULT NULL, `longitude` double DEFAULT NULL, `date_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `name` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`), KEY `account_id` (`account_id`), FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ) |
テーブルを定義した後は、これらのテーブルを RDS インスタンス内に作成します。RDS インスタンス内にテーブルを作成する方法は、ローカル・マシンで実行中の MySQL インスタンスにテーブルを作成する場合と同じです。単純に、ターミナル・ウィンドウを開くか、お好みの GUI で RDS エンドポイントを指定するかして、テーブルを作成してください。これは極めて簡単な作業です。
Play Web アプリケーション・フレームワーク (「参考文献」を参照) は、Amazon RDS でも、Elastic
Beanstalk での場合と同じように機能するため、今回もこのフレームワークを使用してアプリケーションを開発します。Play
では各種のデータストアをごく簡単に切り替えることができます。しかも、このフレームワークには最初から JPA サポートが組み込まれています。MongoHQ 実装から Amazon RDS を使用する実装に切り替えるには、モデルに多少の変更を加えるだけの話です。まず、Play には JPA サポートが組み込まれているため、Magnus の application.conf ファイルを変更して、代わりに RDS インスタンスを参照させるようにします (リスト 3 を参照)。
リスト 3. location テーブル
db.url=jdbc:mysql://magnus.cp3pl5vineyp.us-east-1.rds.amazonaws.com/magnus_locations db.driver=com.mysql.jdbc.Driver db.user=admin db.pass=g3tf0kl |
上記のリストに何も特別な処理はありません。リスト 3 は 100 パーセント JDBC です!
あらゆる RDBMS ORM ライブラリーと同様に、これから最上位レベルの Java オブジェクトを使って、テーブルを 1 対 1
の関係でモデル化します。このアプリケーションで最上位レベルの Java オブジェクトに該当するのは、1 つの Account 型と 1 つの Location 型です。Location は Account に関係づけられることになります。
Play の Model 型を継承すると、いくつかのおまけが付いてきます。その 1 つは、ファインダー風のメソッドと、save および delete という標準的な CRUD メソッドを手に入れられることです。
Account クラスは 2 つの JPA アノテーションを使用します。そのうちの 1 つ、Table アノテーション
(リスト 4 を参照) には、名前を (小文字に) 変更した account テーブルを指定する必要があります。
リスト 4. Account 型
package models;
import play.db.jpa.Model;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "account") //required otherwise table is Account
public class Account extends Model {
public String name;
}
|
リスト 5 に示す Location POJO は、多少複雑です。このオブジェクトにはさらに 2
つのアノテーションを追加して、Location と Account との間に多対 1 の関係を作成しなければなりません。
リスト 5. JPA で定義された Location クラス
package models;
import play.db.jpa.Model;
import javax.persistence.*;
import java.math.BigDecimal;
import java.sql.Timestamp;
@Entity
@Table(name = "location")
public class Location extends Model {
public BigDecimal latitude;
public BigDecimal longitude;
public String name;
@Column(name = "date_time")
public Timestamp timestamp;
@ManyToOne
@JoinColumn(name="account_id", nullable = false)
public Account account;
}
|
最後に、リスト 6 に示すように Application コントローラーの saveLocation メソッドを更新します (前の Magnus 実装では、/location/ に対するすべての HTTP
PUT をこのメソッドにルーティングしたことを思い出してください)。saveLocation は単に、新しい Location オブジェクトを作成し
(したがって、それに対応するレコードも作成します)、この Location インスタンスを既存の Account に関連付けるだけに過ぎません。この関連付けをするには、先ほど Play の Model オブジェクトを継承したので、重宝な findById メソッドを使用することもできます。
リスト 6. RDS での位置を基準とした更新
public static void saveLocation(String id, JsonObject body) throws Exception {
String eventname = body.getAsJsonPrimitive("name").getAsString();
double latitude = body.getAsJsonPrimitive("latitude").getAsDouble();
double longitude = body.getAsJsonPrimitive("longitude").getAsDouble();
Location loc = new Location();
loc.longitude = new BigDecimal(longitude);
loc.latitude = new BigDecimal(latitude);
loc.name = eventname;
loc.account = Account.findById(new Long(id));
loc.save();
renderJSON(getSuccessMessage());
}
|
更新後の位置情報サービスが機能するかどうかをテストするには、RESTClient を使用することができます。このテストでは、以前 Magnus で行ったように、いくつかの JSON 文書を作成して送信します。
図 6. RESTClient を使ったテスト
メソッドが新しい Location レコードを正常に永続化すると、成功を意味する JSON
レスポンスが送り返されてきます。私が使っている便利で素晴らしい GUI では RDBMS 内のデータを表示できるので、location テーブルを確認してみます。すると、どうなっているかわかりますか? RDS によって新しい Magnus レコードがクラウドに保管されています!
図 7. これがクラウドに保管された Magnus レコードです!
PaaS は、Web アプリケーションの迅速な開発およびデプロイを目指すソフトウェア開発チームの良き友です。この記事では、リレーショナル・データベース (この記事では MySQL を使いましたが、RDS は Oracle Database もサポートします) をクラウドに配置する PaaS ソリューション、Amazon RDS を紹介しました。Amazon RDS はプロビジョニングするのが極めて簡単で、おそらく皆さんがこれまで長年にわたって構築してきた各種の RDBMS システムとまったく同じように機能します。重要な違いは、Amazon が保守を引き受けてくれることです。
学ぶために
- 連載「Java
開発 2.0」: この dW の連載では Java 開発の様相を塗り替える技術を詳しく探っています。これまで、Amazon
Elastic Beanstalk (2011年2月)、MongoDB
(2010年9月)、Amazon
EC2 (2009年10月)、NoSQL
(2010年5月)、Hibernate
Shards (2010年8月) などの話題を取り上げてきました。
- ナレッジ・パス「Using NoSQL and
analyzing big data」(developerWorks、2011年5月): NoSQL、ビッグ・データ、そしてデータ・マイニングについて学ぶための dW リソースが揃っています。
- ナレッジ・パス「Cloud
computing: Fundamentals」(2011年3月): クラウド・コンピューティングの概念、および IaaS、PaaS、SaaS という 3 つのサービス・モデルについて解説しています。
- Java Technology
bookstore で、この記事で取り上げた技術やその他の技術に関する本を探してください。
- developerWorks Java technology ゾーン: Java プログラミングのあらゆる側面を網羅した記事が豊富に用意されています。
製品や技術を入手するために
- Amazon Relational Database Service: Amazon Web Services ファミリーに含まれるこの Java Web サービスは、リレーショナル・データベースをクラウドでスケーリングします。
- Play フレームワーク: Web 開発者によって構築された Java フレームワークを自称する Play は、開発者の生産性に重点を置き、RESTful なアーキテクチャーをターゲットとしています。
- IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox
のオンライン試用版で、DB2、Lotus、Rational、Tivoli、および WebSphere などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。
議論するために
- developerWorks
コミュニティーに参加してください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。

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