スティルハウスの書庫の書庫

はてなダイアリーで書いてた「スティルハウスの書庫」を移転してきました。

Bigtableをお手軽に使える凄さ

(この記事は、日経BP社「ITpro」向けに書いたものを再掲しています)

GAE/Jのもうひとつの革新的な点は、「Googleインフラの圧倒的なスケーラビリティ・高信頼性をお手軽に利用できる」という点です。例えばGAE/Jでは、データを保存・検索する手段として一般的なRDBは利用できない代わりに、Google独自のデータストア「Bigtable」を利用します。

Bigtableについての詳細はここでは省略しますが、従来型のRDBとは異なる「key-value型」の巨大分散データストアであり、Googleの検索サービスの桁外れのスケーラビリティと可用性を実現している中核技術のひとつです。リレーショナルモデルではないため、例えばテーブル間の結合や全文検索といった(RDB感覚では)ごくあたりまえの機能も対応できないなど、いろいろと制限やクセがあり、あらゆる用途に適用可能なわけではありません。しかしそれと引き替えに、Google検索と同等のほぼ無限のスケーラビリティと高い可用性を手に入れることができます。実際、Googleの社員が個人で始めたSNSサービス「orkut」がブラジルを中心に全世界で急成長した際にも、同サービスがBigTable上に構築されていたため、当初のアーキテクチャをそのまま使い続けることができたと言われています。

Bigtableについては、以下の書籍に詳しいです。

GAE/Jでは、Java EE標準のJDO(Java Data Objects)APIに基づいてコードを記述することで、このBigtableに簡単にアクセスできます。例として、ご都合.comにおける「カレンダーの新規作成」のコード例を紹介しましょう。ユーザーが作成した個々のカレンダー情報は、GtgCalendarクラスというEntityクラスに保持されています。

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class GtgCalendar {

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
	private String key;

	@Persistent
	private String uid;

	@Persistent
	private String title;

	@Persistent
	private String comment;

...<以下、そのほかのフィールドやgetter/setterは省略>

このように、POJOクラスに「@Persistent」や「@PrimaryKey」といったアノテーションを記述することで、同クラスの内容をBigTableに保存可能になります。なお、BigTableでは事前にDBスキーマを定義しておく必要はなく、スキーマの変更も随時可能です。

このGtgCalendarに納められたカレンダー情報を保存するコードは、以下のように記述します(いずれもご都合.comで実際に動作しているコードです)。

		// GtgCalendar「gc」を保存
		PersistenceManager pm = pmf.getPersistenceManager();		
		try {
			pm.makePersistent(gc);
		} finally {
			pm.close();
		}

このように、GtgCalenderをPersistenceManagerのmakePersistenceメソッドの引数として渡すだけで、その内容がBigtableに格納されます。ちょうどHibernateRuby on RailsにおいてオブジェクトをDB保存する場合と同じ感覚で、ものの数行で記述できます。

一方、BigTableに保存されたデータを検索して取得するには、JDOで規定されたクエリ言語「JDOQL」を用いて、SQLライクなクエリを記述します。

		// クエリを作成
		PersistenceManager pm = pmf.getPersistenceManager();
		Query query = pm.newQuery(GtgCalendar.class);
		query.setFilter("token == tokenParam");
		query.declareParameters("String tokenParam");
		
		// クエリを実行
		List results; 
		GtgCalendar gc = null;
		try {
			results = (List)query.execute(token);
		} finally {
			query.closeAll();
			pm.close();
		}

ここでは、GtgCalendarのtokenフィールドをキーにして、同オブジェクトを検索しています。これもきわめて容易に記述できます。このように、JDOによるBigtableプログラミングはたいへん容易で、JDOとBigTableのいずれも初体験の筆者でも1日程度でやりたいことをひととおり実装できました。

もちろん、Bigtableの「クセ」はときにたいへんやっかいな問題となり、用途によってはまったく使えないケースも少なくないはずです。しかしBigtableで対応できる用途ならば、サービスの規模拡大にともなうスケーラビリティや可用性の心配はほぼなくなります。例えば、万が一に「ご都合.com」のようなプチWebサイトが全世界的な人気を獲得し、数1000万件のカレンダーを抱える巨大サイトに成長したとしても、現在のコードをあまり変更せずにサービス品質を維持できるはずです(負荷テストで検証したわけではありませんが……)。つまり、大規模Webサイトへの成長過程でこれまで避けられなかった「データベースのスケールアップ/スケールアウト」、「クラスタ構築による負荷分散と高可用性の実現」のための巨額の追加投資が一切不要となります。これは既存のデータベースベンダーやサーバベンダー、大手SIerにとってはもっとも“うまみ”の大きなエリアであり、彼らにとっては地殻変動レベルの脅威ではないでしょうか。