mongodb之replSet复制集

复制集是一个带有故障转移的主从集群。是从现有的主从模式演变而来,增加了自动故障转移和节点成员自动恢复。

复制集模式中没有固定的主结点,在启动后,多个服务节点间将自动选举产生一个主结点。该主结点被称为primary,一个或多个从结点被称为secondaries。primary结点基本上就是master结点,不同之处在于primary结点在不同时间可能是不同的服务器。如果当前的主结点失效了,复制集中的其余结点将会试图选出一个新的主结点。

复制集模式的好处是,一切自动化。首先,复制集模式本身做了大量的管理工作,自动管理从节点,确保数据不会不一致。其次,主节点挂掉后,会自动判断集群中的服务器并进行故障转移,推举新的主节点。一个复制集集群支持1-7台服务器,在一个复制集中各个服务器数据保持完全一致。


在一个复制集集群中,各个服务器有以下几种状态:

Primary 主节点,一个复制集有且仅有一台服务器处于Primary状态,只有主节点才对外提供读写服务。如果主节点挂掉,复制集将会投票选出一个备用节点成为新的主节点。

Secondary 备用节点,复制集允许有多台Secondary,每个备用节点的数据与主节点的数据是完全同步的。

Recovering 恢复中,当复制集中某台服务器挂掉或者掉线后数据无法同步,重新恢复服务后从其他成员复制数据,这时就处于恢复过程,数据同步后,该节点又回到备用状态。

Arbiter 仲裁节点,该类节点可以不用单独存在,如果配置为仲裁节点,就主要负责在复本集中监控其他节点状态,投票选出主节点。该节点将不会用于存放数据。如果没有仲裁节点,那么投票工作将由所有节点共同进行。

Down 无效节点,当服务器挂掉或掉线时就会处于该状态。

复制集的从节点读请求,也是在各个Driver层设置slaveOk的值来实现的。


操作系统环境如下:

OS:Centos6.4 64bit
IP:192.168.33.131

此次操作均在同一台机器上操作,安装mongodb请参考mongodb2.6安装编,然后建立复制集相对应的目录以及log日志文件等等

1:目录规划如下:

[root@localhost opt]# pwd
/opt
[root@localhost opt]# tree .
.
├── logs
├── rs0
├── rs1
└── rs2
4 directories, 0 files

2:因为在此服务器上需要配置replSet复制集,所以不使用默认的配置文件以及服务,需要但对建立配置文件以及更改相应的,目录文件日志文件等等

mongod对应ip地址以及端口如下:

mongod-IP              Port
192.168.33.131         30000//主
192.168.33.131         30001//从
192.168.33.131         30002//从

wKiom1Z4Fr-QElLLAAESAEk-GTw716.jpg


3:mongodb各个配置文件如下:

mongodb-30000配置文件

# grep '^[a-Z]' /etc/30000.conf 
logpath=/opt/log/rs0.log #日志文件
logappend=true #日志以追加模式
fork = true #后台启动
port = 30000#端口号
dbpath=/opt/rs0#mongodb数据目录
pidfilepath = /opt/rs0/30000.pid#mongodb-pid
master = true #是否参加选举
replSet = zxl#复制集名称
rest = true#mongodb接口,web界面访问


mongodb-30001配置文件

# grep '^[a-Z]' /etc/30001.conf  
logpath=/opt/log/rs1.log
logappend=true
fork = true
port = 30001
dbpath=/opt/rs1
pidfilepath = /opt/rs1/30001.pid
master = true
replSet = zxl


mongodb-30002配置文件

# grep '^[a-Z]' /etc/30002.conf  
logpath=/opt/log/rs2.log
logappend=true
fork = true
port = 30002
dbpath=/opt/rs2
pidfilepath = /opt/rs2/30002.pid
master = true

replSet = zxl


4:启动各个mongodb节点,方式如下:

mongodb端口30000启动

# mongod -f /etc/30000.conf 
about to fork child process, waiting until server is ready for connections.
forked process: 1968
all output going to: /opt/log/rs0.log
child process started successfully, parent exiting
# netstat -ntpl|grep :2000
tcp        0      0 0.0.0.0:30000               0.0.0.0:*                   LISTEN      1968/mongod



mongodb端口30001启动

# mongod -f /etc/30001.conf 
about to fork child process, waiting until server is ready for connections.
forked process: 2033
all output going to: /opt/log/rs1.log
child process started successfully, parent exiting
# netstat -ntpl|grep :2000
tcp        0      0 0.0.0.0:30000               0.0.0.0:*                   LISTEN      1968/mongod         
tcp        0      0 0.0.0.0:30001               0.0.0.0:*                   LISTEN      2033/mongod



mongodb端口30002启动

# mongod -f /etc/30002.conf 
about to fork child process, waiting until server is ready for connections.
forked process: 2083
all output going to: /opt/log/rs2.log
child process started successfully, parent exiting
# netstat -ntpl|grep :2000
tcp        0      0 0.0.0.0:30000               0.0.0.0:*                   LISTEN      1968/mongod         
tcp        0      0 0.0.0.0:30001               0.0.0.0:*                   LISTEN      2033/mongod         
tcp        0      0 0.0.0.0:30002               0.0.0.0:*                   LISTEN      2083/mongod




机器实际操作如下:

终端方式只是测试启动各个replica sets,此方式与上面是一样,只不过我没有使用配置文件方式启动,生产环境请使用配置文件方式启动!下面方式启动各个mongod实例是一样的!

[root@localhost opt]# mongod --replSet zxl --dbpath=/opt/rs0/ --logpath=/opt/logs/rs0.log --logappend --port 30000 --fork       
about to fork child process, waiting until server is ready for connections.
forked process: 1671
child process started successfully, parent exiting
[root@localhost opt]# mongod --replSet zxl --dbpath=/opt/rs1/ --logpath=/opt/logs/rs1.log --logappend --port 30001 --fork  
about to fork child process, waiting until server is ready for connections.
forked process: 1717
child process started successfully, parent exiting
[root@localhost opt]# mongod --replSet zxl --dbpath=/opt/rs2/ --logpath=/opt/logs/rs2.log --logappend --port 30002 --fork  
about to fork child process, waiting until server is ready for connections.
forked process: 1764
child process started successfully, parent exiting
[root@localhost opt]#

5:登录mongodb端口为30000

[root@localhost opt]# mongo --port 30000
MongoDB shell version: 2.6.11
connecting to: 127.0.0.1:30000/test
> db
test

注:以下是添加复制集的主机,id:zxl复制集的名称,相当于一个小组。{_id:0,host: '192.168.33.131:30000'}是添加对应的id以及主机ip和端口,默认先添加谁,谁就是主,如果设置优先级就另说了.....

> cfg={_id:'zxl',members:[
... {_id:0,host: '192.168.33.131:30000'},
... {_id:1,host: '192.168.33.131:30001'},
... {_id:2,host: '192.168.33.131:30002'}]
... }
{
        "_id" : "zxl",
        "members" : [
                {
                        "_id" : 0,
                        "host" : "192.168.33.131:30000"
                },
                {
                        "_id" : 1,
                        "host" : "192.168.33.131:30001"
                },
                {
                        "_id" : 2,
                        "host" : "192.168.33.131:30002"
                }
        ]
}
> rs.initiate(cfg) 
{
        "info" : "Config now saved locally.  Should come online in about a minute.",
        "ok" : 1
}
注:初始化
[22:3:2]> rs.initiate(cfg)
[22:3:2]{
[22:3:2]        "info" : "Config now saved locally.  Should come online in about a minute.",
[22:3:2]        "ok" : 1
[22:3:2]}
注:显示状态
> rs.status()
{
        "set" : "zxl",
        "date" : ISODate("2015-12-13T21:48:42Z"),
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "192.168.33.131:30000",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 140,
                        "optime" : Timestamp(1450043304, 1),
                        "optimeDate" : ISODate("2015-12-13T21:48:24Z"),
                        "electionTime" : Timestamp(1450043313, 1),
                        "electionDate" : ISODate("2015-12-13T21:48:33Z"),
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "192.168.33.131:30001",
                        "health" : 1,
                        "state" : 5,
                        "stateStr" : "STARTUP2",
                        "uptime" : 17,
                        "optime" : Timestamp(0, 0),
                        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                        "lastHeartbeat" : ISODate("2015-12-13T21:48:41Z"),
                        "lastHeartbeatRecv" : ISODate("2015-12-13T21:48:41Z"),
                        "pingMs" : 0,
                        "lastHeartbeatMessage" : "initial sync need a member to be primary or secondary to do our initial sync"
                },
                {
                        "_id" : 2,
                        "name" : "192.168.33.131:30002",
                        "health" : 1,
                        "state" : 5,
                        "stateStr" : "STARTUP2",
                        "uptime" : 17,
                        "optime" : Timestamp(0, 0),
                        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                        "lastHeartbeat" : ISODate("2015-12-13T21:48:41Z"),
                        "lastHeartbeatRecv" : ISODate("2015-12-13T21:48:42Z"),
                        "pingMs" : 0,
                        "lastHeartbeatMessage" : "initial sync need a member to be primary or secondary to do our initial sync"
                }
        ],
        "ok" : 1
}

注:以上显示各个复制集的主机信息以及是否主或者从等等信息

6:查看是否是主的master的信息如下

zxl:PRIMARY> db.isMaster()
{
        "setName" : "zxl",
        "setVersion" : 1,
        "ismaster" : true,
        "secondary" : false,
        "hosts" : [
                "192.168.33.131:30000",
                "192.168.33.131:30002",
                "192.168.33.131:30001"
        ],
        "primary" : "192.168.33.131:30000",
        "me" : "192.168.33.131:30000",
        "electionId" : ObjectId("566de7b2a25a61b157882302"),
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 1000,
        "localTime" : ISODate("2015-12-13T21:48:58.224Z"),
        "maxWireVersion" : 2,
        "minWireVersion" : 0,
        "ok" : 1
}

创建一个数据库ceshi,并插入数据

zxl:PRIMARY> use ceshi
switched to db ceshi
zxl:PRIMARY> db
ceshi
zxl:PRIMARY> db.a.insert({name:"xiaoer",age:33})
WriteResult({ "nInserted" : 1 })

7:mongodb端口30001登录,已经显示为从节点

[root@localhost ~]# mongo --port 30001
MongoDB shell version: 2.6.11
connecting to: 127.0.0.1:30001/test
zxl:SECONDARY> db
test

也可以在从节点查看是否为master命令如下:

zxl:SECONDARY> db.isMaster()
{
        "setName" : "zxl",
        "setVersion" : 1,
        "ismaster" : false,
        "secondary" : true,
        "hosts" : [
                "192.168.33.131:30001",
                "192.168.33.131:30002",
                "192.168.33.131:30000"
        ],
        "primary" : "192.168.33.131:30000",
        "me" : "192.168.33.131:30001",
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 1000,
        "localTime" : ISODate("2015-12-13T21:51:55.807Z"),
        "maxWireVersion" : 2,
        "minWireVersion" : 0,
        "ok" : 1
}

此时从节点是没有查询权限,需进行rs.slaveOk()即可

zxl:SECONDARY> rs.slaveOk()
zxl:SECONDARY> show tables;
a
system.indexes
zxl:SECONDARY> db.a.find()
{ "_id" : ObjectId("566de8054436414a1c849a93"), "name" : "xiaoer", "age" : 33 }

8:把主节点端口为30000的停止,看从节点是否成为主的,操作如下

zxl:PRIMARY> use admin
switched to db admin
zxl:PRIMARY> db.shutdownServer()
2015-12-14T06:15:18.778+0800 DBClientCursor::init call() failed
server should be down...
2015-12-14T06:15:18.781+0800 trying reconnect to 127.0.0.1:30000 (127.0.0.1) failed
2015-12-14T06:15:18.782+0800 warning: Failed to connect to 127.0.0.1:30000, reason: errno:111 Connection refused
2015-12-14T06:15:18.782+0800 reconnect 127.0.0.1:30000 (127.0.0.1) failed failed couldn't connect to server 127.0.0.1:30000 (127.0.0.1), connection attempt failed
2015-12-14T06:15:18.786+0800 trying reconnect to 127.0.0.1:30000 (127.0.0.1) failed
2015-12-14T06:15:18.787+0800 warning: Failed to connect to 127.0.0.1:30000, reason: errno:111 Connection refused
2015-12-14T06:15:18.787+0800 reconnect 127.0.0.1:30000 (127.0.0.1) failed failed couldn't connect to server 127.0.0.1:30000 (127.0.0.1), connection attempt failed
> exit
bye
9:登录从节点端口30001、30002,并分别登录如下
[root@localhost ~]# mongo --port 30001
MongoDB shell version: 2.6.11
connecting to: 127.0.0.1:30001/test
zxl:SECONDARY> 
zxl:PRIMARY> db.isMaster()
{
        "setName" : "zxl",
        "setVersion" : 1,
        "ismaster" : true,
        "secondary" : false,
        "hosts" : [
                "192.168.33.131:30001",
                "192.168.33.131:30002",
                "192.168.33.131:30000"
        ],
        "primary" : "192.168.33.131:30001",
        "me" : "192.168.33.131:30001",
        "electionId" : ObjectId("566dedfbdc32e033bb4d0e18"),
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 1000,
        "localTime" : ISODate("2015-12-13T22:16:10.788Z"),
        "maxWireVersion" : 2,
        "minWireVersion" : 0,
        "ok" : 1
}

30002登陆查看

[root@localhost ~]# mongo --port 30002
MongoDB shell version: 2.6.11
connecting to: 127.0.0.1:30002/test
zxl:SECONDARY> db.isMaster()
{
        "setName" : "zxl",
        "setVersion" : 1,
        "ismaster" : false,
        "secondary" : true,
        "hosts" : [
                "192.168.33.131:30002",
                "192.168.33.131:30001",
                "192.168.33.131:30000"
        ],
        "primary" : "192.168.33.131:30001",
        "me" : "192.168.33.131:30002",
        "maxBsonObjectSize" : 16777216,
        "maxMessageSizeBytes" : 48000000,
        "maxWriteBatchSize" : 1000,
        "localTime" : ISODate("2015-12-13T22:17:57.891Z"),
        "maxWireVersion" : 2,
        "minWireVersion" : 0,
        "ok" : 1
}

注:此时端口30001的已经成为主节点,进行插入数据等等

zxl:PRIMARY> use ceshi
switched to db ceshi
zxl:PRIMARY> show tables;
a
system.indexes
zxl:PRIMARY> db.a.insert({a:1})
WriteResult({ "nInserted" : 1 })
zxl:PRIMARY> db.a.find()
{ "_id" : ObjectId("566de8054436414a1c849a93"), "name" : "xiaoer", "age" : 33 }
{ "_id" : ObjectId("566def04cbb79452107c217f"), "a" : 1 }

登录另一个端口30002的进行查看,操作如下:

zxl:SECONDARY> show dbs
admin  (empty)
ceshi  0.078GB
local  1.078GB
test   (empty)
zxl:SECONDARY> use ceshi
switched to db ceshi
zxl:SECONDARY> show tables;
2015-12-14T06:20:29.891+0800 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:131
zxl:SECONDARY> rs.slaveOk()
zxl:SECONDARY> show tables;
a
system.indexes
zxl:SECONDARY> db.a.find()
{ "_id" : ObjectId("566de8054436414a1c849a93"), "name" : "xiaoer", "age" : 33 }
{ "_id" : ObjectId("566def04cbb79452107c217f"), "a" : 1 }
zxl:SECONDARY>

注:以上可以进行查询到端口30001的新的节点数据,但是从节点30002,查询时出现错误,需要设置为rs.slaveOk()即可,不过配置文件是可以设置的。

以上就是mongodb replSet复制集