MongoDBでゆるふわDB体験

第2回MongoDB 2.2の新機能

今回は、MongoDB v2.2リリースノートをもとにv2.2で追加/改善された機能を紹介します。機能についてより詳しく知りたい方は第3回丸の内勉強会の資料を参照ください。コマンドレベルでの手順や、一部機能の検証が載っています。

新機能ダイジェスト

1.並列処理の強化(Concurrency Improvements)
  • ロックの粒度がGlobalロックからDBロックになりました。
  • PageFaultアーキテクチャが改善されロック時間が減りました。
2.Aggregation Framework
集計処理がコマンドで可能になりました。
3.Replica SetsのReadノード選択
一貫性レベルに応じて、どのノードからデータをReadするかを選択可能になりました。
4.Tagを使用したSharding(Improved Data Center Awareness)
データ保存先のShardをTagで指定可能になりました。
5.TTL(Time To Live)Collections
一定時間で削除されるCollectionを定義可能になりました。
6.その他の変更点
今回は省略します。第3回丸の内勉強会の資料を参照ください。

並列処理の強化(Concurrency Improvements)

並列処理の強化のために2つの大きな改善が入りました。ロックレベルに関するものとPage Faultに関するものです。どちらも利用者が意識することなく利用できる機能です。

ロックレベル

ロックの粒度がv2.0までのGlobalロック(Mongodインスタンス全体のロック)からDBレベルロックとなり、並列処理がより効率よく行えるようになりました。複数のDBで運用しているシステムには恩恵がありますが、それほど対象ユーザは多くはないかもしれません。

次のステップであるCollectionレベルロックでは多くのユーザに恩恵があると思われますが、実装は次バージョン以降となります。JIRAにチケット登録されており、2012年11月末現在でFix Version/s: Planning Bucket Aとなっており実装バージョンは未定となってます。

図1 ロックレベル
図1 ロックレベル

Page Faultアーキテクチャ

MongoDBはメモリキャッシュ機能を持っています。高速なReadを実現するためにpageと言う単位でデータをメモリに保持しています。メモリ内に無いデータはディスクからロードすることになりますが、このイベントをPage Faultと呼びます。Page FaultはメモリからReadする場合と比較して時間がかかってしまいます。

v2.2ではロック中にPage Faultが発生してロックが長引くことを避けるための仕組みが追加されました。更新系の処理が多いシステムではこの改善によってスループットが向上する可能性があります。

図2 Page Faultアーキテクチャ
図2 Page Faultアーキテクチャ

Aggregation Framework

Aggregation Frameworkは、データに対して集計処理を行うコマンド集です。v2.0系まではユーザがMap/Reduceでの実装が必要だった処理のうち、よく使うものをコマンドとして使えるようになりました。SQLでいうGROUP BY句に似た機能を提供します。コマンドは$から始まるオペレータと呼ばれ、パイプラインとして処理を組み合わせることが可能です。

たとえば、以下のSQL句をAggregation Frameworkで実現すると、図3のようになります。

SQL
SELECT name as '_id', AVG(score) as 'average' FROM scores
WHERE year = 'junior'
GROUP BY = name
Aggregation Framework
db.scores.aggregate(
  { $match   : { "year" : "junior" } },
  { $project : { "name" : 1, "score" : 1 } },
  { $group   : { "_id"  : "$name",
                 "average" : { "$avg" : "$score" } } }
);
図3 Aggregation Frameworkのパイプライン処理
図3 Aggregation Frameworkのパイプライン処理

パイプラインに組み合わせることができるオペレータは以下のものがあります。

オペレータ名 処理
$match 条件で絞り込みを実施(SQLのWHERE句)
$project 集計処理を行うフィールドの選択/除外、リネーム(SQLのAS句⁠⁠、計算結果のInsertを実施
$unwind 指定された配列の展開を実施
$group $sum, $avgなどを使い集計処理を実施
$sort 指定されたsortキーによるソートを実施
$skip 指定された数字分スキップして次の処理へ渡す
$limit 指定された数字分の結果を次の処理へ渡す

Readノードの選択

システムで保証する一貫性のレベルに応じて、Replica Setsのノード群の中でどのノードからReadするかを選択可能となりました。一貫性レベルが強い順に以下の5段階が設定できます。システムにデータの強い一貫性が求められる場合はPRIMARYに、結果整合性[1]でも十分な場合にはそれ以外に設定してReadの性能と可用性を向上させることが可能となりました。

設定名 意味
PRIMARY PRIMARYノードのみからReadする
PRIMARY PREFERRED 可能であればPRIMARYノードからReadする
SECONDARY SECONDARYノードのみからReadする
SECONDARY PREFERRED 可能であればSECONDARYノードからReadする
NEAREST レイテンシの小さいノードからReadする※

Tagを利用したSharding

Shardingに参加しているノードにTagを追加しTagRangeを設定することで、指定したレンジのデータを任意のノードに格納することが可能になりました。この機能により、uid=1~100のデータは東京データセンターのノード、uid=101~200のデータはNew Yorkデータセンターのノード、というDR(ディザスタリカバリ)を考慮したデータ配置が可能となります。2.2の目玉機能のひとつで、前述のReadノードの設定と合わせて"Data Center Awareness"[2]と表現されています。

設定例
> sh.addShardTag("shard0000", "TokyoDC");
> sh.addTagRange("appdb.users", { "uid" : 1  }, { "uid" : 100  }, "TokyoDC");
図4 大陸間をまたがったHA構成の例
図4 大陸間をまたがったHA構成の例

TTL(Time To Live) Collections

一定時間が経過した後、データが削除されるTTL Collectionsが定義可能になりました。

起点とするフィールドに{"expireAfterSeconds":数値}というハッシュを第二引数に入れてensureIndex()でインデックスを作成することで、起点に入力されたdate-type型から計測して、先ほどexpireAfterSecondsのvalueとして入れた数値秒後にドキュメントデータが削除されます。

制限として、データサイズ上限が決められるCapped Collectionsでは使用できません。

TTL Collectionsの例
// eventsコレクションのデータを、created_atフィールドを起点に30秒後に
// 削除されるように設定
> db.events.ensureIndex( { “created_at”: 1 }, { expireAfterSeconds: 30 } )

// statusにはdate-type型を入れる。new Date()でOK
// statusがdata-type型以外、またはcreated_atが無いデータは消えない
> db.events.insert( { "myid" : 1, "created_at"    : new Date() } );
> db.events.insert( { "myid" : 2, "created_at"    : "String"   } );   
> db.events.insert( { "myid" : 3, "time_field"    : new Date() } ); 

> db.events.count();
// => 3

//30秒後
> db.events.count(); 
// => 2
> db.events.find({},{"_id":0})
{ "myid" : 2, "created_at" : "String" }
{ "myid" : 3, "time_field" : ISODate("2012-11-28T16:04:19.781Z") }
// "myid" : 1 のデータが消えている

次回のテーマ

今回はv2.2で追加/改善された主な機能を紹介しました。次回はMongoDBのクエリに関して説明します。

MongoDBと他のNoSQLを比較した場合の特徴のひとつとして、JOINを除くほぼすべてのSQLを再現できることが挙げられます。スムーズな理解につながるよう、SQLと比較しながらMongoDBのクエリを紹介していきます。

おすすめ記事

記事・ニュース一覧