Mongodb 紹介

Preview:

Citation preview

MongoDB紹介

2012/5/18 matsumura

MongoDBってなんぞ - 多機能 but 発展途上 •  ドキュメント指向データベース

o  最新2.0.5 •  自動シャーディング

o  Read / Writeがスケールアウト

•  自動フェイルオーバー o  Master deadでも自動でフェイルオーバー

•  柔軟なクエリ o  SQLで可能なことはJOIN句以外 一通りできる

•  スキーマレス o  データによって自由に持つものを決められる

他にも多機能

構成例

Web mongos

Web mongos

Mongod (config)

Mongod (config)

Mongod (config)

meta

Replica set

mongod

mongod

mongod

Replica set

mongod

mongod

mongod

data data

3processで最適化 最小構成台数

3process

基本的なデータの持ち方

mongod

データベース etcr

データベース other

コレクション 行動履歴 コレクション XXマスタ

コレクション 各種ログ

doc doc doc

doc doc doc

doc doc doc

doc

doc doc doc

mysqld

MySQLで例えると

データベース

テーブル

レコード

レプリカセット - MySQL同様

Mongod (Primary)

データベース etcr

コレクション 行動履歴

docA docB docC

docD docE docF

データベース local

コレクション oplog

操作 操作 操作

Mongod(Secondary)

データベース etcr

コレクション 行動履歴

docA docB docC

docD docE docF

データベース local

コレクション oplog

操作 操作 操作

Mongod(Secondary)

データベース etcr

コレクション 行動履歴

docA docB docC

docD docE docF

データベース local

コレクション oplog

操作 操作 操作 同期

再現 再現

自動フェイルオーバー •  Primaryが死ぬ

•  Primaryが死んだことがreplica set内で共有 •  残ったノードで投票を行う •  ノードごとの優先度設定、最終同期時刻をもとに投票を行う

•  過半数より多くの票を集めたノードがPrimaryとなる

•  この間 約20s ~ 60s

Mongod (Shard A)

自動シャーディング - phase1

データベース etcr

コレクション 行動履歴

Mongod (Shard B) データベース etcr

コレクション 行動履歴

Chunk ( –無限大 〜 無限大]

docA docB docC

デフォルト 200MB

Mongod (Shard A)

自動シャーディング - phase2

データベース etcr

コレクション 行動履歴

Mongod (Shard B) データベース etcr

コレクション 行動履歴

Chunk ( –無限大 〜 D]

docA docB docC

Chunk ( D 〜 無限大]

docD docE docF

Mongod (Shard A)

自動シャーディング - phase3

データベース etcr

コレクション 行動履歴

Mongod (Shard B) データベース etcr

コレクション 行動履歴

Chunk ( –無限大 〜 D] docA docB docC

Chunk ( D 〜 無限大]

docD docE docF

docC’ docC’’ docC’’’

Mongod (Shard A)

Chunk (C’ 〜 D]

自動シャーディング - phase4

データベース etcr

コレクション 行動履歴

Mongod (Shard B) データベース etcr

コレクション 行動履歴

Chunk ( –無限大 〜 C’]

docA docB docC

Chunk ( D 〜 無限大]

docD docE docF

docC’ docC’’ docC’’’

Mongod (Shard A)

Chunk (C’ 〜 D]

自動シャーディング - phase5

データベース etcr

コレクション 行動履歴

Mongod (Shard B) データベース etcr

コレクション 行動履歴

Chunk ( –無限大 〜 C’]

docA docB docC

Chunk ( D 〜 無限大]

docD docE docF

docC’ docC’’ docC’’’ 水平方向に スケールアウト

自動シャーディング - phase6

• Sharding Demo

スキーマレス

• Create table, Create column family 不要 o  Insertした時点で作られる o アプリ要件に合わせて柔軟に入れられる Item1 = {

_id: ObjectId('4b0552b0f0da7d1eb6f12xxx'), name: 秘薬, price: 100,

} Item2 = {

_id: ObjectId('4b0552b0f0da7d1eb6f12yyy'), name: 自分用秘薬,

}

柔軟なクエリ

• SQL文を持たない • Demo • ハッシュでO/Rマッパーのように指定する

o フロントjavascriptからクエリオブジェクトを送って、サーバーサイドでは検証後、即実行できる

クエリ 周辺の話 (1)

• Index(B-Tree) o 配列やオブジェクトに対してもはれる

§ ただし、配列は1つ / indexに制限 o メモリに乗るようにintを使うと吉

// indexをつける db.test.ensureIndex({x:1, y:1, z:1}) ○ db.test.find({x:'a'}) ○ db.test.find({x:'a', y:'b'}) ○ db.test.find({x:'a', y:'b'}).sort({z:1}) // 順序が重要 × db.test.find({y:'b', x:'a'})

クエリ 周辺の話(2)

• クエリオプティマイザ o MySQLのようなコストベースではない o 初回のクエリで複数クエリプランを同時実行 o 最も早かったクエリを利用 o データ量に応じて定期的に見直し o explain()

クエリ 周辺の話(3)

• Capped コレクション o あらかじめサイズを決めたコレクション o 古いものから順次消えていく o 挿入順での検索で高速 o Shardingできない o 削除不能 o Create文を明示的に発行して作成

§ db.createCollection("mycoll", {capped:true, size:100000})

クエリ findの話 (1) • 検索条件は、bsonオブジェクトの先頭に寄せる

{ owner_id: 123, request: { type: '合成', params: {}}, process: {category: 'composit'}, memo: ['lv.0 -> lv.15'], concerned: [ {io: 'i', type: 'card', id: 100, object: '111', base: true}, {io: 'i', type: 'card', id: 201, object: '222'}, {io: 'o', type: 'card', id: 100, object: '111'}, ] })

1. db.activityHistoryDemo.find({owner_id: 123})

2. db.activityHistoryDemo.find({‘concerned.id’: ‘201’})

クエリ findの話 (2) •  bsonオブジェクト階層を細分化したほうが早い

{ owner_id: 123, request: { type: '合成', params: {}}, process: {category: 'composit'}, memo: ['lv.0 -> lv.15'], concerned: [ {io: 'i', type: 'card', id: 100, object: '111', base: true}, {io: 'i', type: 'card', id: 201, object: '222'}, {io: 'o', type: 'card', id: 100, object: '111'}, ] })

db.activityHistoryDemo.find({‘concerned.id’: ‘201’})

クエリ findの話 (3) • 条件の指定順序

o  And条件は結果の小さな条件から順次 §  補集合を無視するので。

o  Or条件は結果の大きな条件から順次 §  後続条件は補集合から検索するので。

○ db.sample.find({owner_id: 123, ‘concerned.type’: ‘card’})

× db.sample.find({‘concerned.type’: ‘card’, owner_id: 123})

○ db.sample.find({$or: [{‘concerned.type’: ‘card’}, {owner_id: 123}])

× db.sample.find({$or: [{owner_id: 123}, {‘concerned.type’: ‘card’}])

クエリ findの話 (4) •  DBRef

doc = { name: 'ryooo', card:[ {'$ref': 'card', '$id' : ObjectId('4b0552b0f0da7d1eb6f12xxx')}, ] } doc.card[0].fetch() // ←カードオブジェクトがとれる

@ruby db = Connection.new.db(”etcr ") user_card = db["user_card"].save({:name => ”ryooo”, :card_id => 123}) ref = DBRef.new(”card", user_card.card_id) db.dereference(ref) #=> カードオブジェクト

クエリ findの話 (5) • 検索条件に関数も使える(javascript)

• mongoサーバーサイドに関数を登録できる

// 極端な話、こんなクエリも書けちゃいます db.cards.find(function(){ row = db.user_summary.findOne({owner_id: this.owner_id}) return this._id == row.leader_card_id; })

// 関数を登録 db.system.js.save({_id:’name', value: function (){ //implementation }}); f = db.system.js.findOne({_id:’name'}) // 検索で利用(fはサーバー側で実行される) Db.cards.find(f)

Mongod (Shard A)

クエリ findの話 (6)

データベース etcr

コレクション 行動履歴

Mongod (Shard B)

データベース etcr

コレクション 行動履歴

Chunk

docA docB docC

Chunk

docD docE docF

Shard keyを利用したクエリ Shard keyを利用しないクエリ

targeted global

クエリ insert/updateの話 (1) •  fire and forget

o  発火即忘却 §  結果を確認せずreturnする §  結果を知りたければgetlasterrorオプションを指定

• 確実にcommitさせる o  データファイルにフラッシュさせる

§  fsync: true o  2台のメンバーに書き込みが完了するまで待機(timeout:5000)

§  db.getlasterror(2, 5000) §  db.getlasterror('majority')

クエリ insert/updateの話 (2) •  ID値

o  デフォルトでは、IDは自動で振られる o  ObjectId = BSON(

[4byte timestamp] + [3byte hash(hostname)] + [2byte pid] + [3byte inc])

// parseすれば時間やサーバーなどもわかる object_id = '4b0552b0f0da7d1eb6f12yyy’ createdDt = new Date(parseInt(object_id.substr(0, 8), 16) * 1000) #=> Thu Nov 19 2009 23:14:08 GMT+0900 (JST)

クエリ insert/updateの話 (3) •  Padding

o  insert時に、パディング領域を確保している §  配列に追加されるなど、ドキュメントサイズが拡大しても高速にupdateするため(In-place update)

o  Padding領域を越える更新 §  ドキュメントの再配置が発生(遅い) §  増加性を持ったコレクションはPaddingサイズ調整が必要

•  Atomicな操作 o  1つのドキュメントの更新に対して別のクエリをブロック o  トランザクションのACIDのA(atomic : all or nothing)ではない。 o  sharding環境でサポートされない

クエリ removeの話 • 断片化

o  削除時はドキュメントの再配置を行わないので断片化する

o  repairコマンド §  同容量の空き領域が必要 §  サーバー単位(sharding環境なら各shardで)

o  compactコマンド §  より少ない空き領域で可能 §  コレクション単位 §  paddingも削除するので、増加性を持ったコレクションはデフラグ後にupdateパフォーマンス悪化

困った話 - 1 •  flush前のデータロスト

o  デフォルトでは60sに1回flushされるまではメモリで保持 §  最大で60秒間のデータロストの可能性

o  対策1 (~ver1.8) §  60秒の設定を短縮する §  getlasterror()でflushさせる

•  重くなる o  対策2 ジャーナルモード (ver1.8~)

§  ジャーナルログ(disc)に100msに1回書き込む §  flushと違い、データの更新先などを意識しないため早い §  起動時にJournalディレクトリがあれば復元し、正常終了時はディレクトリを削除する。

困った話 - 2 • 書き込み時(flush時)はDBロックする

o  あまり問題にならないほど、書き込みは高速とのこと §  ほんまかいな

• 非効率なCPUリソース利用 o  書き込み処理とMapReduceではシングルコアしか使えない o  読み込みは複数コアを使う

みんなが苦労しているのは •  Shard key の決め方

o  Chunkの移動があまり起こらないこと o  長期の運用でも綺麗に分散すること o  Shard keyを使って効率よく検索できること

•  Shard keyは一度決めると変えられない

• Migration中の残念なパフォーマンスと不整合

Shard keyの考察 (うけうり) •  [bad] 離散データ

o  chunk分割できない §  例:都道府県コード

•  [bad] 単純インクリメントデータ o  最後のchunkのみが分割移動される

§  例:連番

•  [bad] ランダム値 o  十分に分散するまでは偏りがあるため、大きなchunkができる

§  例:ハッシュ

•  [good] 緩やかに増加するキーと検索に利用するキーの組み合わせ o  検索利用キーでひと月かけて偏りが発生してくるが、ひと月たてば偏りがリセットされる §  例:yyyymm-owner_id

解析用サーバー

シンプルな解析PFの例

Web Web

日次増分をMap/Reduceで集計

認証機能が必要なため。 I/Oをjsonで一致させて

開発スピードアップ

使ったことないものを 仕事で使ってみたいという想い