MongoDB复制集群的神奇之处在于本身就拥有自动容灾和选举的功能,不像mysql
需要借助中间件如mha和mysql-mmm来实现.mongodb复制集的从节点绝对不可写,
也不能指定只复制某个库或某个集合,集群只能有一个primary,服从大多数原则.
搭建与测试:
1>配置复制集:
conf = {_id:"yooo", members:[{_id:0,host:"127.0.0.1:28001"}, {_id:1,host:"127.0.0.1:28002"}} --配置复制集成员
rs.initiate(conf) ---初始化复制集
rs.conf() ---查看复制集成员配置,实际是在local数据库的system.replset集合里面文档,
可使用db.system.replset.find().pretty()查看和rs.conf()输出一样
rs.status() ---查看复制集状态
rs.isMaster()
修改复制成员信息:不能修改_id,不能将接收rs.reconfig命令的成员的优先级设置为 0,不能将仲
裁者成员变为非仲裁者成员反正亦然,不能将 buildIndexes从false 改为 true
conf=rs.conf()
conf.members[1].hidden=true
rs.reconfig(conf) 或rs.reconfig(conf,{"force":true})强制重新配置
2>复制集节点属性:
_id和host: 集群节点的id,host为ip:port
priority: 整数,设置为0则永远不能成为主,数字越大越能成为主,如把复制集中某个节点的priority变成
最大,而且该节点的optime与原主节点不超过10s,则原primary会降级,该节点升级成为新primary.
arbiterOnly: 是否是仲裁者
hidden: 是否隐藏节点
votes: 是否拥有投票权
slaveDlay: 复制延时时间
buildIndexes:当前节点是否把主上的index也clone过来,对_id限制无效
3>复制集节点类型:
主节点:提供读写服务的节点,-----priority至少为1
从节点:提供读服务的节点,包含下面:
隐藏节点:对程序不可见的节点,------priority为0且hidden=true
rs.isMaster()不会显示隐藏节点,rs.status()依旧可以查看
延时节点:延时复制的节点 ------priority为0且hidden=true,slaveDlay=XXX
投票节点,具有投票权的节点 ------votes=1
arbiter:选举节点,无数据,仅做选举作用 ------arbiterOnly=true
1.配置文件,先启动2个实例
/etc/28001.conf,/etc/28002.conf,/etc/28003.conf
-----------------
port=28001
dbpath=/data/db1/28001
logpath=/data/db1/mongod.log
logappend=true
oplogSize=1024
fork=true
replSet=yooo
------------------
[root@rhel64-64bit etc]# ps -ef|grep mongo
root 1041 1 2 12:34 ? 00:00:02 ./mongod -f /etc/28001.conf
root 1108 1 16 12:35 ? 00:00:03 ./mongod -f /etc/28002.conf
2.在28001实例上配置并初始化复制集:
---配置复制集节点信息
> conf = {_id:"yooo", members:[{_id:0,host:"127.0.0.1:28001"}, {_id:1,host:"127.0.0.1:28002"}]}
{
"_id" : "yooo",
"members" : [
{
"_id" : 0,
"host" : "127.0.0.1:28001"
},
{
"_id" : 1,
"host" : "127.0.0.1:28002"
}
]
}
> rs.initiate(conf)----初始化复制集群
{
"ok" : 1,
"operationTime" : Timestamp(1529988091, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1529988091, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
yooo:PRIMARY> rs.status() ---提示符已经变成的primary,查看集群状态
-----------------------------
yooo:PRIMARY> use local
yooo:PRIMARY> show tables
me
oplog.rs ----记录oplog
replset.election
replset.minvalid
startup_log
system.replset ----复制集的配置信息
system.rollback.id
------------------------------
yooo:PRIMARY> db
fooo
yooo:PRIMARY> db.foo.find() ---主上创建数据库并插入数据
{ "_id" : ObjectId("5b31c49cdca108d5217c60c1"), "x" : 1, "y" : 1 }
3.在28002实例上查看:
yooo:SECONDARY> rs.slaveOk() ---28002实例已加入集群是个从节点
yooo:SECONDARY> use fooo
switched to db fooo
yooo:SECONDARY> db.foo.find() ---主上的数据已经同步过来
{ "_id" : ObjectId("5b31c49cdca108d5217c60c1"), "x" : 1, "y" : 1 }
yooo:SECONDARY> db.foo.insert({x:11,y:22}) ---从节点不可以写操作
WriteResult({ "writeError" : { "code" : 10107, "errmsg" : "not master" } }
4>添加新的集群节点:
内部过程:设置oplog的start日志点,新的节点会drop掉原有的数据库,并把复制源primary上的数据库
同步过来,然后从oplog的start点开始复制,可考虑用mongodump先同步数据
rs.add("new_node:port")---不需要rs.reconfig()
rs.addArb("new_node:port")
rs.add({'_id':5,"host":"new_node:port","arbiterOnly":true})
rs.remove("del_node:port") --移除集群节点
4.先在28003实例上创建一些库和数据:
> show dbs
admin 0.000GB
aiya 0.000GB
local 0.000GB
> show tables
aiyaya
> db.aiyaya.find()
{ "_id" : ObjectId("5b31c840f5dacf8de3883762"), "x" : 123, "y" : 12345 }
5.在28001实例primary上添加28003实例进入yooo集群:
yooo:PRIMARY> rs.add("127.0.0.1:28003")
{
"ok" : 1,
"operationTime" : Timestamp(1529989365, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1529989365, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
6.再次在28003实例上查看:
yooo:SECONDARY> rs.slaveOk() --28003已经加入集群
yooo:SECONDARY> show dbs --原有的数据库被drop掉并且clone了primary的库数据过来
admin 0.000GB
config 0.000GB
fooo 0.000GB
local 0.000GB
1.停止28001实例: ./mongod -f /etc/28001.conf --shutdown
"members" : [
{
"_id" : 0,
"name" : "127.0.0.1:28001",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)", ---28001已经不可访问
{
"_id" : 1,
"name" : "127.0.0.1:28002",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY", ----28002被选举成为新的primary
"uptime" : 5151,
2.主动把primary降级为secondary
mongo>use admin
mongo>rs.stepDown(60)#单位为 秒
rs.freeze(100) 100秒内不可以为主
6>查看复制集群状态:
rs.status()---查看复制集状态
mongo>db.serverStatus()
mongo>db.printReplicationInfo() ---查看oplog状态
mongo>rs.printReplicationInfo()
mongo>db.printSlaveReplicationInfo()
mongo>rs.printSlaveReplicationInfo() ---查看复制延时
yooo:PRIMARY> db.serverStatus().host
rhel64-64bit:28002
yooo:PRIMARY> rs.printSlaveReplicationInfo()
source: 127.0.0.1:28001
syncedTo: Tue Jun 26 2018 14:54:09 GMT+0800 (HKT)
0 secs (0 hrs) behind the primary
source: 127.0.0.1:28003
syncedTo: Tue Jun 26 2018 14:54:09 GMT+0800 (HKT)
0 secs (0 hrs) behind the primary
7>oplog作用类似于mysql里面的binlog:
oplog的结构:在默认情况下,oplog分配的是空闲磁盘空间的5%
ts: 时间戳,在选举新primary时,会选择ts最大的那个secondary作为primary
h: 此操作独一无二的ID
v: oplog的版本
op:操作类型(i 代表insert,d代表 delete,u代表update,c代表db cmd,db代表声明当前数据库,n代表空操作)
ns: 操作所在的namespace-->一般显示是db.collection
o: 操作所对应的document,即当前操作的内容。
o2: 仅限于update操作时有,更新时的where条件
yooo:PRIMARY> db.oplog.rs.find().sort({$natural:-1}).limit(1).pretty()
{
"ts" : Timestamp(1529992525, 1),
"t" : NumberLong(3),
"h" : NumberLong("-8501625235504890872"),
"v" : 2,
"op" : "n",
"ns" : "",
"wall" : ISODate("2018-06-26T05:55:25.884Z"),
"o" : {
"msg" : "periodic noop"
}
}
调整oplog的大小:
1.如果是主节点,则先将primary 降为 secondary,rs.status()确保没有其他secondary 从该节点复制数据
并以单机方式启动(即不加--replSet参数启动)
2.local.oplog.rs中的最新的一条保存的临时表:
use local
db.oplog.rs.find().sort({$natural:-1}).limit(1)
db.temp.save(db.oplog.rs.find().sort({$natural:-1}).limit(1).next())
3.将oplog.rs 删除:
db.oplog.rs.drop()
4.创建一个新的oplog.rs集合:
db.createCollection("oplog.rs":{"capped":true,"size":10240})
5.将临时集合中的最后一条操作记录写回新创建的oplog.rs:
db.oplog.rs.save(db.temp.findOne())
db.oplog.rs.count()
6.加上replSet重启加入集群即可