系统:centos6.5
IP:10.19.21.244 主节点
10.19.21.245 备节点
10.19.21.248 仲裁点
不只是主节点、副本节点、仲裁节点,还有Secondary-Only、Hidden、Delayed、Non-Voting。
Secondary-Only:不能成为primary节点,只能作为secondary副本节点,防止一些性能不高的节点成为主节点。
Hidden:这类节点是不能够被客户端制定IP引用,也不能被设置为主节点,但是可以投票,一般用于备份数据。
Delayed:可以指定一个时间延迟从primary节点同步数据。主要用于备份数据,如果实时同步,误删除数据马上同步到从节点,恢复又恢复不了。
Non-Voting:没有选举权的secondary节点,纯粹的备份数据节点。
三台主机安装mongodb
下载mongodb wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.9.tgz 解压到目录 tar xf mongodb-linux-x86_64-2.6.9.tgz -C /usr/local/src 更改名 mv mongodb-linux-x86_64-2.6.9 /usr/local/mongodb cd /usr/local/mongodb/ 创建数据目录和日志目录 mkdir -p data log 创建用户 useradd mongodb -s /sbin/nologin 更改目录属主属组 chown mongod:mongodb /usr/local/mongodb -R 更改环境变量 vim ~/.bash_profile PATH=$PATH:/usr/local/mongodb/bin source ~/.bash_profile
配置文件 vim /etc/mongodb.conf port = 27017 fork = true logpath = /usr/local/mongodb/log/mongodb.log dbpath =/usr/local/mongodb/data/ journal = true #以目录的形式存数据,如果已经存在,修改此配置会导致原始数据消失(注释次参数会回来),除非迁移现有数据文件到directoryperdb所产生的数据目录中。 directoryperdb=true #日志增加形式写入 logappend=true #配置副本集,指定副本名称作为参数,所有主机都必须有相同名称作为同一个副本集 replSet=testrs #使用预分配方式来保证写入性能的稳定,预分配在后台进行,并且每个预分配的文件都用0进行填充。这会让MongoDB始终保持额外的空间和空余的数据文件,从而避免了数据增长过快而带来的分配磁盘空间引起的阻塞。设置noprealloc= true来禁用预分配的数据文件,会缩短启动时间,但在正常操作过程中,可能会导致性能显著下降。 noprealloc=true
启动服务 mongod -f /etc/mongodb.conf
首先连接主节点 mongo > use admin > conf = {_id:"testrs",members:[{_id:0,host:"10.19.21.244:27017",priority:2},{_id:1,host:"10.19.21.245:27017",priority:1},{_id:2,host:"10.19.21.248:27017",arbiterOnly:true}]}; { "_id" : "testrs", "version" : 1, "members" : [ { "_id" : 0, "host" : "10.19.21.244:27017", "priority" : 2 }, { "_id" : 1, "host" : "10.19.21.245:27017" }, { "_id" : 2, "host" : "10.19.21.248:27017", "arbiterOnly" : true } ] } 注意最初的_id的值就是我们配置文件中设定的replSet的值,arbiterOnly是大写的O,配置完成后进行初始化: > rs.initiate(conf) { "info" : "Config now saved locally. Should come online in about a minute.", "ok" : 1 } 此步骤必须备节点和仲裁节点的mongo启动,不然无法执行此步骤。
> rs.status() { "set" : "testrs", "date" : ISODate("2015-05-07T11:55:17Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "10.19.21.244:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 5737, "optime" : Timestamp(1430995665, 1), "optimeDate" : ISODate("2015-05-07T10:47:45Z"), "electionTime" : Timestamp(1430993992, 1), "electionDate" : ISODate("2015-05-07T10:19:52Z"), "self" : true }, { "_id" : 1, "name" : "10.19.21.245:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 3077, "optime" : Timestamp(1430995665, 1), "optimeDate" : ISODate("2015-05-07T10:47:45Z"), "lastHeartbeat" : ISODate("2015-05-07T11:55:17Z"), "lastHeartbeatRecv" : ISODate("2015-05-07T11:55:17Z"), "pingMs" : 0, "syncingTo" : "10.19.21.244:27017" }, { "_id" : 2, "name" : "10.19.21.248:27017", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 5735, "lastHeartbeat" : ISODate("2015-05-07T11:55:17Z"), "lastHeartbeatRecv" : ISODate("2015-05-07T11:55:17Z"), "pingMs" : 0 } ], "ok" : 1 }
> use test 插入数据 > db.testdb.insert({"tset1":"i'm master"})
然后到备份节点查看数据是否有 mongo 10.19.21.245 testrs:SECONDARY> use test switched to db test testrs:SECONDARY> show tables; 2015-05-07T19:57:29.670+0800 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:131 需要进行配置 testrs:SECONDARY> db.setSlaveOk() testrs:SECONDARY> show tables; system.indexes testdb testrs:SECONDARY> db.testdb.find() { "_id" : ObjectId("554a4ee4eb804a0f1b6ec347"), "test1" : "i'm master" }
停止主节点,查看整个集群状态 testrs:PRIMARY> rs.status() { "set" : "testrs", "date" : ISODate("2015-05-07T11:59:42Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "10.19.21.244:27017", "health" : 0, "state" : 8, "stateStr" : "(not reachable/healthy)", "uptime" : 0, "optime" : Timestamp(1430995665, 1), "optimeDate" : ISODate("2015-05-07T10:47:45Z"), "lastHeartbeat" : ISODate("2015-05-07T11:59:40Z"), "lastHeartbeatRecv" : ISODate("2015-05-07T11:59:32Z"), "pingMs" : 0 }, { "_id" : 1, "name" : "10.19.21.245:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 3342, "optime" : Timestamp(1430995665, 1), "optimeDate" : ISODate("2015-05-07T10:47:45Z"), "electionTime" : Timestamp(1430999976, 1), "electionDate" : ISODate("2015-05-07T11:59:36Z"), "self" : true }, { "_id" : 2, "name" : "10.19.21.248:27017", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 3340, "lastHeartbeat" : ISODate("2015-05-07T11:59:42Z"), "lastHeartbeatRecv" : ISODate("2015-05-07T11:59:41Z"), "pingMs" : 0 } ], "ok" : 1 }
主节点已切换过来,此时备节点已经变成了主节点。再插入一条数据 testrs:PRIMARY> db.testdb.insert({"test2":"i'm new master"}) testrs:PRIMARY> db.testdb.find(); { "_id" : ObjectId("554a4ee4eb804a0f1b6ec347"), "test1" : "i'm master" } { "_id" : ObjectId("554a505d494f70c600422b41"), "test2" : "i'm new master" }
重启原来的主节点查看状态 testrs:SECONDARY> rs.status() { "set" : "testrs", "date" : ISODate("2015-05-07T14:00:33Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "10.19.21.244:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 15, "optime" : Timestamp(1430995665, 1), "optimeDate" : ISODate("2015-05-07T10:47:45Z"), "electionTime" : Timestamp(1431007222, 1), "electionDate" : ISODate("2015-05-07T14:00:22Z"), "self" : true }, { "_id" : 1, "name" : "10.19.21.245:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 13, "optime" : Timestamp(1430995665, 1), "optimeDate" : ISODate("2015-05-07T10:47:45Z"), "lastHeartbeat" : ISODate("2015-05-07T14:00:32Z"), "lastHeartbeatRecv" : ISODate("2015-05-07T14:00:33Z"), "pingMs" : 0, "lastHeartbeatMessage" : "syncing to: 10.19.21.244:27017", "syncingTo" : "10.19.21.244:27017" }, { "_id" : 2, "name" : "10.19.21.248:27017", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 13, "lastHeartbeat" : ISODate("2015-05-07T14:00:32Z"), "lastHeartbeatRecv" : ISODate("2015-05-07T14:00:33Z"), "pingMs" : 0 } ], "ok" : 1 }
查看数据是否同步过来 testrs:PRIMARY> use test switched to db test testrs:PRIMARY> db.testdb.find() { "_id" : ObjectId("554a4ee4eb804a0f1b6ec347"), "test1" : "i'm master" } { "_id" : ObjectId("554a505d494f70c600422b41"), "test2" : "i'm new master" }
向集群中增加节点 cfg = rs.conf() cfg.members[3] = {_id:3,host:"10.19.21.246:27017",priority:0.5} rs.reconfig(cfg) 如果备份节点无法读取数据,需要设置db.setSlaveOK()。如果备份节点可读但不可写,修改优先级 cfg = rs.conf() cfg.members[0].priority = 0.5 cfg.members[1].priority = 2 cfg.members[2].priority = 2 rs.reconfig(cfg) 需要 reconfig后配置才能生效。
php与mongodb连接 <?php $options = array( 'replicaSet' => 'testrs', 'readPreference' => 'secondaryPreferred', ); $m = new MongoClient("mongodb://10.19.21.244:27017,10.19.21.245:27017/", $options); foreach ( $m->getConnections() as $c ) { echo $c['hash'], ":\n", " - {$c['connection']['connection_type_desc']}, ", "{$c['connection']['ping_ms']} ms\n"; } ?>
primary:默认参数,只从主节点上进行读取操作;
primaryPreferred:大部分从主节点上读取数据,只有主节点不可用时从secondary节点读取数据。
secondary:只从secondary节点上进行读取操作,存在的问题是secondary节点的数据会比primary节点数据“旧”。
secondaryPreferred:优先从secondary节点进行读取操作,secondary节点不可用时从主节点读取数据;
nearest:不管是主节点、secondary节点,从网络延迟最低的节点上读取数据。