基於 MongoDB 正式環境的一些基本要求,應該是要用三台機器來測試 MongoDB,但為了測試 mongodb driver 的 cluster 機制,又沒有那麼多實體的機器,這次先用單機來了解 client 由遠端連接 MongoDB 的一些狀況。
環境設定
一個由三個 replica set 組成的 shard server,三個 config server,三個 route server。
shard1: 3 replica sets
192.168.1.11:27017
192.168.1.11:28017
192.168.1.11:29017
3 config server
192.168.1.11:30000
192.168.1.11:31000
192.168.1.11:32000
3 route server
192.168.1.11:40000
192.168.1.11:41000
192.168.1.11:42000
shard1 的設定以及啟動:
mkdir -p /home/mongodb/shard/data/s1_1
mkdir -p /home/mongodb/shard/data/s1_2
mkdir -p /home/mongodb/shard/data/s1_3
mkdir -p /home/mongodb/shard/logs
/usr/share/mongodb/bin/mongod --port 27017 --fork --dbpath /home/mongodb/shard/data/s1_1 --logpath /home/mongodb/shard/logs/s1_1.log --logappend --shardsvr --replSet shard1 --directoryperdb
/usr/share/mongodb/bin/mongod --port 28017 --fork --dbpath /home/mongodb/shard/data/s1_2 --logpath /home/mongodb/shard/logs/s1_2.log --logappend --shardsvr --replSet shard1 --directoryperdb
/usr/share/mongodb/bin/mongod --port 29017 --fork --dbpath /home/mongodb/shard/data/s1_3 --logpath /home/mongodb/shard/logs/s1_3.log --logappend --shardsvr --replSet shard1 --directoryperdb
連接其中一台,並設定 shard1 的三個 replica set 成員
mongo --port 27017
config_shard1={
_id: 'shard1',
members: [
{_id:0, host:'192.168.1.11:27017'},
{_id:1, host:'192.168.1.11:28017'},
{_id:2, host:'192.168.1.11:29017'}
]
};
rs.initiate(config_shard1);
rs.status();
rs.isMaster();
建立管理帳號 admin 以及連接 test database 的測試帳號 test
db.createUser({
user: "admin",
pwd: "pass",
roles: [ { role: "root", db: "admin" } ]
});
use test
db.createUser(
{
user: "test",
pwd: "pass",
roles: [
{ role: "readWrite", db: "test" }
]
}
);
db.getUsers();
啟動三個 config servers
mkdir -p /home/mongodb/shard/data/config1
mkdir -p /home/mongodb/shard/data/config2
mkdir -p /home/mongodb/shard/data/config3
/usr/share/mongodb/bin/mongod --configsvr --fork --port 30000 --dbpath /home/mongodb/shard/data/config1 --logpath /home/mongodb/shard/logs/config1.log --logappend
/usr/share/mongodb/bin/mongod --configsvr --fork --port 31000 --dbpath /home/mongodb/shard/data/config2 --logpath /home/mongodb/shard/logs/config2.log --logappend
/usr/share/mongodb/bin/mongod --configsvr --fork --port 32000 --dbpath /home/mongodb/shard/data/config3 --logpath /home/mongodb/shard/logs/config3.log --logappend
啟動三個 route servers
/usr/share/mongodb/bin/mongos --port 40000 --configdb 192.168.1.11:30000,192.168.1.11:31000,192.168.1.11:32000 --fork --logpath /home/mongodb/shard/logs/route1.log --logappend --chunkSize 1
/usr/share/mongodb/bin/mongos --port 41000 --configdb 192.168.1.11:30000,192.168.1.11:31000,192.168.1.11:32000 --fork --logpath /home/mongodb/shard/logs/route2.log --logappend --chunkSize 1
/usr/share/mongodb/bin/mongos --port 42000 --configdb 192.168.1.11:30000,192.168.1.11:31000,192.168.1.11:32000 --fork --logpath /home/mongodb/shard/logs/route3.log --logappend --chunkSize 1
連接到 route server,設定 shard1 並設定 sharding 的 database
mongo --host 192.168.1.11 --port 40000
use admin
db.runCommand({addshard:"shard1/192.168.1.11:27017,192.168.1.11:28017,192.168.1.11:29017"});
db.runCommand({enablesharding:"test"});
db.runCommand({shardcollection:"test.users", key:{_id:1}});
db.runCommand({shardcollection:"test.doc", key:{_id:1}});
直接測試新增 500000 筆資料
for(var i=1;i<500000; i++) {
db.users.insert({
userid:"user_"+i,
username:"name_"+i,
age: NumberInt(_rand()*100)
})
}
use test
db.users.stats();
MongoDB Client Drivers
MongoDB 官方提供的 client driver libary 很完整地支援了多種語言:C, C++, C#, Java, Node.js, Perl, PHP, Python, Motor, Ruby, Scala,另外有兩個社群提供的 driver:Go, Erlang。
使用 driver 之前,最重要的是知道連接 MongoDB 的 connection string。
格式為:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
參考 node.js 的 mongoclient 說明頁面,有比較完整的 options 的設定項目。
因為我們建立了三個 route server,因此連線的 uri 填寫為以下的 connection string。
mongodb://192.168.1.11:40000,192.168.1.11:41000,192.168.1.11:42000/test?maxPoolSize=20
我們就利用 scala driver 的 QuickTour Sample,記得要同時把 Helpers.scala 以及 QuickTour.scala 都取回來編譯。
首先建立一個 scala sbt project,然後在 build.sbt 裡面加上一行 mongodb scala driver,接下來把剛剛的 Helper.scala 及 QuickTour.scala 放進 scala soruce 裡面,就可以了。
name := "mongodb"
version := "1.0"
scalaVersion := "2.11.7"
libraryDependencies += "org.mongodb.scala" %% "mongo-scala-driver" % "1.0.0"
接下來只擷取部份的程式碼,也就是我們修改的部份:
首先我們修改 mongodb 的 connection string,連接到三個 route server
val mongoClient:MongoClient = MongoClient("mongodb://192.168.1.11:40000,192.168.1.11:41000,192.168.1.11:42000/test?maxPoolSize=20")
剛剛我們把 database:test, collection: doc 加入 shardcollection 中
// get handle to "mydb" database
val database: MongoDatabase = mongoClient.getDatabase("test")
// get a handle to the "test" collection
val collection: MongoCollection[Document] = database.getCollection("doc")
然後是清除 collection,並測試插入一筆資料
collection.drop().results()
// make a document and insert it
val doc: Document = Document("_id" -> 0, "docid" -> "test", "type" -> "database",
"count" -> 1, "page" -> Document("x" -> 100, "y" -> 200))
collection.insertOne(doc).results()
// get it (since it's the only one in there since we dropped the rest earlier on)
collection.find.first().printResults()
讓 Thread 暫停 30 秒,因為我們想要測試在執行到一半,把其中一台 route server 關掉的狀況。
Thread sleep 30*1000
當我們執行 QuickTour.scala 的時候,console 會列印以下的資訊:
資訊: Monitor thread successfully connected to server with description ServerDescription{address=192.168.1.11:41000, type=SHARD_ROUTER, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 0, 7]}, minWireVersion=0, maxWireVersion=3, electionId=null, maxDocumentSize=16777216, roundTripTimeNanos=39787239}
十一月 20, 2015 5:25:53 下午 com.mongodb.diagnostics.logging.JULLogger log
資訊: Opened connection [connectionId{localValue:4}] to 192.168.1.11:40000
十一月 20, 2015 5:25:53 下午 com.mongodb.diagnostics.logging.JULLogger log
資訊: Opened connection [connectionId{localValue:5}] to 192.168.1.11:42000
{ "_id" : 0, "name" : "MongoDB", "type" : "database", "count" : 1, "axis" : { "x" : 100, "y" : 200 } }
這時候程式會因為 Thread sleep 30*1000 而暫停下來。
接下來有30s 的時間,可以連線到 port 40000 的 route server,並把這個 route server 關掉。
mongo --port 40000
use admin
db.shutdownServer();
當我們把 route server 關掉的瞬間,scala 程式的 console 就會馬上發現,192.168.1.11:40000 這個 route server 現在有問題,沒辦法使用了。
十一月 20, 2015 5:26:04 下午 com.mongodb.diagnostics.logging.JULLogger log
資訊: Exception in monitor thread while connecting to server 192.168.1.11:40000
com.mongodb.MongoException: java.io.IOException: 遠端電腦拒絕網路連線。
at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:125)
at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:141)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: 遠端電腦拒絕網路連線。
at sun.nio.ch.Iocp.translateErrorToIOException(Iocp.java:309)
at sun.nio.ch.Iocp.access$700(Iocp.java:46)
at sun.nio.ch.Iocp$EventHandlerTask.run(Iocp.java:399)
... 1 more
接下來的程式中,當我們要繼續使用 mongodb,client driver 會自動選擇下一個 route server: 192.168.1.11:41000,然後繼續執行後面的程式。
十一月 20, 2015 5:26:23 下午 com.mongodb.diagnostics.logging.JULLogger log
資訊: Opened connection [connectionId{localValue:8}] to 192.168.1.11:41000
total # of documents after inserting 100 small ones (should be 101): 101
MongoDB 的 driver 真的做得很完整,不但有內建 connection pool 還有自動 fail over 的能力。
沒有留言:
張貼留言