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 setreplica set故障切换完全自动化

假设一个三节点的mongodb集群

三个节点server-1-2-3无论哪一个节点出现故障,其他节点马上会将业务接转过来而无需停机操作

主要学习replica set 复制集

replica set可以实现自动的failover和自动的recovery

replica set由两个或者更多的节点组成,实现彼此的复制。

replica set自动选择primary节点,没有一个节点是固定的primary

mongos会自动发现一个replica setprimary节点发生变化,并将写操作发送给这个新的primary节点。

通常用于下面几个场景

数据冗余。

自动failover,提供高可用性的服务。

分散读的负载。

简化维护(相对于master-slave来说)。

灾难恢复。

首先还是启动mongod,用于replica set的参数有两个:

--replSet <setname>,复制集的名称。

--oplogSize <MB>,操作日志的大小,单位为MB。(一般是磁盘空间的5%);

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)

表示你还没有执行初始化,这个暂时不用考虑

第四步:初始化

登录任意一台servermongodb数据库

[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日志

Mongodbreplica set架构是通过一个日志来存储写操作的,这个日志就是‘oplog’。Oplog是一个固定长度的capped collection,它存放于local数据库下,用于记录replica sets的操作记录。Oplog的日志大小是可以调整的,就在我们启动的时候使用--oplogSize  参数指定的,单位是MB

res1:PRIMARY> show dbs;

admin   (empty)

local   0.203125GB (有oplogcollection,是有数据的)

先在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 }

之后,你会看到另外两台mongodblog日志的变化,有追加:

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)

SourceslaveIP和端口信息

SyncedTo:目前的同步情况,延迟了多久等信息

local数据库内,不仅有oplog的集合,还有一个集合是记录set 配置信息

db.system.replset.find();

或者是 rs.conf() 都可以查看到

以上步骤是replica set的搭建过程和相关的查看语句,如有不足之处,还请指点

replica set 节点的增、删、改和故障切换参考: