About MongoDB 3.2
MongoDB3.2の紹介
渡部 徹太郎2016/07/27
自己紹介
{"ID" :"fetaro"
"名前":"渡部 徹太郎"
"所属":"リクルートテクノロジーズ"
"研究":"東京工業大学でデータベースと情報検索の研究
(@日本データベース学会)"
"仕事":{前職:["証券会社のオントレシステムのWeb基盤",
"オープンソース部隊。主にMongoDB,NoSQL"],
現職:["リクルートの横断分析基盤
Exadata, Hortonworks, EMR"]}
"エディタ":"emacs派"
"趣味": ["自宅サーバ","麻雀"]
"属性" : ["ギーク","スーツ"]}
目次
• API
o ドキュメントバリデーション
o 部分的インデックス
o 新しいCRUD
o アグリゲーションフレームワークの改良
• 高可用構成
o プライマリ選出高速化
o 設定サーバ群がレプリカセットに
o Read Concern
• ストレージ
o デフォルトがWiredTigerに
• 運用
API
ドキュメントバリデーション
• ドキュメントの中身にバリデーション
(キー名や値のチェック)がかけられる
• 今まではスキーマレスを売りにしてきた
• でもやっぱり、場合によってはスキーマが重要
ドキュメントバリデーション
• nameというキーの値を文字列に、ageを30より大きい値に限定
• 正しいドキュメント
• 不正なドキュメント
> db.createCollection( "user" , {
validator : {
name : { $type : "string" },
age : { $gt : 30 }
}})
> db.user.insert({"name":"fetaro","age":33})
WriteResult({ "nInserted" : 1 })
> db.user.insert({"name":1,"age":1})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
メッセージは固定
どうやって失敗したか
わからない
ドキュメントバリデーション
• よく使うバリデーション
o findで検索するときの条件指定と同じ文法が使える
• 配列をバリデートする場合の注意
種類 説明 バリデーションの値
$exists キーが存在するか true,false
$type 値の型が正しいか "number","string" 等
$in 値が配列に含まれるか
想定するキーの値を含
む配列
$regex 値が正規表現とマッチするか 正規表現
> db.createCollection("user",{ validator:{ "hoge" :{$type : "array" }}})
> db.createCollection("user",{ validator:{ "hoge.0":{$exists : true}}})
✕
◯
部分的インデックス
• ドキュメントの中のある値の条件よって、
そのドキュメントをインデックスに含めるかどうかを分けれる
• 例
o Scoreにある80点以上ドキュメントだけをインデックスに含める
o db.scores.createIndex({"score":1},
{partialFilterExpression: {score:{$gt:80}}})
• 条件の指定
o キーの存在
o 値そのもの
o 値の存在
o 値の型
• 使いドコロ
o インデックスツリーそのものの大きさが減ることにより
 インデックスサイズの削減
 インデックス探索の高速化
新しいCRUD
• 今までのCRUD
o 一回のクエリで更新されるドキュメントの数が一つだったり複数だったり
o 例: db.mycol.update( {score:{$gt:75}}, {"pass": true})
 一つのドキュメントだけ更新される!
 ドキュメントが丸ごと置き換わる!
• 新しいCRUD
o 明確に更新するドキュメント数が分かるようになった
3.0までのAPI 3.2で追加になったAPI
insert() insertOne()
insertMany()
remove() deleteOne()
deleteMany()
update() replaceOne()
updateOne()
updateMany()
findAndModify() findOneAndDelete()
findOneAndReplace()
findOneAndUpdate()
アグリゲーションの改良(1)
• $lookup
o 他のコレクションから紐づくデータを結合できる。 LEFT OUTER JOINのようなもの
• ただしこの結合はRDBMSの結合とは大きく異なる
o RDBMSのJOIN
 結合計算の最適化、一貫したビュー
o MongoDBの結合
 内部的には結合先テーブルに対してクエリを発行しているだけ
 他のクエリから分離されたものではない。
 つまりアグリゲーションフレームの実行中に、結合先のテーブルが更新さ
れたら、その影響を受ける
• というか、MongoDBは本来分析用途ではない
db.user.aggregate([{
$lookup:{ from : "item", 結合先テーブル
localField : "item_id", 結合キー(自テーブル)
foreignField: "item_id", 結合キー(相手テーブル)
as : "item" 列名
}}])
アグリゲーションの改良(2)
• 3.0まで
o プライマリシャードに負
荷が集中
• 3.2から
o この動作が解消
o ただし、$outと$lookupは
依然としてプライマリ
シャードを使う
アグリゲーションの改良(3)
• インデックス内にデータがあればそれを使いドキュメ
ントにはアクセスしない
その他の改善
• 全文検索が英語以外に対応
o 追加された言語はアラビア語、ペルシャ語、ウルドゥー語、
中国語
o 日本語は残念ながら未対応
o 有償のEnterprise版のみで利用可能
• ビットをテストするオペレータの追加
• JavascriptのエンジンがまたSpidermonkeyに
o 2.4でSpidermonkeyからV8にしているので、戻った
• 地理空間インデックスの最適化
高可用構成
プライマリ選出高速化
• プロトコルのバージョンアップによりプライマリ選出が速くなっ
た
• 1.7秒以内になった(MongoDB World 2016での発表)
プライマリ
1 4 9
プライマリ
1 4 9
セカンダリ
1 4 9データ複製
アプリケーション
MongoDBドライバ
書き込み 読み込み読み込み
レプリカセット
設定サーバ群がレプリカセットに
• 今まで
o 設定サーバはmongod 1台 or 3台で2PC(2フェーズコミット)
o mongos --configdb <config1>,<config2>,<config3>
• 3.2から
o 設定サーバをレプリカセットで構築できるようになる
o mongos --configdb <replicasetName>/<config1>,<config2>
mongos
ルータ
設定
サーバ
mongod mongod mongod
設定
サーバ
設定
サーバ
mongos
ルータ
設定
サーバ
mongod mongod mongod
設定
サーバ
設定
サーバ
2PC
レプリケーション
• レプリカノードの過半数にデータが更新されるのを待って読む
• 一見シンプルな機能に見えるが、よく考えると恐ろしい機能
→大幅にシステムのスループットが落ちる可能性がある
• 何がうれしいのか?
o レプリカセットとして生き残ることが保証された(Rollbackしない)
データだけを読むことができる
o レプリカセットは壊れ方によってはデータロストが発生するが、それを予防し
ている
Read Concern
アプリ1
プライマリ
A B C
セカンダリ
A B C
セカンダリ
A B
書き
セカンダリ セカンダリ
A B A B
C
アプリ2
読み
アプリ3 アプリ4
読み
読み
↑まだ同期できていない↑
Read Concern
• MongoDBにおける「Rollback」とは
• データロストが発生する壊れ方
Read Concern
アプリ1
プライマリ
A B C
セカンダリ
A B C
セカンダリ
A B
書き
セカンダリ セカンダリ
A B A B
C
①↑まだ同期できていない↑
②↓ここでネットワークが分断される
アプリ2
セカンダリ
A B C
セカンダリ
A B C
プライマリ
A B
書き
セカンダリ セカンダリ
A B A BD
D
③レプリカの過半数が見え
ないためセカンダリに降格↓
D D
セカンダリ
A B
C
セカンダリ
A B
C
プライマリ
A B
セカンダリ セカンダリ
A B A BD D DDD
④Cをロスト
ストレージ
mongod
デフォルトがMMAPv1からWiredTigerに
• Version 2.x
o 名無しのストレージ(MMAPベース)
• Version 3.0
o MMAPv1 ⇒ デフォルト
o WiredTiger ⇒ オプション
• Version 3.2
o MMAPv1 ⇒ オプション
o WiredTiger ⇒ デフォルト
MMAPv1
ストレージAPI
参考) http://www.slideshare.net/NorbertoLeite/mongodb-wiredtiger-internals
セキュリティ
MongoDBクエリ言語エンジン
WiredTiger
アプリケーション
MonogDBドライバ
管理
MMAP用
データ
ファイル
WiredTiger用
データファイル
MMAP用
データ
ファイル
WiredTiger用
データファイル
デフォルトがMMAPv1からWiredTigerに
• MMAPv1とは
o MongoDB 3.0のデフォルト
o ディスクにあるファイルをそのままメモリに乗せる
o OSがキャッシュするデータを決める
 LRUのアルゴリズムでページアウトさせる
 最も頻度が高いメモリのページが残る
o つまり、「手抜き」のストレージ
D
E
F
ディスク
メモリ
C
B
A
B
D mongod
プロセス
OSにメモリに
乗せてもらう
E
デフォルトがMMAPv1からWiredTigerに
• MMAPv1における更新=in place(その場)
ディスク
メモリ
{ name : "abe",
age : 20 }
doc1 doc2 doc3
{ name : "abe",
age : 20 }
ディスク
メモリ
{ name : "abe",
age : 20 }
doc1 doc2 doc3
{ name : "abe",
age : 21 }
ディスク
メモリ
doc1 doc2 doc3
{ name : "abe",
age : 21 }
1.メモリに乗せる
2.更新する(アプリに応答)
3.非同期でディスクに書き戻す
{ name : "abe",
age : 21 }
クエリスレッド
クエリスレッド
同期スレッド
注意)ジャーナルを使っていないときの動き
デフォルトがMMAPv1からWiredTigerに
• MMAPv1の問題点
o 書き込むときにロックを取る必要がある
 読み取りがブロックされ、システムのスループットは低下
 コレクション全体のロック(ver 2.xではデータベースロック)
o メモリ使用量を制御できない(OSまかせ)
 OSは空いているだけ使う
o 物理的に収まりきらない場合は、ディスク上で再配置が起こる
 非常に重い処理
 物理的にデータの穴が開き、フラグメンテーション発生。
ディスク
メモリ
doc1 doc2 doc3
{ name : "abe",
age : 20, id:123456}
{ name : "abe",
age : 20, id:123456}入らない!
デフォルトがMMAPv1からWiredTigerに
• WiredTigerとは
o 3.0から搭載されているストレージ
o 3.2からはデフォルト
o 追記型
o 書き込みが読み込みをロックしないアルゴリズム(MVCC)を採用し、ド
キュメントレベルのロックを実現
o データ圧縮可能
o メモリ使用量コントロール可能
o インデックスとデータファイルの分離可能(IOの分散ができる)
o ストレージの統計情報が出力できるようになった
• つまり、「ちゃんとした」ストレージ
デフォルトがMMAPv1からWiredTigerに
• WiredTigerにおける更新=追記型 (MVCC)
{"no": 11}
{"no": 11}
チェックポイント直後
メモリ
ディスク {"no": 11}
{"no": 11}
noが12に更新された
update{"no": 12}
{"no": 11}
{"no": 11}
update{"no": 12}
update{"no": 13}
noが13に更新された
{"no": 11}
{"no": 11}
update{"no": 12}
update{"no": 13}
チェックポイント
Eviction(立ち退き)
{"no": 13}
{"no": 13}
チェックポイント直後
version 2
version 1
version 2
version 1
version 3
更新中の読み込みは、
旧バージョンを読み取る
⇒読み込みは待たされない!
デフォルトがMMAPv1からWiredTigerに
• WiredTigerの更新の特徴
o 書き込みは1ドキュメントを追記するだけ
o 読み取りは書き込みを待たない
o ディスクに書き戻される時にディスク上の物理配置を都度調整するた
め、フラグメンテーションは発生しない
• その他ポイント
o ジャーナルを有効にすると、追記書き込みをディスクに永続化できる
 チェックポイントの間にクラッシュしてもデータロストなし
o インデックスとデータファイルはWiredTigerのトランザクション機能を
使って同時に更新される
o 複数ドキュメントを跨いだトランザクションは提供されない
その他ストレージ
• インメモリ
o ディスクIOを行わないインメモリストレージエンジンinMemoryが選べる
ようになった
o 有償のEnterprise版のみ
o ベータ版
• 暗号化対応のWiredTiger
o WiredTigerを暗号化できる
o HIPAA, PCI-DSS, FERPAといったセキュリティの標準化に準拠してい
ます
o 有償のEnterprise版のみ
• テスト用エフェメラル
o テストで毎回データをクリアしなくてよい、テスト用のストレージエンジ
ンephemeralForTestが選べる
o ベータ版です。
運用
運用の改善
• mongodumpとmongorestoreの改良
o 圧縮に対応
o リモートのmongodに対してdumpしたデータをストリームで
転送しrestoreすることができる
• 診断用データ
o デフォルトで1秒ごとに診断用データ(Diagnostic Data)がと
られるようになった。
o データはデータフォルダにファイルとして出力される。
その他のエンハンス
• WiredTigerがfsyncでロックできるようになった
o 静止点を取りやすくなった
• 32bitバイナリが非推奨になった。
• Write Concernの仕様がちょっと変わった
• journalCommitIntervalのオプションがWiredTiger
でも使えるようになった
最後に書籍紹介 近日発売
• 著者
o 小笠原 徳彦
• タイトル
o はじめてのMongoDB
―オープンソースのNoSQLデータベース
• 内容
o 初心者向け
o アプリ開発者向け ≠DBA
o コマンド例多め
ちょっとMongoDB使ってみたいな、
MongoDBを使ったアプリケーションを
書いてみたいな」という人の背中をお
してあげる本を目指して書きました。
ぜひMongoDBを使ったアプリ開発を
楽しんでみてください!

MongoDB3.2の紹介