MongoDB复制集RS(ReplicationSet)*****

![](D:\data\Sync-data\simon\学习笔记\Mysql 笔记\MySql-DBA\Mongodb\NoSQL-Mongodb-04-复制集RS(ReplicationSet).assets\复制集RS架构图-01.png)

基本原理

基本构成是1主2从的结构,自带互相监控投票机制(Raft 分布式一致性协议(MongoDB)  Paxos(mysql MGR 用的是变种))

如果发生主库宕机,复制集内部会进行投票选举,选择一个新的主库替代原有主库对外提供服务。同时复制集会自动通知

客户端程序,主库已经发生切换了。应用就会连接到新的主库。

集群节点 也会有专用日志:OPLOG

通过OPLOG日志,实现各节点之间的数据同步

OPLOG会自带类似GTID的能力,只不过OPLOG是基于时间戳的进行控制,类似MySQL中的binlog

OPLOG不是以文件形式存储,是存储在数据库的一个 集合/表 里

节点之间自动心跳检测

如果主节点宕机,会自动选新主并重构主从关系,实现FailOver故障转移

Raft Paxos 分布式一致性协议

在真正事务commit提交之前,数据或日志已经达到各个node节点,进行决议之后再决定是否提交还是回滚。日志的传输,是在总体执行前的动作。

规划

默认1主多从,建议1主2从,满足投票半数

三个以上的mongodb节点(或多实例)

环境准备

多个端口

28017、28018、28019、28020

多套目录

su - mongod 
mkdir -p /mongodb/280{17..20}/{conf,data,log}

多套配置文件

/mongodb/28017/conf/mongod.conf
/mongodb/28018/conf/mongod.conf
/mongodb/28019/conf/mongod.conf
/mongodb/28020/conf/mongod.conf

配置文件内容

cat > /mongodb/28017/conf/mongod.conf <<EOF
systemLog:
  destination: file
  path: /mongodb/28017/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/28017/data
  directoryPerDB: true
  #engine: wiredTiger	
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1	#缓冲区大小
      directoryForIndexes: true	#目录索引
    collectionConfig:
      blockCompressor: zlib		#压缩
    indexConfig:
      prefixCompression: true
processManagement:
  fork: true
net:
  bindIp: 10.0.50.61,127.0.0.1
  port: 28017
replication:
  oplogSizeMB: 2048		#oplog 大小为2G,滚动使用,空间不够,会覆盖之前的记录
  replSetName: my_repl	# 复制集的name
EOF


说明:
1、3.x版本以上默认 WT(wiredTiger) 引擎,相当于MySQL 的Innodb,支持事务,文档锁,redo功能,多缓冲区支持等等
2、早起2.x版本中,默认的是MMAPv1引擎,相当于MySQL的MyISAM引擎


\cp  /mongodb/28017/conf/mongod.conf  /mongodb/28018/conf/
\cp  /mongodb/28017/conf/mongod.conf  /mongodb/28019/conf/
\cp  /mongodb/28017/conf/mongod.conf  /mongodb/28020/conf/

sed -i 's#28017#28018#g' /mongodb/28018/conf/mongod.conf 
sed -i 's#28017#28019#g' /mongodb/28019/conf/mongod.conf
sed -i 's#28017#28020#g' /mongodb/28020/conf/mongod.conf

chown -R mongod:mongod /mongodb

启动多个实例备用

mongod -f /mongodb/28017/conf/mongod.conf
mongod -f /mongodb/28018/conf/mongod.conf
mongod -f /mongodb/28019/conf/mongod.conf
mongod -f /mongodb/28020/conf/mongod.conf

netstat -lnp|grep 280
[mongod@mysql-node01 ~]$ netstat -lnp|grep 280
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:28017         0.0.0.0:*               LISTEN      9476/mongod         
tcp        0      0 10.0.50.61:28017        0.0.0.0:*               LISTEN      9476/mongod         
tcp        0      0 127.0.0.1:28018         0.0.0.0:*               LISTEN      9509/mongod         
tcp        0      0 10.0.50.61:28018        0.0.0.0:*               LISTEN      9509/mongod         
tcp        0      0 127.0.0.1:28019         0.0.0.0:*               LISTEN      9542/mongod         
tcp        0      0 10.0.50.61:28019        0.0.0.0:*               LISTEN      9542/mongod         
tcp        0      0 127.0.0.1:28020         0.0.0.0:*               LISTEN      9575/mongod         
tcp        0      0 10.0.50.61:28020        0.0.0.0:*               LISTEN      9575/mongod         
unix  2      [ ACC ]     STREAM     LISTENING     483181   9476/mongod          /tmp/mongodb-28017.sock
unix  2      [ ACC ]     STREAM     LISTENING     483535   9509/mongod          /tmp/mongodb-28018.sock
unix  2      [ ACC ]     STREAM     LISTENING     483197   9542/mongod          /tmp/mongodb-28019.sock
unix  2      [ ACC ]     STREAM     LISTENING     483208   9575/mongod          /tmp/mongodb-28020.sock
[mongod@mysql-node01 ~]$

配置普通复制集

1主2从,从库普通从库
mongo --port 28017 admin
config = {_id: 'my_repl', members: [
                          {_id: 0, host: '10.0.50.61:28017'},
                          {_id: 1, host: '10.0.50.61:28018'},
                          {_id: 2, host: '10.0.50.61:28019'}
                          ]
          }
rs.initiate(config) 
> rs.initiate(config)
{
	"ok" : 1,
	"operationTime" : Timestamp(1603515267, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1603515267, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
my_repl:OTHER>

查询复制集状态
rs.status();

Replica Set Arbiter

上述普通复制集结构,主节点要向其他节点传输OPLOG,会承担较大的IO负载,对节点性能有影响,为了减少这种影响,MongoDB官方给出 Replica Set Arbiter 结构,结构图:

![](D:\data\Sync-data\simon\学习笔记\Mysql 笔记\MySql-DBA\Mongodb\NoSQL-Mongodb-04-复制集RS(ReplicationSet).assets\ReplicaSet-Arbiter.png)

在这个结构中,Arbiter节点,不参与数据复制,也不参与故障时的选主,只负责投票,用以打破投票平局的情况。

官方文档说明:

https://docs.mongodb.com/v3.6/core/replica-set-arbiter/index.html

1主 1从 1个arbiter

方法1:
# 推荐,在搭建MongoDB 复制集过程中,直接把Arbiter节点做好。
mongo -port 28017 admin
config = {_id: 'my_repl', members: [
                          {_id: 0, host: '10.0.0.51:28017'},
                          {_id: 1, host: '10.0.0.51:28018'},
                          {_id: 2, host: '10.0.0.51:28019',"arbiterOnly":true}]
          }                
rs.initiate(config)
方法2:
将已有节点28019,替换为Arbiter节点
mongo -port 28017 admin

# 把28019节点从复制集中移除
rs.remove("10.0.50.61:28019")

my_repl:PRIMARY> rs.remove("10.0.50.61:28019")
{
	"ok" : 1,	# 返回为1,说明节点移除成功
	"operationTime" : Timestamp(1603516687, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1603516687, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
my_repl:PRIMARY> 

# 用rs.addArb命令,把28019 添加为arbiter节点
my_repl:PRIMARY> 
my_repl:PRIMARY> rs.add
rs.add(     rs.addArb(
my_repl:PRIMARY> rs.addArb("10.0.50.61:28019")
{
	"ok" : 1,
	"operationTime" : Timestamp(1603516901, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1603516901, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
my_repl:PRIMARY>

# 查看副本集状态
my_repl:PRIMARY> rs.status("member")
......
			"_id" : 2,
			"name" : "10.0.50.61:28019",
			"health" : 0,
			"state" : 8,
			"stateStr" : "(not reachable/healthy)",
			"uptime" : 0,
......

# 节点状态为“not reachable/healthy” 无状态

# 查看 28019端口
[mongod@mysql-node01 ~]$ ss -lntp|grep 28019
[mongod@mysql-node01 ~]$ 

# 被down掉了,重启28019
mongod -f /mongodb/28019/conf/mongod.conf

# 启动28019后再 登陆mongodb查看状态

my_repl:PRIMARY> rs.status("member")
......
			"name" : "10.0.50.61:28019",
			"health" : 1,
			"state" : 7,
			"stateStr" : "ARBITER",
			"uptime" : 6,
......

# 添加arbiter节点完成

复制集管理操作

查看复制集状态

rs.status();    //查看整体复制集状态
rs.isMaster(); // 查看当前是否是主节点
rs.conf();   //查看复制集配置信息

添加删除节点

rs.remove("ip:port"); // 删除一个节点
rs.add("ip:port"); // 新增从节点
rs.addArb("ip:port"); // 新增仲裁节点
例子:
添加 arbiter节点
1、连接到主节点
[mongod@db03 ~]$ mongo --port 28018 admin
2、添加仲裁节点
my_repl:PRIMARY> rs.addArb("10.0.0.53:28020")
3、查看节点状态
my_repl:PRIMARY> rs.isMaster()
{
    "hosts" : [
        "10.0.0.53:28017",
        "10.0.0.53:28018",
        "10.0.0.53:28019"
    ],
    "arbiters" : [
        "10.0.0.53:28020"
    ],

rs.remove("ip:port"); // 删除一个节点
例子:
my_repl:PRIMARY> rs.remove("10.0.0.53:28019");
{ "ok" : 1 }
my_repl:PRIMARY> rs.isMaster()
rs.add("ip:port"); // 新增从节点
例子:
my_repl:PRIMARY> rs.add("10.0.0.53:28019")
{ "ok" : 1 }
my_repl:PRIMARY> rs.isMaster()
# 将rs.slaveOk()写入到这个.mongors.js文件中,这样,就可以让mongo-shell客户端为自动执行这个命令

echo 'rs.slaveOk()'  > /root/.mongors.js

读写分离

对于MongoDB来说,主节点一般用于写数据,从节点用于读数据,且主节点也并不是固定的(当主节点宕机后会选举出一个新的主节点),所以在生产环境时客户端不能直连主节点,要配置所有节点

<mongo:mongo-client replica-set="ip1:port1,ip2:port2,ip3:port3">
    <mongo:client-options read-preference="SECONDARY_PREFERRED"/>
</mongo:mongo-client>

通过read-preference参数控制读写分离方式,其类型有以下几种:

  • PRIMARY(默认)
    读操作都在主节点,若主节点不可用则报错。
  • PRIMARY_PREFERRED
    首选主节点,若主节点不可用则转移到其它从节点。
  • SECONDARY
    读从节点,不可用则报错。
  • SECONDARY_PREFERRED(推荐)
    首选从节点,若是特殊情况则在主节点读(单主节点架构)。
  • NEAREST
    最邻近主节点。