Top Banner
Advanced @doryokujin 第6回 MongoDB 勉強会 2011/09/24 #1
68

Advanced MongoDB #1

Jan 15, 2015

Download

Technology

Takahiro Inoue

MongoDBのTipsや運用における注意点など、一歩進んだ内容を紹介します。書ききれないので#1です。
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Advanced MongoDB #1

Advanced

@doryokujin第6回 MongoDB 勉強会 2011/09/24

#1

Page 2: Advanced MongoDB #1

・井上 敬浩(26歳)

・twitter: doryokujin

・データマイニングエンジニア

・MongoDB JP 代表

・NoSQLやHadoopに興味

・マラソン2時間33分

自己紹介

Page 3: Advanced MongoDB #1

・[ニュース] InfoWorldが2011年のベストオープンソース賞「Bossies」を発表、MongoDB、Hadoop、LibreOfficeなどが受賞

・[ニュース] MongoDB 2.0 正式リリース

・[コミュニティ] 11月15日(火)「第7回MongoDB勉強会」に ServerDensity の @davidmytton 氏が来日・講演

・[コミュニティ] 1月第3週に10genのエンジニアを招待して「MongoDB Conference in Japan#2」を開催予定!

最近のニュース

Page 4: Advanced MongoDB #1

1. スキーマデザイン

2. パフォーマンス

3. データ保全・バックアップ

アジェンダ

Page 6: Advanced MongoDB #1

・MongoDB on the Cloud

・MongoDB with Web Application

・MongoDB for Data Processing

・Sharding に関する Tips

#2 へ続く

今回書けなかった事

Page 7: Advanced MongoDB #1

・1-1. Reference / Embedded

・1-2. オブジェクト増加性

・1-3. Template / Preallocate

・1-4. _id にどの型を用いるべきか

・1-5. ドキュメント内のフィールド順序

1. スキーマデザイン

Page 8: Advanced MongoDB #1

・1-1. Reference / Embedded

・1-2. オブジェクト増加性

・1-3. Template / Preallocate

・1-4. _id にどの型を用いるべきか

・1-5. ドキュメント内のフィールド順序

1. スキーマデザイン

Page 9: Advanced MongoDB #1

Collection “product”:

{

"_id" : productId1,

"name" : name1,

"price" : price1,

"desc" : description1

},

{

"_id" : productId2,

Collection “order”:

{

"_id" : orderId,

"user" : userInfo,

"items" : [

productId1,

productId2,

productId3

]

}

Reference Document

Page 10: Advanced MongoDB #1

Collection “product”:

{

"_id" : productId1,

"name" : name1,

"price" : price1,

"desc" : description1

}

{

"_id" : productId2,

Collection “order”:

{

"_id" : orderId,

"user" : userInfo,

"items" : [

productId1,

productId2,

productId3

]

}

> db.product.findOne(“_id”:productId1)

> db.product.findOne(“_id”:productId2)

> db.product.findOne(“_id”:productId3)

シングルクエリでドキュ

メント情報全取得は不可

Reference Document

Page 11: Advanced MongoDB #1

Embedded DocumentCollection “order”:

{

"_id" : orderId,

"user" : userInfo,

"items" : [

{

"_id" : productId1,

"name" : name1,

"price" : price1

}, {

"_id" : productId1,

"name" : name1,

"price" : price2

},...

] }

Page 12: Advanced MongoDB #1

Embedded DocumentCollection “order”:

{

"_id" : orderId,

"user" : userInfo,

"items" : [

{

"_id" : productId1,

"name" : name1,

"price" : price1

}, {

"_id" : productId1,

"name" : name1,

"price" : price2

},...

] }

シングルクエリで全てのorder情報を取得可能

collectionの中から特定のnameや条件以上の

priceを持つorderも特定可能

> db.order.find({ items :{

$elemMatch: { name: name1 }

} } )

> db.order.find({ items :{

$elemMatch: { price:{ $gt: 3000 } }

} } )

Page 13: Advanced MongoDB #1

Embedded: [] or {} ?Collection “order”:

{

"_id" : orderId,

"user" : userInfo,

"items" : [

{

"_id" : productId1,

"name" : name1,

"price" : price1

}, {

"_id" : productId1,

"name" : name1,

"price" : price2

},...

] }

Collection “performance_rating”:

{

"_id" : "employeeId",

"name" : "name",

"post" : "section chief",

"abilities" : {

"skillA" : 20,

"skillC" : 12,

"skillE" : 18,

"skillF" : 24,

"skillG" : 23

}

}

Page 14: Advanced MongoDB #1

Embedded: [] or {} ?Collection “order”:

{

"_id" : orderId,

"user" : userInfo,

"items" : [

{

"_id" : productId1,

"name" : name1,

"price" : price1

}, {

"_id" : productId1,

"name" : name1,

"price" : price2

},...

] }

Collection “performance_rating”:

{

"_id" : "employeeId",

"name" : "name",

"post" : "section chief",

"abilities" : {

"skillA" : 20,

"skillC" : 12,

"skillE" : 18,

"skillF" : 24,

"skillG" : 23

}

}

・等価なオブジェクトが増えていく場合・$elemMatch オペレータを使用

・オブジェクトは1つでフィールドのみが  増加する場合・”abilities.skillA”といったドット記法で内部フィールドにアクセス

Page 15: Advanced MongoDB #1

Embedded Document

[デメリット]

・16MB/ドキュメント制約

・product 情報が更新された場合が非常に厄介(例えば期間限定セールなど)

・階層固定:order 情報から product 情報は辿れるが、product 情報からorder情報は辿れない

Page 16: Advanced MongoDB #1

Reference or Embedded ?[1] パフォーマンス:シングルクエリで完結する方が高速

※ MongoDB は DBRef の機能自身を備えていない。つまりEmbedded オブジェクトの情報を取得する場合は普通にクエリを実行しなければならない(ドライバが Wrap してくれる)

[2] 更新コスト:Embedded されるオブジェクトにどれくらいの変更可能性があるか、あれば大量の更新処理が必要

[3] オブジェクト増加性:Embedded されるオブジェクト数が挿入後不変出なければ必ず Reference を使う

※ 先の例では order 作成時にproductの数も決まるので不変

Page 17: Advanced MongoDB #1

・1-1. Reference / Embedded

・1-2. オブジェクト増加性

・1-3. Template / Preallocate

・1-4. _id にどの型を用いるべきか

・1-5. ドキュメント内のフィールド順序

1. スキーマデザイン

Page 18: Advanced MongoDB #1

オブジェクト増加性Collection “blog”:

{

"_id" : blogId,

"user" : userInfo,

"tags" : [tag1, tag2, tag3]

"comment": [{

"_id" : commentId1,

"user" : userInfo1,

"contents" : contents1

}, {

"_id" : commentId2,

"user" : userInfo2,

"contents" : contents2

},...

] }

comment オブジェクトはユーザーの投稿によりドキュメント挿入後も増加し続ける

・16MB/document 制約に抵触する危険性・更新がIn-Placeで行われなくなり非効率

Page 19: Advanced MongoDB #1

オブジェクト増加性Collection “blog”:

{

"_id" : blogId,

"user" : userInfo,

"tags" : [tag1, tag2, tag3]

"comment" : [

commentId1,

commentId3,

commentId5

],...

},

{

Collection “comment”:

{

"_id" : commentId,

"user" : userInfo,

"contents" : contents1,

"lastUpdate" : datetime,

...

},...

{

"_id" : commentId5,

"user" : userInfo,

"contents" : contents1,

"lastUpdate" : datetime,

...

}

> db.blog.update({“_id”:blogId},

{$push: { “comment”: commentId5 }}

})

> db.comment.insert({

“_id”:commentId5,

“user”:...

})

Page 20: Advanced MongoDB #1

・Embedded Document の場合、Update のパフォーマンス的にも、1回挿入した後にできるだけドキュメントのサイズが増えないように工夫する

・In-Place Update:新規ドキュメント挿入時には、必ずpadding(デフォルト1MB)が設けられる。新しくオブジェクトが追加される場合でも、”In-Place”で高速にUpdateが可能。paddingを超えるサイズ増加はドキュメントの領域移動が起こる

・必ず全てのUpdateが ”In-Place” になるように

(続)オブジェクト増加性

Page 21: Advanced MongoDB #1

・padding のサイズはデフォルトは1MB

・その後コレクション内のドキュメントサイズの増加傾向を見ながら自動で padding サイズを拡張してくれる。現在の padding サイズは以下のコマンドで確認可能

padding の確認

> db.coll.stats()

{ ...

#1で無ければドキュメントの移動が起きている

"paddingFactor" : 1.4099999999940787,

...

}MongoDB paddingFactor implications

Page 22: Advanced MongoDB #1

・1-1. Reference / Embedded

・1-2. オブジェクト増加性

・1-3. Template / Preallocate

・1-4. _id にどの型を用いるべきか

・1-5. ドキュメント内のフィールド順序

1. スキーマデザイン

Page 23: Advanced MongoDB #1

Template DocumentCollection “access_history”:

{

"_id" : pageId,

"start" : time,

"visits" : {

"minutes" : [

[num0, num1, ..., num59],

[num0, num1, ..., num59],

[num0, num1, ..., num59],

[num0, num1, ..., num59],

[num0, num1, ..., num59],

[num0, num1, ..., num59]

],

"hours" : [num0, ..., num5] }

}

ページごとに、“start”の時間から6時間の間の毎分のvisitor数を記録するケース

“minites”は[]からどんどんとオブジェクト(配列・要素)が追加される

しかし“minites”と”hours”は全ての配列要素を0で初期化しておける

Page 24: Advanced MongoDB #1

Template DocumentCollection “access_history”:

{

"_id" : pageId,

"start" : time,

"visits" : {

"minutes" : [

[0,0, ..., 0],

[0,0, ..., 0],

[0,0, ..., 0],

[0,0, ..., 0],

[0,0, ..., 0],

[0,0, ..., 0]

],

"hours" : [0, ..., 0] }

}

事前に初期化したオブジェクトで満たしておくことで、ドキュメントサイズの後からの増加

を防げる

Page 25: Advanced MongoDB #1

Template DocumentCollection “access_history”:

{

"_id" : pageId,

"start" : time,

"visits" : {

"minutes" : [

[0,0, ..., 0],

[3,0, ..., 0],

[0,0, ..., 0],

[0,0, ..., 0],

[0,0, ..., 0],

[0,0, ..., 0]

],

"hours" : [0, ..., 0] }

}

> db.pages.update({ "_id" : pageId, "start" : thisHour},{ "$inc": {"visits.minutes.1.0": 3}})

$incオペレータなどはオブジェクトのサイズを増加させない

Page 26: Advanced MongoDB #1

・オブジェクトの増加を避けられない場合でも、意図的に大きな padding を持たせておくことで、できる限り In-Place Update を可能にする:

Preallocate Document

> collection.insert(

{ "_id" : 123,

/* other fields */,

"garbage" : someLongString})

> collection.update(

{ "_id": 123 },

{ $unset: { "garbage" : 1} })

十分に長い文字列を持ったフィールドで多めの領域を事前に確保しておく

insert後すぐにgabageフィールドを削除

Page 27: Advanced MongoDB #1

・1-1. Reference / Embedded

・1-2. オブジェクト増加性

・1-3. Template / Preallocate

・1-4. _id にどの型を用いるべきか

・1-5. ドキュメント内のフィールド順序

1. スキーマデザイン

Page 28: Advanced MongoDB #1

・ObjectId = BSON( [4byte timestamp]

+ [3byte hash(hostname)]

+ [2byte pid]

+ [3byte inc] )

・ObjectId は決して重複せず、単調増加。できる限りObjectIdを使用

・数億件のデータで自前でユニーク性を保証できる _id を生成するのは困難 (重複する _id の insert は失敗する)

_id にどの型を用いるべきか

Page 29: Advanced MongoDB #1

[例外]

[1] 値を int 型で持てる場合:インデックスサイズの節約

[2] リトライを行う場合:insert 処理が途中で失敗した場合は対象のデータ集合全体を remove して再 insert が必要

・しかし時間等に依らず常に同じ値を持つ _id にしておけば remove 不要で、再実行すれば既に insert してあるデータは失敗(無視)し、残りの insert だけを実行する事ができる。ただし Fire-and-Forget insert にしておく

_id にどの型を用いるべきか

Page 30: Advanced MongoDB #1

# 例:(集計後の)ユーザー行動ログ

{

"_id" : BinData(5,"iiOI5R6P+dbut19O1mS1lA=="),

"reduce_id" : 0,

"user_id" : 00000,

"date" : 20110727,

"action_type" : "a{Make}",

"key_depth" : 1,

"action_detail" : {

"kakejiku" : 2,

"kaizokunojyuu" : 1,

"matoryo-sika" : 1,

"syokudai" : 1

}

}

・_id = user_id + date + timeMilliSec + action_type

でユニークな_idを取得可能。この文字列をハッシュ化してBinary変換する

# Pythonbson.Binary( hashlib.md5( str(unique_id) ).digest(), bson.binary.MD5_SUBTYPE)

_id にどの型を用いるべきか

Page 31: Advanced MongoDB #1

[indexサイズの考慮]

・_id (その他インデックスフィールド)に使用できる現実的な型は int, ObjectId, base64

How to save 200% RAM by selecting the right key data type for #MongoDB

_id にどの型を用いるべきか

Page 32: Advanced MongoDB #1

・1-1. Reference / Embedded

・1-2. オブジェクト増加性

・1-3. Template / Preallocate

・1-4. _id にどの型を用いるべきか

・1-5. ドキュメント内のフィールド順序

1. スキーマデザイン

Page 33: Advanced MongoDB #1

{

"_id" : id,

"name" : username,

"email" : email,

"phone" : phone,

"twitter" : username,

"facebook" : username,

"linkedin" : username,

"google+" : number,

"street" : street

"city" : city,

"state" : state,

"zip" : zip,

"fax" : number

}

> db.profile.find({ “fax”: number })

常に各ドキュメントを上から順に、”fax”フィールドが無いかスキャンしている

ドキュメント内のフィールド順序

Page 34: Advanced MongoDB #1

ドキュメント内のフィールド順序

・ドキュメント内の順序は非常に重要

・頻繁に検索されるフィールドは先頭に近くあるべき

[対策1]:順序付き連想配列 <-- Pythonならば”SON” オブジェクトを使う。

[対策2]:サブオブジェクトを使用。subKey のフィールドには ”key.subKey” で直接アクセスできる

※ 両方を併用する

Page 35: Advanced MongoDB #1

{

"_id" : id,

"name" : username,

“online”: {

"email" : email,

"twitter" : username,

...

},

”address”: {

"street" : street

"city" : city,

...

},

“telephone”: {

"phone" : phone,

"fax" : number

}

> db.profile.find({ “telephone.fax”: number })

上から順にスキャンせず、直接”telephone”フィールド内のスキャンを行える

Page 36: Advanced MongoDB #1

・2-1. Query Match 順序

・2-2. Index

2. パフォーマンス

Page 37: Advanced MongoDB #1

・2-1. Query Match 順序

・2-2. Index

2. パフォーマンス

Page 38: Advanced MongoDB #1

[AND(OR)-Queries]

・次の2つのクエリは検索速度が異なる

Query Match 順序

# Aにマッチする集合の中でBにマッチさせ、さらにその集合の中でCにマッチする集合を表示

> db.coll.find({“A”: a, “B”: b, “C”: c})# Cにマッチする集合の中でBにマッチさせ、さらにその集合の中でAにマッチする集合を表示

> db.coll.find({“C”: c, “B”: b, “A”: a})

# Aの補集合の中でBにマッチさせ、その補集合の中でCにマッチする集合の和を表示

> db.coll.find($or: [“A”: a, “B”: b, “C”: c])# Cの補集合の中でBにマッチさせ、その補集合の中でAにマッチする集合の和を表示

> db.coll.find($or: [“C”: c, “B”: b, “A”: a])

Page 39: Advanced MongoDB #1

[AND-Queries]

[worse] Aの集合が大きい場合。続くB、Cはその大きな集合から検索される

[better] Cの集合が最も小さい場合。先に検索されれば、続くB、Aは小さな集合内から高速に検索される

Query Match 順序

AB B

C

A A

C

BBA

C C

Page 40: Advanced MongoDB #1

[OR-Queries]

[worse] Cの補集合(青領域)が大きい場合。続くB、Cはその大きな補集合から検索される

[better] Aの補集合(青領域)が最も小さい場合。続くB、Aは小さな集合内から高速に検索される

Query Match 順序

C

A AB

AB

C

B

C

B

C

A

Page 41: Advanced MongoDB #1

・2-1. Query Match 順序

・2-2. Index

2. パフォーマンス

Page 42: Advanced MongoDB #1

・インデックスを使用しているフィールド群に限定してデータを抽出する場合は、実質インデックスツリーのスキャンだけでデータの高速検索が可能

Covered Index

> db.coll.ensureIndex({ A: 1 })

> db.coll.ensureIndex({ B: 1 })

> db.coll.ensureIndex({ C: 1 })

# find の第2引数で “Select A,B,C” のように特定のフィールドのみを取得する

> db.coll.find({ A: a, B: b, C: c },

{ _id: -1, A: 1, B: 1, C: 1 })

・インデックスを作成しているフィールドのみを条件・抽出 (_idは必ず取得項目から除外) 対象にしたクエリには Covered Index が自動的に適用される

Page 43: Advanced MongoDB #1

・MongoDBはインデックスと、直近にアクセスされたドキュメントをメモリに持っておく

・「インデックスサイズ」 < 「メモリサイズ」となるように常に心がけるのは非常に重要(しかし現実は厳しい)

→ できるだけインデックスを作成しない

→ インデックスの型に注意(配列などは論外。文字列も避ける)

→ Sharding (Chunk間ではインデックスは共有される)

→ ver.2.0 (25% smaller and 25% faster。ただし再作成の必要)

Index について

Page 44: Advanced MongoDB #1

・3-1. Replica Set

・3-2. Journaling

・3-3. getlasterror

・3-4. Repair / Comapct

3. データ保全・バックアップ

Page 45: Advanced MongoDB #1

・3-1. Replica Set

・3-2. Journaling

・3-3. getlasterror

・3-4. Repair / Comapct

3. データ保全・バックアップ

Page 46: Advanced MongoDB #1

Replica Set メンバータイプType 特徴

High Priority フェイルオーバー時、Primaryになりやすい (例: priority=1.0)

Low Priority フェイルオーバー時、Primaryになりにくい (例: priority=0.5)

Slave Delay Primaryと遅延同期(例: slaveDelay=300)

Back Up Primaryには決してなり得ない。Readは可能 (例: priority=0.0)

Hidden Primaryには決してなり得ず、Readも不可能(例: hidden=true)

Arbiter 自身はデータを持たず、フェールオーバー時の投票のみ参加(例: arbiterOnly=true)

Page 47: Advanced MongoDB #1

Replica Set メンバータイプType

High Priority

Low Priority

Slave Delay

Back Up

Hidden

Arbiter

・サーバーにばらつきがある場合

・ユーザーの人為的操作ミスからでデータを守りたい場合

・journaling専用バックアップとして使用する場合。インデックスも作成する必要なし:buildIndexes=false

・ReplicaSet最低構成台数3を満たすためのダミーとして。AWSではSingle Instance に使用可能

Page 48: Advanced MongoDB #1

Replica Set 構成例

Primary

Secondary

Slave Delay

Back Up --journal

Secondary

DC1 DC2

・人為的ミスから復帰させるためにSlave Delayを用意するのは有効

・メンバーの中で最低1つはjournalingを有効に

Page 49: Advanced MongoDB #1

Replica Set 構成例

Secondary

Shard1 on AWS

Arbiter

Primary

Large Instance

Large Instance

MicroInstance

・Micro Instance ではメモリ不足・Small Instance は32bitなので不可・Large Instance を使用する・ただしArbiterは実データを持たないのでSmallで十分

--journal

Page 50: Advanced MongoDB #1

[1] フェイルオーバーでは、新しい Primary が必ずしも最新の Oplog を保持しているとは限らない。

[2] Secondary の方が新しい Oplog を保持している可能性もある

[3] その場合は Primary の Oplog に全て統一するために、全 Secondary の Oplog の差分は捨てられる

※しかし、捨てられたオペレーションは手動でロールバックすることができる。これによってできる限り元 Primary の保持していたデータに近づける

Replica Set Rollback

Page 51: Advanced MongoDB #1

[4] フェイルオーバー後、dbpathのディレクトリ以下の ”rollback” ディレクトリの中に、差分の oplog 情報を含むbsonファイルが作成される

[5] bsondump コマンドによりロールバックを行う:

Replica Set Rollback

$ ls /dbpath/rollback

dbname.collname.2011-08-14T18-27-14.0.bson

$ bsondump dbname.collname.2011-08-14T18-27-14.0.bson

{ "_id" : ... }

{ "_id" : ... }

{ "_id" : ... }

Wed Aug 15 13:33:32 3 objects found

Page 52: Advanced MongoDB #1

・3-1. Replica Set

・3-2. Journaling

・3-3. getlasterror

・3-4. Repair / Comapct

3. データ保全・バックアップ

Page 53: Advanced MongoDB #1

・ver.2.0 で標準機能に

・さらにフラッシュタイミング(デフォルト100ms)が任意に調整可能に

[journalingとは]

・データ書き込み前にオペレーションを journal ログに先行して保存 (WAL)

・journal ログは --dbpath 以下の journal/ サブディレクトリ以下にある

・古い journal ファイルは1GBごとにローテートされ、古いログは削除

Journaling

Page 54: Advanced MongoDB #1

[0] クリーンシャットダウン時には journal サブディレクトリは削除

[1] サーバーダウン時には journal サブディレクトリはそのまま残る

[2] mongod は起動時に journal サブディレクトリが無いかチェック

[3] あればそのディレクトリ内の journal ログからダウン時に未実行だったオペレーションを実行する(クライアントは完了まで待機)

・journal ログへの書き込みは任意 (> v.2.0、デフォルト100ms)

・書き込みは Group Commits を行って高速に行われる

Journaling Process

Page 55: Advanced MongoDB #1

[メリット]

・データの安全性:実際の書き込みオペレーションが適用前にダウンしても journal ログに記述されたオペレーションは保証される

・Repair 不要:不意なシャットダウンからの復帰は lock ファイルの削除、Repair コマンドが必要であったがそのどちらのオペレーションが不要に。起動時に自動リカバリしてくれる (journaling process)

・Journaling は必ず使用すべき

Journaling

Page 56: Advanced MongoDB #1

[デメリット]

[1] パフォーマンス低下:常にJournalログへの書き込みが行われるので全体のパフォーマンスが低下する(30%程度悪化?)

[2] 重複書き込み:Replica SetもオペレーションをOplog Collectionに保存する。Journalingもオペレーションを保存する。毎回のオペの書き込みが重複 (3重) するコストは大きい

Journaling

Page 57: Advanced MongoDB #1

[対策][1] journal サブディレクトリをシンボリックリンクで別ディスクへ逃がす。SSD(64GBで十分)に逃がせば効率的

[2] Replica Set メンバーの中で最低 1 台のメンバー(BackUpタイプ) のみjournaling を有効にしておく

Journaling

Primary

Secondary

Back Up --journal

DC1 DC2

・DC1のPのダウン時にはSがPになるが、その際にはロールバックが必要な場合も。DC2のダウン時には再起動してリカバリして同期をすれば良い

・DC1全体のダウン時にはDC2のバックアップをMasterとして起動することでデータをリカバリできる。

Page 58: Advanced MongoDB #1

・3-1. Replica Set

・3-2. Journaling

・3-3. getlasterror

・3-4. Repair / Comapct

3. データ保全・バックアップ

Page 59: Advanced MongoDB #1

getlasterror コマンド・デフォルトの Insert は ”Fire-and-Forget”

・書き込み完了を確認してからリターンを返すためにはgetlasterror コマンドを併用

・ドライバからはオプションで指定可能:Pythonなら “safe=True”、JavaならWriteConcernオブジェクト

> db.collname.insert({_id:...})

# 直前の書き込みが完了してからリターンを返す> db.getLastError()

# or

> db.runCommand("getlasterror")

Page 60: Advanced MongoDB #1

getlasterror オプション

[fsync] ※ journaling を適用していない場合・全データがフラッシュされるまで待機

[j] ※ journaling を適用している場合・journal commit が完了するまで待機

> db.runCommand({ getlasterror: 1, fsync: true })

{ "err" : null, "n" : 0, "fsyncFiles" : 2, "ok" : 1 }

> db.runCommand({ getlasterror: 1, j: true })

Page 61: Advanced MongoDB #1

getlasterror オプション[w]・Replica Set の n 台のメンバーに対して書き込みが完了するまで待機

・w を使用する場合は必ず timeout を設定する

[majority]

・過半数のノードへの書き込みが完了するまで待機

> db.getLastError(2, 5000) // w=2, timeout 5000ms

> db.getLastError("majority")

Page 62: Advanced MongoDB #1

・3-1. Replica Set

・3-2. Journaling

・3-3. getlasterror

・3-4. Repair / Comapct

3. データ保全・バックアップ

Page 63: Advanced MongoDB #1

・MongoDB は remove() や drop() によって削除したドキュメントやコレクションの領域をシステムに解放しない

・MongoDB が空き領域を管理し、後に追加されるデータをそこに入れようとする → 実際は効率良く行われない

・この機能によってデータ削除を繰り返すと実データの割に占有するディスク領域が大きくなっていく

・Repair、Compact (ver2.0) コマンドでその無駄な領域を開放できる

Removeの繰り返しによる断片化

Page 64: Advanced MongoDB #1

・Repair コマンドは、DB のダウンから復帰の際にも使用する。不良データチェックとデフラグの役割を果たす

・全データスキャンを行うため、非常に時間がかかる。できれば使いたくないコマンド

・さらに現在のディスクサイズと同じサイズの空き領域が必要

・内部的には空き領域に mongoimport/mongoexport によって隙間なくデータを書き込んでいく

Repair コマンドについて

Page 65: Advanced MongoDB #1

・Repair コマンドはサーバー単位。Replica Set ではSecondary に降格させて順次バックグラウンドで行う。Sharding 環境でも shard 個々に行う必要がある。

・Compact コマンドはコレクション単位で行える。ただしこれも Secondary に降格させて行う

・Compact コマンドは2倍のディスクを消費せず、かつ高速

※ Compact コマンドはドキュメントの padding をも消去する。オブジェクト増加性を持ったコレクションにはパフォーマンスに悪影響

Comapct コマンドについて

Page 66: Advanced MongoDB #1

・スキーマデザインの問題は完全にケースに依存、ただできるだけ “Single Query” で実行出来るデザインであるべき

・インデックスのサイズには常に細心の注意を

・MongoDB を実際に運用する際にはデータ保全のための施策とバックアップを行っておく事が重要

まとめ

Page 67: Advanced MongoDB #1

・MongoDB JPでは「MongoDB Conference in Japan#2」のスポンサーを募集しています

・また会場を提供して頂ける方、スタッフをして頂ける方を広く募集しております

・MongoDB の導入を検討されている企業さんも気軽に相談して頂ければ

・mr.stoicman[at]gmail.com か @doryokujin まで宜しくお願いします

募集

Page 68: Advanced MongoDB #1

ありがとうございました