MongoDB

ドキュメント指向データベース

http://www.mongodb.org/

Tutorials

http://docs.mongodb.org/master/tutorial/

Java Driver for MongoDB

http://docs.mongodb.org/ecosystem/drivers/java/

MongoDB クライアント

http://robomongo.org/

特徴:スキーマレス(カラムが固定されない)、パフォーマンス高い、スケーラブル

利用場面:ビッグサイズ、重要度が低いデータの保存、リアルタイム性

不適場面:Transaction必要、複数テーブルからの複雑なクエリ

★Ubuntuにインストール

#公開鍵の設定

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10

#/etc/apt/sources.list.d/mongodb.listの作成

echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list

sudo apt-get update

sudo apt-get install mongodb-10gen

★起動

サービス起動

mongod --dbpath D:\mongodb\db

★MySQL vs MongoDB

構造

SQL文

sudo service mongodb start

sudo service mongodb stop

sudo service mongodb restart

httpによりMongoDB状態を確認

http://localhost:27017/

http://localhost:28017/ webコンソール

シェルクライアント

mongoコマンド

mongo [DB名] [xxx.js] 外部ファイル

コマンド --help

★シェルクライアントのコマンド

help コマンド一覧

use test データを切り替え

db カレントDB

db.stats()

db.help() カレントDBのメソッド一覧

db.コレクション.help() コレクションのメソッド一覧

db.system.users.find() ユーザ一覧

show users

db.system.users.remove()

show dbs

db.dropDatabase()

show collections

db.createCollection("xxx")

db.コレクション.getIndexes() Index一覧

db.コレクション.drop()

db.コレクション.renameCollection("xxx")

load("xxx.js")

★Indexについて

> db.person.find({"name":"andy"}).explain()

Index使用しない

{

"cursor" : "BasicCursor", 全件検索

"isMultiKey" : false,

"n" : 1, 結果の行数

"nscannedObjects" : 5,

"nscanned" : 5, 全件スキャン

"nscannedObjectsAllPlans" : 5,

"nscannedAllPlans" : 5,

"scanAndOrder" : false,

"indexOnly" : false,

"nYields" : 0,

"nChunkSkips" : 0,

"millis" : 0, 実行時間

"indexBounds" : {

},

"server" : "xxx:27017"

}

Index使用する

{

"cursor" : "BtreeCursor name_1",

"isMultiKey" : false,

"n" : 1,

"nscannedObjects" : 1,

"nscanned" : 1,

"nscannedObjectsAllPlans" : 1,

"nscannedAllPlans" : 1,

"scanAndOrder" : false,

"indexOnly" : false,

"nYields" : 0,

"nChunkSkips" : 0,

"millis" : 0,

"indexBounds" : {

"name" : [

[

"andy",

"andy"

]

]

},

"server" : "xxx:27017"

}

★DBバックアップ、DB回復、Read-Write分離

●Master-Slave方式

mongod --dbpath D:\mongodb\dbM --master

mongod --dbpath D:\mongodb\dbS1 --port 8888 --slave --source 127.0.0.1:27017

mongo 127.0.0.1:27017

mongo 127.0.0.1:8888

●Replica Sets方式

mongod --dbpath D:\mongodb\dbR1 --port 2222 --replSet testR/127.0.0.1:3333

mongod --dbpath D:\mongodb\dbR2 --port 3333 --replSet testR/127.0.0.1:2222

mongod --dbpath D:\mongodb\dbR --port 4444 --replSet testR/127.0.0.1:2222

mongo 127.0.0.1:2222/admin

環境構築

>初期化

db.runCommand({"replSetInitiate":{

"_id":"testR",

"members":[

{

"_id":1,

"host":"127.0.0.1:2222"

},

{

"_id":2,

"host":"127.0.0.1:3333"

}

]

}

})

或いは

var config = {_id: 'testR', members: [

{_id: 1, host: '127.0.0.1:2222'},

{_id: 2, host: '127.0.0.1:3333'}]

}

rs.initiate(config)

>追加

rs.addArb("127.0.0.1:4444")

環境確認

rs.status()

↓結果

{

"set" : "testR",

"date" : ISODate("2013-07-20T15:19:10Z"),

"myState" : 1,

"members" : [

{

"_id" : 1,

"name" : "127.0.0.1:2222",

"health" : 1,

"state" : 1,

"stateStr" : "PRIMARY",

"uptime" : 436,

"optime" : Timestamp(1374333508, 1),

"optimeDate" : ISODate("2013-07-20T15:18:28Z"),

"self" : true

},

{

"_id" : 2,

"name" : "127.0.0.1:3333",

"health" : 1,

"state" : 2,

"stateStr" : "SECONDARY",

"uptime" : 366,

"optime" : Timestamp(1374333508, 1),

"optimeDate" : ISODate("2013-07-20T15:18:28Z"),

"lastHeartbeat" : ISODate("2013-07-20T15:19:10Z"),

"lastHeartbeatRecv" : ISODate("2013-07-20T15:19:10Z"),

"pingMs" : 0,

"syncingTo" : "127.0.0.1:2222"

},

{

"_id" : 3,

"name" : "127.0.0.1:4444",

"health" : 1,

"state" : 7,

"stateStr" : "ARBITER",

"uptime" : 42,

"lastHeartbeat" : ISODate("2013-07-20T15:19:10Z"),

"lastHeartbeatRecv" : ISODate("2013-07-20T15:19:08Z"),

"pingMs" : 0

}

],

"ok" : 1

}

>127.0.0.1:2222が停止

{

"set" : "testR",

"date" : ISODate("2013-07-20T15:20:51Z"),

"myState" : 1,

"members" : [

{

"_id" : 1,

"name" : "127.0.0.1:2222",

"health" : 0,

"state" : 8,

"stateStr" : "(not reachable/healthy)",

"uptime" : 0,

"optime" : Timestamp(1374333508, 1),

"optimeDate" : ISODate("2013-07-20T15:18:28Z"),

"lastHeartbeat" : ISODate("2013-07-20T15:20:50Z"),

"lastHeartbeatRecv" : ISODate("2013-07-20T15:20:24Z"),

"pingMs" : 0

},

{

"_id" : 2,

"name" : "127.0.0.1:3333",

"health" : 1,

"state" : 1,

"stateStr" : "PRIMARY",

"uptime" : 528,

"optime" : Timestamp(1374333508, 1),

"optimeDate" : ISODate("2013-07-20T15:18:28Z"),

"self" : true

},

{

"_id" : 3,

"name" : "127.0.0.1:4444",

"health" : 1,

"state" : 7,

"stateStr" : "ARBITER",

"uptime" : 141,

"lastHeartbeat" : ISODate("2013-07-20T15:20:50Z"),

"lastHeartbeatRecv" : ISODate("2013-07-20T15:20:49Z"),

"pingMs" : 0

}

],

"ok" : 1

}

★Shardingについて

mongod --dbpath D:\mongodb\db --port 2222

mongos --port 3333 --configdb 127.0.0.1:2222

mongod --dbpath D:\mongodb\dbSh1 --port 4444

mongod --dbpath D:\mongodb\dbSh2 --port 5555

mongo 127.0.0.1:3333/admin

db.runCommand({"addshard":"127.0.0.1:4444","allowLocal":true})

db.runCommand({"addshard":"127.0.0.1:5555","allowLocal":true})

db.runCommand({"enablesharding":"test"})

db.runCommand({"shardcollection":"test.person","key":{"name":1}})

大量データを入れた前

db.printShardingStatus()

↓結果

--- Sharding Status ---

sharding version: {

"_id" : 1,

"version" : 3,

"minCompatibleVersion" : 3,

"currentVersion" : 4,

"clusterId" : ObjectId("51ebb8a481549425b79cac30")

}

shards:

{ "_id" : "shard0000", "host" : "127.0.0.1:4444" }

{ "_id" : "shard0001", "host" : "127.0.0.1:5555" }

databases:

{ "_id" : "admin", "partitioned" : false, "primary" : "config" }

{ "_id" : "test", "partitioned" : true, "primary" : "shard0000" }

test.person

shard key: { "name" : 1 }

chunks:

shard0000 1

{ "name" : { "$minKey" : 1 } } -->> { "name" : { "$maxKey" : 1 } } on : shard0000 Timestamp(1, 0)

大量データを入れた後

for(var i=0; i<100000; i++){

db.person.insert({"name":"andy "+i,"age":i})

}

db.printShardingStatus()

↓結果

--- Sharding Status ---

sharding version: {

"_id" : 1,

"version" : 3,

"minCompatibleVersion" : 3,

"currentVersion" : 4,

"clusterId" : ObjectId("51ebb8a481549425b79cac30")

}

shards:

{ "_id" : "shard0000", "host" : "127.0.0.1:4444" }

{ "_id" : "shard0001", "host" : "127.0.0.1:5555" }

databases:

{ "_id" : "admin", "partitioned" : false, "primary" : "config" }

{ "_id" : "test", "partitioned" : true, "primary" : "shard0000" }

test.person

shard key: { "name" : 1 }

chunks:

shard0000 2

shard0001 1

{ "name" : { "$minKey" : 1 } } -->> { "name" : "andy 0"} on : shard0000 Timestamp(2, 1)

{ "name" : "andy 0" } -->> { "name" : "andy 9999" } on : shard0000 Timestamp(1, 3)

{ "name" : "andy 9999" } -->> { "name" : { "$maxKey" : 1 } } on : shard0001 Timestamp(2, 0)

★groupについて

サンプル1

db.person.group({

"key":{"age":true},

"initial":{"person":[]},

"reduce":function(cur,prev){

prev.person.push(cur.name);

}

})

↓結果

[

{

"age" : 27,

"person" : [

"andy",

"jane"

]

},

{

"age" : 28,

"person" : [

"tom"

]

},

{

"age" : 31,

"person" : [

null,

"mike"

]

}

]

サンプル2

db.person.group({

"key":{"age":true},

"initial":{"person":[]},

"reduce":function(cur,prev){

prev.person.push(cur.name);

},

"finalize":function(out){

out.count=out.person.length;

},

"condition":{"age":{$lt:30}}

})

↓結果

[

{

"age" : 27,

"person" : [

"andy",

"jane"

],

"count" : 2

},

{

"age" : 28,

"person" : [

"tom"

],

"count" : 1

}

]

★mapReduceについて

var map = function(){emit(this.age, {count:1})}

var reduce = function(key, value){

var result = {count:0};

for(var i = 0; i < value.length; i++){

result.count += value[i].count;

}

return result;

}

※keyはemitのkeyと同じ、valueはemitのvalueと同じ

db.person.mapReduce(map,reduce,{"out":"collection"})

↓結果

{

"result" : "collection",

"timeMillis" : 461,

"counts" : {

"input" : 5,

"emit" : 5,

"reduce" : 2,

"output" : 3

},

"ok" : 1,

}

db.collection.find()

↓結果

{ "_id" : 27, "value" : { "count" : 2 } }

{ "_id" : 28, "value" : { "count" : 1 } }

{ "_id" : 31, "value" : { "count" : 2 } }

★運用について

●サービス登録

コマンドプロンプトを管理者モードで起動

mongod --dbpath D:\mongodb\db --logpath D:\mongodb\log.txt --port 2222 --install

mongod --dbpath D:\mongodb\db --logpath D:\mongodb\log.txt --port 2222 --auth --reinstall

net start MongoDB

●監視

1.httpによる監視

2.db.serverStatus()

3.mongostatコマンド(リアルタイム監視)

mongostat --port 2222

●認証・認可

mongo 127.0.0.1:2222/admin

> db.addUser("admin","admin")

{

"user" : "admin",

"readOnly" : false,

"pwd" : "7c67ef13bbd4cae106d959320af3f704",

"_id" : ObjectId("51ebc5e9539fe170fffc53f5")

}

> db.addUser("andy","andy",true)

{

"user" : "andy",

"readOnly" : true,

"pwd" : "d09b3fdc22d3f9fea603f98b9ce67120",

"_id" : ObjectId("51ebc638539fe170fffc53f6")

}

> db.auth("admin","admin")

> db.auth("andy","andy")

●バックアップ・回復

1.mongodumpコマンドとmongorestoreコマンド

サービス停止は必要なし

※リアル性が欠ける(メモリに残るデータ)

mongodump --db test

mongorestore --drop

mongodump --port 2222 -d test -o D:\mongodb\backup

mongorestore --port 2222 -d test --drop D:\mongodb\backup\test

2.Master-Slaveにより

3.fsync+lock

リアル性保証(メモリに残るデータをディスクに書き込む)

ロック制御:db.runCommand({"fsync":1,"lock":1})

ロック解除:db.$cmd.unlock.findOne()

★Performance改善

1.遅い処理を調べる: db.setProfilingLevel(1, 100);

2.explain分析、mtoolsでログを分析

3.index作成、Indexes in the Background、Sparse Indexes

4.write(master)とread(slave)を分離