一)理解MongoDB复制集
二)案例
第一个:以三节点为例
操作系统;centos7.3
节点:
node1: 10.2.13.187
node2: 10.2.13.186
node3: 10.2.13.185
mongodb版本: Mongodb3.6.3
1)第一步,在所有节点上安装mongodb3.6.3,脚本如下
~~~
[root@node2 scripts]# cat install_mongodb.sh
#!/bin/bash
#
M_VER=3.6
M_INSTALL_VER=3.6.3
PORT=27017
BIND_IP=$(ifconfig eth0|grep inet|grep -v inet6|awk '{print $2}')
function yum_install_mongodb(){
cd /etc/yum.repos.d
if [ ! -f mongodb-org-${M_VER}.repo ];then
cat >>mongodb-org-${M_VER}.repo <<EOF
[mongodb-org-${M_VER}]
name = MongoDB Repository
baseurl = https://repo.mongodb.org/yum/redhat/7Server/mongodb-org/${M_VER}/x86_64/
gpgcheck = 0
enabled = 1
EOF
fi
yum install -y mongodb-org-${M_INSTALL_VER} mongodb-org-server-${M_INSTALL_VER} mongodb-org-shell-${M_INSTALL_VER} mongodb-org-mongos-${M_INSTALL_VER} mongodb-org-tools-${M_INSTALL_VER}
cd /etc/ && [ ! -f mongod.conf.ori ] && cp /etc/mongod.conf{,.ori}
#修改配置文件
sed -i "s@bindIp: 127.0.0.1@bindIp: ${BIND_IP}@g" /etc/mongod.conf
#启动mongod服务
systemctl start mongod
if [ "`ss -tunl|grep ${PORT}|cut -d: -f2|awk '{print $1}'`" == "${PORT}" ];then
echo "mongod start successful"
else
echo "mongod start fail"
fi
}
main(){
yum_install_mongodb
}
main
~~~
2)配置mongod.conf
参数
replication:
oplogSizeMB : <int>
replSetName : <string>
secondaryIndexPrefetch : <string>
enableMajorityReadConcern : <boolean> ##在3.6中不推荐使用
replSetResizeOplog使您可以动态调整oplog的大小而不必重新启动mongod进程。
replication.secondaryIndexPrefetch仅适用于mmapv1 存储引擎
* 在node1上操作
replication:
oplogSizeMB: 3072
replSetName: repl1
secondaryIndexPrefetch: _id_only
解释:
replSet:定义一个复制集的名称,假如三个服务器的mongodb.conf中都需要加入replSet的指定,它们都属于repl1复制集(replSetName)
replIndexPrefetch:指定索引预获取行为,[none|_id_only|all] ( secondaryIndexPrefetch)
oplogSize:用于复制操作的大小(以MB为单位)日志。默认值是磁盘空间的5%
(oplogSizeMB)
启动mongod服务
[root@node1 ~]# systemctl start mongod
* 在node2和node3上操作
[root@node3 ~]# vim /etc/mongod.conf
replication:
oplogSizeMB: 3072
replSetName: repl1
secondaryIndexPrefetch: _id_only
然后重启mongod服务
[root@node3 ~]# systemctl restart mongod
3)配置复制集
在node1上操作
~~~
[root@node1 ~]# mongo 10.2.13.187:27017
MongoDB shell version v3.6.3
connecting to: mongodb://10.2.13.187:27017/test
MongoDB server version: 3.6.3
Server has startup warnings:
2018-03-13T10:29:01.155+0800 I STORAGE [initandlisten]
2018-03-13T10:29:01.155+0800 I STORAGE [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2018-03-13T10:29:01.155+0800 I STORAGE [initandlisten] ** See http://dochub.mongodb.org/core/prodnotes-filesystem
2018-03-13T10:29:05.989+0800 I CONTROL [initandlisten]
2018-03-13T10:29:05.989+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2018-03-13T10:29:05.989+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2018-03-13T10:29:05.989+0800 I CONTROL [initandlisten]
> rs.
rs.add( rs.isMaster(
rs.addArb( rs.printReplicationInfo(
rs.apply( rs.printSlaveReplicationInfo(
rs.bind( rs.propertyIsEnumerable(
rs.call( rs.prototype
rs.compareOpTimes( rs.reconfig(
rs.conf( rs.remove( 当前配置
rs.config( rs.slaveOk(
rs.constructor rs.status(
rs.debug rs.stepDown(
rs.freeze( rs.syncFrom(
rs.hasOwnProperty( rs.toLocaleString(
rs.help( rs.toString(
rs.initiate( rs.valueOf( 初始化
~~~
* 先初始化并查看状态
~~~
> rs.initiate() 初始化
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "10.2.13.187:27017",
"ok" : 1,
"operationTime" : Timestamp(1520908730, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520908730, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
repl1:PRIMARY> rs.status() --查看副本集的状态
{
"set" : "repl1",
"date" : ISODate("2018-03-13T02:39:47.584Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1520908782, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1520908782, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1520908782, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1520908782, 1),
"t" : NumberLong(1)
}
},
"members" : [ 显示副本集成员信息
{
"_id" : 0, 节点标识
"name" : "10.2.13.187:27017", 节点名称
"health" : 1, 节点健康状态
"state" : 1, 有没有状态信息
"stateStr" : "PRIMARY", 当前节点状态
"uptime" : 646, 运行状态
"optime" : {
"ts" : Timestamp(1520908782, 1),
"t" : NumberLong(1)
}, --oplog中最近一次最后一次oplog操作的时间戳
"optimeDate" : ISODate("2018-03-13T02:39:42Z"), --oplog中最近一次最后一次oplog操作的时间
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1520908730, 2), 选举时间戳
"electionDate" : ISODate("2018-03-13T02:38:50Z"),选举日期
"configVersion" : 1,
"self" : true
}
],
"ok" : 1,
"operationTime" : Timestamp(1520908782, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520908782, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
~~~
~~~
repl1:PRIMARY> rs.add("10.2.13.186:27017") 添加节点
{
"ok" : 1,
"operationTime" : Timestamp(1520909511, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520909511, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
repl1:PRIMARY> rs.status()
{
"set" : "repl1",
"date" : ISODate("2018-03-13T02:51:59.822Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1520909507, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1520909511, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1520909511, 1),
"t" : NumberLong(1)
}
},
"members" : [
{
"_id" : 0,
"name" : "10.2.13.187:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1378,
"optime" : {
"ts" : Timestamp(1520909511, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-03-13T02:51:51Z"),
"electionTime" : Timestamp(1520908730, 2),
"electionDate" : ISODate("2018-03-13T02:38:50Z"),
"configVersion" : 2,
"self" : true
},
{
"_id" : 1,
"name" : "10.2.13.186:27017",
"health" : 1,
"state" : 0,
"stateStr" : "STARTUP", 追赶主节点的阶段,一旦追赶成功就会显示"SECONDARY",如 "stateStr" : "SECONDARY",
"uptime" : 7,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDurable" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2018-03-13T02:51:57.837Z"),
"lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
"pingMs" : NumberLong(1),
"configVersion" : -2
}
],
"ok" : 1,
"operationTime" : Timestamp(1520909511, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520909511, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
一旦状态变成"SECONDARY",我们可以登录node2查看
[root@node2 ~]# mongo 10.2.13.186:27017
MongoDB shell version v3.6.3
connecting to: mongodb://10.2.13.186:27017/test
MongoDB server version: 3.6.3
Server has startup warnings:
2018-03-13T10:32:03.222+0800 I CONTROL [initandlisten]
2018-03-13T10:32:03.222+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2018-03-13T10:32:03.222+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2018-03-13T10:32:03.222+0800 I CONTROL [initandlisten]
2018-03-13T10:32:03.223+0800 I CONTROL [initandlisten]
2018-03-13T10:32:03.223+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2018-03-13T10:32:03.223+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2018-03-13T10:32:03.223+0800 I CONTROL [initandlisten]
2018-03-13T10:32:03.223+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2018-03-13T10:32:03.223+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2018-03-13T10:32:03.223+0800 I CONTROL [initandlisten]
repl1:SECONDARY>
~~~
错误提示1(在从节点上)
~~~
repl1:SECONDARY> show dbs;
2018-03-13T11:01:43.988+0800 E QUERY [thread1] Error: listDatabases failed:{
"operationTime" : Timestamp(1520910097, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1520910097, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:65:1
shellHelper.show@src/mongo/shell/utils.js:816:19
shellHelper@src/mongo/shell/utils.js:706:15
@(shellhelp2):1:1
~~~
因为从节点默认是不允许读写的,解决这个问题,有两种方式
在从节点上执行rs.slaveOk()
或者在主节点上执行db.getMongo().setSlaveOk()
repl1:SECONDARY> rs.slaveOk()
repl1:SECONDARY> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
person 0.000GB
在主机节点上操作rs.conf
~~~
rs.conf()
{
"_id" : "repl1",
"version" : 3,
"protocolVersion" : NumberLong(1),
"members" : [
{
"_id" : 0,
"host" : "10.2.13.187:27017",
"arbiterOnly" : false, 当前节点是不是仲裁节点
"buildIndexes" : true,
"hidden" : false,当前节点是否为隐藏节点
"priority" : 1, 当前节点的优先级
"tags" : {
},
"slaveDelay" : NumberLong(0), 当前节点是否为延迟复制的
"votes" : 1------是否有选票的资格
},
{
"_id" : 1,
"host" : "10.2.13.186:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "10.2.13.185:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5aa739baf02836af4dbcb3c5")
}
}
~~~
模拟主节点故障:
repl1:PRIMARY> rs.stepDown()
repl1:SECONDARY>
此时第三个节点就变成主的
repl1:SECONDARY>
repl1:PRIMARY>
* 调整属性
1)调整该节点的优先级为2,使其成为主节点(在主节点上操作)
repl1:PRIMARY> cfg=rs.conf()
repl1:PRIMARY> cfg.members[0].priority=2
repl1:PRIMARY> rs.reconfig(cfg)
然后就发现当前主节点变成
repl1:SECONDARY>
然后优先级为2的节点成为primary节点咯
repl1:PRIMARY>
2)添加仲裁节点
推荐使用
repl1:PRIMARY> rs.addArb("10.2.13.185:27017") 直接添加仲裁节点
把已有的某个节点改成冲裁节点
repl1:PRIMARY> cfg=rs.conf()
repl1:PRIMARY> cfg.members[2].arbiterOnly=true
true
repl1:PRIMARY> rs.reconfig(cfg)
如果没有成功就执行如下操作
~~~
repl1:PRIMARY> rs.remove("10.2.13.185:27017")
{
"ok" : 1,
"operationTime" : Timestamp(1520913161, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520913161, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
repl1:PRIMARY> rs.addArb("10.2.13.185:27017")
{
"ok" : 1,
"operationTime" : Timestamp(1520913184, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520913184, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
使用rs.conf()查看
{
"_id" : 2,
"host" : "10.2.13.185:27017",
"arbiterOnly" : true,
"buildIndexes" : true,
~~~
3)查看各从节点是否落后与主节点多少
repl1:PRIMARY> rs.printSlaveReplicationInfo()
source: 10.2.13.186:27017
syncedTo: Tue Mar 13 2018 11:54:23 GMT+0800 (CST)
0 secs (0 hrs) behind the primary
source: 10.2.13.185:27017
no replication info, yet. State: (not reachable/healthy)
4) 配置节点成为延迟节点(在主节点上配置)
cfg = rs.conf()
cfg.members[2].priority = 0
cfg.members[2].hidden = true
cfg.members[2].slaveDelay = 3600
rs.reconfig(cfg)
* 副本集的维护
1)更改oplog大小
~~~
repl1:SECONDARY> db.oplog.rs.stats().maxSize
NumberLong("3221225472")
repl1:SECONDARY> db.adminCommand({replSetResizeOplog:1,size:2048})
{
"ok" : 1,
"operationTime" : Timestamp(1520915223, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1520915223, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
repl1:SECONDARY> db.oplog.rs.stats().maxSize
NumberLong("2147483648")
~~~
2)