在Windows7环境中构建MongoDB 3.0的副本集
简要概述
我整理了一份在Windows7上创建MongoDB副本集的开发环境和验证步骤。
环境 –
-
- Windows7 (64bit)
- MongoDB 3.0.2
复制的配置
环境建设
目录结构
本次示例中,在D:\dev文件夹下创建了bin文件夹和每个节点对应的conf、db、log文件夹。
D:\dev\mongodb3.0
|
+----- \bin
| |
| +---- \mongod.exe
| +---- \mongo.exe
| +---- \shell_node1.bat (shell_node1.bat~shell_node4.bat)
| +---- \startup_node1.bat (startup_node1.bat~startup_node4.bat)
|
+----- \node1
| |
| +---- \conf\mongod.cfg
| +---- \db
| +---- \log
|
+----- \node2
| |
| +---- \conf\mongod.cfg
| +---- \db
| +---- \log
|
+----- \node3
| |
| +---- \conf\mongod.cfg
| +---- \db
| +---- \log
|
+----- \node4
|
+---- \conf\mongod.cfg
+---- \db
+---- \log
配置文件
我会为每个节点创建一个conf文件。
然后将创建好的conf文件放置在每个节点目录下的conf文件夹中。
这是一个用于node1的配置文件。
systemLog:
destination: file
path: "D:/dev/mongodb3.0/node1/log/mongod.log"
logAppend: true
timeStampFormat: iso8601-local
storage:
dbPath: "D:/dev/mongodb3.0/node1/db"
directoryPerDB: true
journal:
enabled: true
net:
bindIp: 127.0.0.1
port: 30001
setParameter:
enableLocalhostAuthBypass: true
operationProfiling:
slowOpThresholdMs: 100
mode: all
replication:
oplogSizeMB: 128
replSetName: "myReplica"
其他节点将把以下三个地方的值分别用于每个节点的值。
-
- systemLog.path
-
- storage.dbPath
- net.port
准备可执行文件
创建符号链接
创建一个到bin目录的符号链接的exe文件。
> mklink mongod.exe "C:\Program Files\MongoDB\Server\3.0\bin\mongod.exe"
> mklink mongo.exe "C:\Program Files\MongoDB\Server\3.0\bin\mongo.exe"
创建MongoDB启动.bat文件
创建适用于每个节点的MongoDB启动bat文件在bin目录下。
这是用于node1的bat文件。我们将为每个节点创建类似的bat文件。
D:\dev\mongodb3.0\bin\mongod.exe --enableExperimentalIndexStatsCmd --rest --httpinterface --verbose --config D:\dev\mongodb3.0\node1\conf\mongod.cfg
pause
— “httpinterface”是一个选项,可以使浏览器能够查看MongoDB服务器的状态。
将1000添加到MongoDB端口上,并指定该值为端口。
由于node1的端口设为30001,因此httpinterface的端口将为31001。
创建Mongo Shell启动.bat文件
在bin目录下创建用于每个节点的Mongo Shell启动bat文件。
这是用于node1的bat文件。为每个节点创建类似的bat文件。
D:\dev\mongodb3.0\bin\mongo.exe --port 30001 --host localhost --verbose
复制品套装的设置
首先,我們要啟動從node1到node4的MongoDB實例。然後,我們要使用mongo shell登錄到node1作為主要節點。
创建复制套装
在node1上执行以下命令以构建副本集。
> var config = {
_id: 'myReplica',
members: [
{_id:0, host:'localhost:30001', priority:2 },
{_id:1, host:'localhost:30002', priority:1 },
{_id:2, host:'localhost:30003', priority:1 },
{_id:3, host:'localhost:30004', arbiterOnly: true}
],
settings: {
getLastErrorDefaults: {w:2, wtimeout:0},
getLastErrorModes: {}
}
}
> rs.initiate(config)
{ "ok" : 1 }
我会检查复制套装的状态。
> rs.status()
{
"set" : "myReplica",
"date" : ISODate("2015-06-06T03:39:33.374Z"),
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "localhost:30001",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1399,
"optime" : Timestamp(1433553387, 1),
"optimeDate" : ISODate("2015-06-06T01:16:27Z"),
"electionTime" : Timestamp(1433560639, 1),
"electionDate" : ISODate("2015-06-06T03:17:19Z"),
"configVersion" : 2,
"self" : true
},
{
"_id" : 1,
"name" : "localhost:30002",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1336,
"optime" : Timestamp(1433553387, 1),
"optimeDate" : ISODate("2015-06-06T01:16:27Z"),
"lastHeartbeat" : ISODate("2015-06-06T03:39:33.345Z"),
"lastHeartbeatRecv" : ISODate("2015-06-06T03:39:33.316Z"),
"pingMs" : 0,
"lastHeartbeatMessage" : "could not find member to sync from",
"configVersion" : 2
},
{
"_id" : 2,
"name" : "localhost:30003",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 1333,
"optime" : Timestamp(1433553387, 1),
"optimeDate" : ISODate("2015-06-06T01:16:27Z"),
"lastHeartbeat" : ISODate("2015-06-06T03:39:31.898Z"),
"lastHeartbeatRecv" : ISODate("2015-06-06T03:39:32.187Z"),
"pingMs" : 0,
"configVersion" : 2
},
{
"_id" : 3,
"name" : "localhost:30004",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 1330,
"lastHeartbeat" : ISODate("2015-06-06T03:39:32.876Z"),
"lastHeartbeatRecv" : ISODate("2015-06-06T03:39:31.800Z"),
"pingMs" : 0,
"configVersion" : 2
}
],
"ok" : 1
}
MongoDB手册 – 副本集配置
确认数据复制
我們將確認將數據添加到主節點後是否會反映到次要節點。
我将登录主节点并添加测试数据。
> use sample
switched to db sample
> db.test.insert({no:1, desc:"test data"})
WriteResult({ "nInserted" : 1 })
从辅助节点读取数据
如果您想从辅助节点(node2,node3)中引用数据,请执行以下命令进行读取设置。由于这是针对连接的设置,因此每次连接都需要进行设置。
登录到次要节点(node2)。
> db.getMongo().setReadPref('secondaryPreferred')
> use sample
switched to db sample
> show collections
columbo
system.indexes
system.profile
test
> db.test.find()
{ "_id" : ObjectId("5572dcd134829ba85871fcfa"), "no" : 1, "desc" : "test data" }
也可以在每次读取操作时进行设置。
> db.test.find().readPref({mode:'secondaryPreferred'})
{ "_id" : ObjectId("5572dcd134829ba85871fcfa"), "no" : 1, "desc" : "test data" }
在中国,可以使用rs.slaveOk()进行设置,但似乎已经过时了。
设置当前连接的slaveOk属性。已被弃用。使用readPref()和Mongo.setReadPref()来设置读取偏好。
关于阅读设置
MongoDB 手册 – 读优先级参考
复制套件的操作方法
rs.reconfig()既存のレプリカセットを再設定します。Only Primary Noders.add()レプリカセットにメンバーを追加します。Only Primary Noders.remove()レプリカセットからメンバーを除外します。除外するメンバーは事前にシャットダウンしておく必要があります。
rs.addArb()レプリカセットにアービターを追加します。
rs.status()レプリカセットのステータスを出力します。
rs.conf()レプリカセットの現在の設定内容を出力します。
rs.help()ヘルプを出力します。
db.isMaster()mongodインスタンスの役割を表示します。
db.getMongo().getReadPrefMode()現在の読み取り設定を出力します。
db.getMongo().setReadPref()読み取り設定を行います。
MongoDB 手册 – 复制方法
复制确认
关于写作保证
如果对多个节点进行写操作,即使其中一些节点发生错误,也无法撤消之前已经写入的数据。
设置写入保障(Write concern)的示例
未被认可的
writeConcern: { w: 0 }
已经收到。
writeConcern: { w: 1 }
记录
writeConcern: { w: 1, j:true }
复制品已收到确认
writeConcern: { w: 2 }
writeConcern: { w: "majority" }
验证书写保证的操作功能。
从主节点(node1)和两个辅助节点(node2,node3)的状态开始,我们尝试在去掉辅助节点(node3)的情况下,使用以下写入保证({writeConcern:{w:3, wtimeout:5000}})添加文档。
这个设置的意思是“保证在5000毫秒内完成写入至三个节点”,但在这个例子中,由于可用节点不足而导致发生错误。
var a = {no:1, name:"test"}
> db.test.insert(a, {writeConcern:{w:3, wtimeout:5000}})
WriteResult({
"nInserted" : 1,
"writeConcernError" : {
"code" : 64,
"errInfo" : {
"wtimeout" : true
},
"errmsg" : "waiting for replication timed out"
}
})
可能有节点1和节点2写入数据已经完成。
将写入保证更改为{writeConcern:{w:2, wtimeout:5000}},并将文档添加到node1、node2,这样就可以进行写入操作,不会出现错误。
> db.test.insert(a, {writeConcern:{w:2, wtimeout:5000}})
WriteResult({ "nInserted" : 1 })
MongoDB手册-写关注
关于节点的排除和添加
在构建复制集之后,您仍然可以对节点进行排除和添加的操作。
在排除辅助节点后进行操作验证
我们会暂时将一个次要节点从副本集中移除,并确保在其重新加入副本集后,添加到主节点上的数据会自动同步。
在此示例中,暂时排除节点3。
在排除辅助节点(节点3)之前,关闭MongoDB。
> use admin
switched to db admin
> db.shutdownServer()
在主节点(node1)上检查副本集的状态。
> rs.status()
将第三个节点从复制集中排除。
> rs.remove("localhost:30003")
{ "ok" : 1 }
再次检查复制集的状态,确认节点3已被排除。
> rs.status()
在主节点上添加数据。
> db.test.insert({no:3, desc:"before node3 add"})
WriteResult({ "nInserted" : 1 })
启动node3的MongoDB,并将其加入到副本集。
> rs.add("localhost:30003")
{ "ok" : 1 }
通过查看复制集的状态,确认成员中是否添加了node3。
> rs.status()
确认在node3上登录并确认数据已经更新。
> db.test.find({no:3})
{ "_id" : ObjectId("55729c1834829ba85871fcf6"), "no" : 3, "desc" : "before node3 add" }
在排除主节点后进行操作验证
确认排除主节点(node1),并确保次要节点(node2或node3)升级为主节点。然后确认恢复排除的主节点(node1)并与升级的次要节点交换。
关闭主节点(node1)。
> use admin
switched to db admin
> db.shutdownServer()
登录到次要节点(node2),查看副本集的状态,确认剩余节点中有一个变成了主节点。
在这个例子中,假设node2成为了主节点。
> rs.status()
在升级为主节点的node2上添加数据。
> use sample
switched to db admin
> db.test.insert({no:2, desc:"inset data from node2"})
WriteResult({ "nInserted" : 1 })
启动node1上的MongoDB,并查看复制集的状态以确认node1已经恢复为主节点。
> rs.status()
我们将确认在node2中添加的数据。
> db.test.find()
{ "_id" : ObjectId("5572dcd134829ba85871fcfa"), "no" : 1, "desc" : "test data" }
{ "_id" : ObjectId("5572e07ab6e83d84b2e82956"), "no" : 2, "desc" : "inset data from node2" }
参考网站
我参考了下面的网站。
-
- MongoDB manual – replication
-
- gihyo.jp – 第4回 MongoDBのレプリケーションを構築してみよう
- gihyo.jp – 第6回 レプリケーション+シャーディングでMongoDBをもっと使いこなす