mongodb 2.4 不同server节点的replica set 搭建过程(一)
Mongodb支持在多个机器中通过异步复制达到故障转移和实现冗余,多机器之间同一时刻只有一台是用于写操作,正是由于这个特性,为mongodb提供了数据一致性的保证,担当primary角色的机器能把读操作分发给slave
Mongodb高可用分两种:
Master-slave 主从复制
只需要在某一个服务启动时加上--master参数,而另外一个服务加上-slave与-source参数,即可实现同步,mongodb的最新版本已经不在支持此方案了
Replica sets 复制集:
Mongodb是从1.6版本开发了新功能replica sets,这个比master-slave功能更加强大一些,增加了故障自动切换和自动修复成员节点,各个DB之间的数据完全一致,大大降低了维护成本。Auto shared已经明确说明不在支持replication paris,建议使用replica set,replica set故障切换完全自动化
假设一个三节点的mongodb集群
三个节点server-1、-2、-3无论哪一个节点出现故障,其他节点马上会将业务接转过来而无需停机操作
主要学习replica set 复制集
replica set可以实现自动的failover和自动的recovery。
replica set由两个或者更多的节点组成,实现彼此的复制。
replica set自动选择primary节点,没有一个节点是固定的primary。
mongos会自动发现一个replica set的primary节点发生变化,并将写操作发送给这个新的primary节点。
通常用于下面几个场景
数据冗余。
自动failover,提供高可用性的服务。
分散读的负载。
简化维护(相对于master-slave来说)。
灾难恢复。
首先还是启动mongod,用于replica set的参数有两个:
--replSet
--oplogSize
Mongodb的版本:
[root@anenjoy mongodb]# /usr/local/mongodb/bin/mongo -version
MongoDB shell version: 2.4.8
实验中三台虚拟机的IP:
192.168.1.247
192.168.1.248
192.168.1.250
先在各个server主机上搭建mongodb的安装,配置存储路径
安装就是解压包,不再细述
第三步:启动mongodb
命令参数:
SERVER -1
/usr/local/mongodb/bin/mongod --port 27017 --replSet res1 --keyFile /data/mon_db/key/res1 --oplogSize 100 --dbpath=/data/mon_db/res1/ --logpath=/usr/local/mongodb/log/mongodb.log --logappend --fork
参数详解:--port 是端口号
--replSet 是replica set的标识参数,后跟set名称
--keyFile 就是标识进群的私钥文件
--oplogSize replica操作的日志,是可以crapped collection,可循环使用的,大小100MB
--dbpath 数据文件的存储路径
--logpath 日志文件路径 --logappend是日志追加
--fork 后台运行程序
SERVER -2
/usr/local/mongodb/bin/mongod --port 27018 --replSet res1 --keyFile /data/mon_db/key/res2 --oplogSize 100 --dbpath=/data/mon_db/res2/ --logpath=/usr/local/mongodb/log/mongodb.log --logappend --fork
SERVER -3
/usr/local/mongodb/bin/mongod --port 27019 --replSet res1 --keyFile /data/mon_db/key/res3 --oplogSize 100 --dbpath=/data/mon_db/res3/ --logpath=/usr/local/mongodb/log/mongodb.log --logappend --fork
各自启动,注意实时观察log文件的变化,看是否有问题产生(tail mongodb.log -f)
如果遇到error信息:
[rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG)
表示你还没有执行初始化,这个暂时不用考虑
第四步:初始化
登录任意一台server的mongodb数据库
[root@test02 bin]# /usr/local/mongodb/bin/mongo --port 27017
MongoDB shell version: 2.4.8
connecting to: 127.0.0.1:27017/test
>
配置初始化文件
config_res1={_id:'res1',members:[
{_id:0,host:'192.168.1.248:27017',priority:2},
{_id:1,host:'192.168.1.247:27018',priority:0}
{_id:2,host:'192.168.1.250:27019',priority:1}]
}
"_id" : "res1",
"members" : [
{
"_id" : 0,
"host" : "192.168.1.248:27017",
"priority" : 2
},
{
"_id" : 1,
"host" : "192.168.1.247:27018",
"priority" : 0
},
{
"_id" : 2,
"host" : "192.168.1.250:27019",
"priority" : 1
}
]
}
Priority 优先级,值越大,表示是primary,当primary宕机时,就会使用priority 值次之的当primary 角色
> rs.initiate(config_res1);
{
"info" : "Config now saved locally. Should come online in about a minute.",
"ok" : 1
}
_id:'res1'这个_id:的值必须是你set集合的名称,就是--replSet的集合名称,否则就是提示你
Error message 信息
"errmsg" : "couldn't initiate : set name does not match the set name host 192.168.1.247:27018 expects"
之后查看状态
rs.status();
{
"set" : "res1", ###set 集名称
"date" : ISODate("2013-12-04T00:37:08Z"), 创建日期
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "192.168.1.248:27017",
"health" : 1, 1表示正常访问,0异常
"state" : 1, 1表示是primary ,2表示secondary
"stateStr" : "PRIMARY", primary 主库
"uptime" : 1632,
"optime" : Timestamp(1386116964, 1),
"optimeDate" : ISODate("2013-12-04T00:29:24Z"),
"self" : true
},
{
"_id" : 1,
"name" : "192.168.1.247:27018",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 461,
"optime" : Timestamp(1386116964, 1),
"optimeDate" : ISODate("2013-12-04T00:29:24Z"),
"lastHeartbeat" : ISODate("2013-12-04T00:37:07Z"),
"lastHeartbeatRecv" : ISODate("2013-12-04T00:37:07Z"),
"pingMs" : 0,
"syncingTo" : "192.168.1.248:27017"
},
{
"_id" : 2,
"name" : "192.168.1.250:27019",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 461,
"optime" : Timestamp(1386116964, 1),
"optimeDate" : ISODate("2013-12-04T00:29:24Z"),
"lastHeartbeat" : ISODate("2013-12-04T00:37:08Z"),
"lastHeartbeatRecv" : ISODate("2013-12-04T00:37:08Z"),
"pingMs" : 1,
"syncingTo" : "192.168.1.248:27017"
}
],
"ok" : 1
}
同步好信息之后,查看另外两个mongodb的日志,就会发现
Fri Dec 6 15:48:48.380 [conn33] end connection 192.168.1.247:25633 (1 connection now open)
Fri Dec 6 15:48:48.381 [initandlisten] connection accepted from 192.168.1.247:25635 #35 (2 connections now open)
Fri Dec 6 15:48:48.383 [conn35] authenticate db: local { authenticate: 1, nonce: "6d6fb8a5d540c164", user: "__system", key: "51b0f27144ec17860f1ca2bd245807ce" }
表示正常的
也可以使用
res1:PRIMARY> rs.isMaster();查看replica set的信息
{
"setName" : "res1",
"ismaster" : true,
"secondary" : false,
"hosts" : [
"192.168.1.248:27017",
"192.168.1.250:27019"
],
"passives" : [
"192.168.1.247:27018"
],
"primary" : "192.168.1.248:27017",
"me" : "192.168.1.248:27017",
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"localTime" : ISODate("2013-12-04T00:42:57.347Z"),
"ok" : 1
Replica set的配置文件,也可以用来更改、增加节点信息
res1:PRIMARY> rs.conf();
{
"_id" : "res1",
"version" : 1,
"members" : [
{
"_id" : 0,
"host" : "192.168.1.248:27017",
"priority" : 2
},
{
"_id" : 1,
"host" : "192.168.1.247:27018",
"priority" : 0
},
{
"_id" : 2,
"host" : "192.168.1.250:27019"
}
]
}
以上步骤,就是replica set的一个搭建的过程,接下来就是操作和验证
五:主从操作的oplog日志
Mongodb的replica set架构是通过一个日志来存储写操作的,这个日志就是'oplog'。Oplog是一个固定长度的capped collection,它存放于local数据库下,用于记录replica sets的操作记录。Oplog的日志大小是可以调整的,就在我们启动的时候使用--oplogSize 参数指定的,单位是MB
res1:PRIMARY> show dbs;
admin (empty)
local 0.203125GB (有oplog的collection,是有数据的)
先在primary上创建库,secondary是无法读写操作的(等下可以解决读的问题)
Use test1
db.appstore.save({'e_name':'frank','e_id':1101,'class_id':1});
db.appstore.find();
{ "_id" : ObjectId("529e7c88d4d317e4bd3eece9"), "e_name" : "frank", "e_id" : 1101, "class_id" : 1 }
之后,你会看到另外两台mongodb的log日志的变化,有追加:
Fri Dec 6 15:56:22.338 [FileAllocator] allocating new datafile /data/mon_db/res2/test1.ns, filling with zeroes...
Fri Dec 6 15:56:22.474 [FileAllocator] done allocating datafile /data/mon_db/res2/test1.ns, size: 16MB, took 0.136 secs
Fri Dec 6 15:56:22.474 [FileAllocator] allocating new datafile /data/mon_db/res2/test1.0, filling with zeroes...
Fri Dec 6 15:56:23.850 [FileAllocator] done allocating datafile /data/mon_db/res2/test1.0, size: 64MB, took 1.376 secs
Fri Dec 6 15:56:23.852 [repl writer worker 1] build index test1.appstore { _id: 1 }
Fri Dec 6 15:56:23.852 [FileAllocator] allocating new datafile /data/mon_db/res2/test1.1, filling with zeroes...
Fri Dec 6 15:56:23.853 [repl writer worker 1] build index done. scanned 0 total records. 0 secs
Fri Dec 6 15:56:27.006 [FileAllocator] done allocating datafile /data/mon_db/res2/test1.1, size: 128MB, took 3.153 secs
Fri Dec 6 15:56:27.007 [rsSyncNotifier] repl: old cursor isDead, will initiate a new one
如果想在secondary上查看数据,默认情况下:
[root@test04 ~]# /usr/local/mongodb/bin/mongo --port 27018
MongoDB shell version: 2.4.8
connecting to: 127.0.0.1:27018/test
res1:SECONDARY> show dbs;show dbs;
admin (empty)
local 0.203125GB
test1 0.203125GB
Ok,可以看到我们刚创建的test1库,
res1:SECONDARY> use test1;
switched to db test1
res1:SECONDARY> show collections;
Fri Dec 6 15:59:10.758 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:128
OK,提示error
解决办法:
res1:SECONDARY> db.getMongo().setSlaveOk(); (自带的函数)
res1:SECONDARY> show collections;show collections;
appstore
System.indexes
res1:SECONDARY> db.appstore.find();db.appstore.find();
{ "_id" : ObjectId("529e7c88d4d317e4bd3eece9"), "e_name" : "frank", "e_id" : 1101, "class_id" : 1 }
如果说你想写数据,就会提示 not master
db.appstore.insert({'e_name':1102,'e_id':1102});
not master
OK.这样就可以实现读写的分离
怎样查看oplog的日志
use local;
show collections;
oplog.rs
slaves
startup_log
system.indexes
System.replset
就是查看oplog.rs collection
res1:PRIMARY> db.oplog.rs.find();
{ "ts" : Timestamp(1386116964, 1), "h" : NumberLong(0), "v" : 2, "op" : "n", "ns" : "", "o" : { "msg" : "initiating set" } }
{ "ts" : Timestamp(1386118280, 1), "h" : NumberLong("8972935208244346897"), "v" : 2, "op" : "i", "ns" : "test1.appstore", "o" : { "_id" : ObjectId("529e7c88d4d317e4bd3eece9"), "e_name" : "frank", "e_id" : 1101, "class_id" : 1 } }
相关解释:
Ts 表示某个操作的时间戳
Op:表示操作类型,一般包括
I insert 插入
D delete 删除
Uupdate 更新
Ns 命名空间,也就是你操作的collection name名
O document(文档),就是你插入的数据信息
查看Mster上的oplog元数据信息:
res1:PRIMARY> db.printReplicationInfo();
configured oplog size: 100MB
log length start to end: 1316secs (0.37hrs)
oplog first event time: Wed Dec 04 2013 08:29:24 GMT+0800 (CST)
oplog last event time: Wed Dec 04 2013 08:51:20 GMT+0800 (CST)
now: Wed Dec 04 2013 09:14:20 GMT+0800 (CST)
Oplog size 是你oplog 的总大小,是可循环的
log length start to end oplog日志的启用时间段,单位 秒
oplog first event time 第一个事务产生的时间
oplog last event time 最后一个事务产生的时间
Now现在的时间
查看slave的数据同步状态
res1:PRIMARY> db.printSlaveReplicationInfo();
source: 192.168.1.247:27018
syncedTo: Wed Dec 04 2013 08:51:20 GMT+0800 (CST)
= 1620 secs ago (0.45hrs)
source: 192.168.1.250:27019
syncedTo: Wed Dec 04 2013 08:51:20 GMT+0800 (CST)
= 1620 secs ago (0.45hrs)
Source:slave的IP和端口信息
SyncedTo:目前的同步情况,延迟了多久等信息
在local数据库内,不仅有oplog的集合,还有一个集合是记录set 配置信息
db.system.replset.find();
或者是 rs.conf() 都可以查看到
以上步骤是replica set的搭建过程和相关的查看语句,如有不足之处,还请指点
replica set 节点的增、删、改和故障切换参考:http://1413570.blog.51cto.com/1403570/1337622