什么是复制集?

  • 复制集(replica sets)是额外的数据副本,是跨多个服务器同步数据的过程,复制集提供了冗余并增加了数据可用性,通过复制集可以对硬件故障和中断服务进行恢复。

复制集的优势

  • 让数据更安全。
  • 高数据可用性。
  • 灾难恢复。
  • 无停机维护(如备份、索引重建、故障转移)
  • 读缩放(额外的副本读取)
  • 副本集对应用程序是透明的。

复制集概述

  • MongoDB复制集是额外的数据副本,复制集提供了冗余和增加数据可用性。
  • MongoDB的复制集至少需要两个节点,其中主节点负责处理客户端请求,从节点负责复制主节点上的数据。
  • MongoDB复制集可以实现群集的高可用,当主节点出现故障时会自动切换。
  • 复制是基于操作日志oplog,相当于MySQL中的二进制日志,只记录发生改变的记录。复制是将主节点的oplog日志同步并应用到其他节点的过程。
  • 节点类型分为标准节点、被动节点、仲裁节点。只有标准节点可能被选举为活跃(主)节点。
  • 尽量保证主节点的oplog足够大,能够存放相当长时间的操作记录。

复制集服务配置

1、创建多实例

mkdir -p /data/mongodb/mongodb{2,3,4} //创建数据目录
mkdir logs
touch logs/mongodb{2,3,4}.log //创建日志文件
cd logs/
chmod 777 *.log //赋予权限

  • 修改多实例配置文件

vim /etc/mongod2.conf

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /data/mongodb/logs/mongodb2.log    //日志文件存放位置

# Where and how to store data.
storage:
  dbPath: /data/mongodb/mongodb2   //数据文件存放位置
  journal:
    enabled: true
#  engine:
#  mmapv1:
#  wiredTiger:

# how the process runs
processManagement:
  fork: true  # fork and run in background
  pidFilePath: /var/run/mongodb/mongod.pid  # location of pidfile
  timeZoneInfo: /usr/share/zoneinfo

# network interfaces
net:
  port: 27018    //监听端口及IP地址
  bindIp: 0.0.0.0  # Listen to local interface only, comment to listen on all interfaces.

#security:

#operationProfiling:

replication:
  replSetName: abc   //打开主从复制集功能,每个节点都要配置相同名称

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第1张图片

2、配置三个节点的复制集

  • 如上创建多实例完成后,修改完成配置文件后,依次重启每个服务。

mongod -f /etc/mongod.conf --shutdown
mongod -f /etc/mongod.conf
mongod -f /etc/mongod2.conf
mongod -f /etc/mongod3.conf
mongod -f /etc/mongod4.conf

  • 进入主节点配置复制集

mongo

> show dbs    //查看数据库

> rs.status()   //查看复制集状态

> cfg={"_id":"abc","members":[{"_id":0,"host":"192.168.144.112:27017"},{"_id":1,"host":"192.168.144.112:27018"},{"_id":2,"host":"192.168.144.112:27019"}]}    //配置复制集节点IP

> rs.initiate(cfg)      //初始化配置时保证从节点没有数据

> rs.status()   //此时再查看复制集状态 
  • 当能够看到如图状态,可以看到各节点状态代表复制集配置完成。

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第2张图片

3、复制集的节点添加和删除

abc:PRIMARY> rs.add("192.168.144.112:27020")    //添加节点

abc:PRIMARY> rs.remove("192.168.144.112:27020")    //删除节点

> rs.status()

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第3张图片

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第4张图片

4、故障转移切换

自动切换

ps aux | grep mongod

  • 模拟故障,复制集完成自动切换

kill -9 46374

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第5张图片
MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第6张图片

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第7张图片

手动切换

abc:PRIMARY> rs.freeze(30)      //暂停30s不参与选举

abc:PRIMARY> rs.stepDown(60,30)   //交出主节点位置,维持从节点状态不少于60秒,等待30秒使主节点和从节点日志同步

MongoDB复制选举

1、复制原理

  • 复制是基于操作日志oplog,相当于MySQL中的二进制日志,只记录发生改变的记录,复制是将主节点的oplog日志同步并应用到其他从节点的过程。

2、选举的原理

  • 节点类型分为:标准(host)节点、被动(passive)和仲裁(arbiter)节点。

  • (1)只有标准节点可以被选举为活跃(primary)节点,有选举权,被动节点有完整副本,不可能成为活跃节点,有选举权,仲裁节点不复制数据,不可能成为活跃节点,只有选举权。
  • 标准节点与被动节点的区别:priority优先级值高者是标准节点,低着则为被动节点。
  • 选举规则是票数高者获胜,priority是优先权为0~100的值,相当于额外增加的0~100的票数。

复制选举配置

  • 如上一小节,打开配置文件中复制功能:
replication:
  replSetName: abc

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第8张图片

选举节点设置

mongo //进入数据库

cfg={"_id":"abc","members":[{"_id":0,"host":"192.168.144.112:27017","priority":100},{"_id":1,"host":"192.168.144.112:27018","priority":100},{"_id":2,"host":"192.168.144.112:27019","priority":0},{"_id":3,"host":"192.168.144.112:27020","arbiterOnly":true}]}
//设置节点IP端口以及节点类型

> rs.initiate(cfg)    //初始化数据库

> rs.isMaster()       //查看状态

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第9张图片

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第10张图片

  • 在主节点所有的修改操作将会被记录在oplog日志中,下面将模拟修改操作,以及查看oplog日志记录。
abc:PRIMARY> use kgc   //创建数据库

abc:PRIMARY> db.t1.insert({"id":1,"name":"tom"})   //创建集合t1并插入数据

abc:PRIMARY> db.t1.insert({"id":2,"name":"jerry"})

abc:PRIMARY> db.t1.find()   //查看集合数据

abc:PRIMARY> db.t1.update({"id":2},{$set:{"name":"jack"}})    //修改集合数据

abc:PRIMARY> db.t1.remove({"id":1})    //删除数据

abc:PRIMARY> use local     //进入oplog所在数据库

abc:PRIMARY> show collections    //查看所有集合
    oplog.rs                    //oplog集合

abc:PRIMARY> db.oplog.rs.find()     
//查看日志记录所有操作,此时从节点会从oplog中同步数据

模拟标准节点故障

  • 当标准节点1选举为primary时,为了模拟故障,直接选择关闭节点1

mongod -f /etc/mongod.conf --shutdown

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第11张图片

  • 进入节点2,查看节点2状态
  • 此时会选举第二个标准节点为主节点

mongo --port 27018

  • 当继续模拟标准节点2故障时,此时两个标准节点都不能工作,此时进入被动节点三,发现被动节点三不能成为主节点

mongo --port 27019

MongoDB复制集(实现选举复制、故障切换、升级oplog大小、认证复制)_第12张图片

允许从节点读取数据

  • 在标准节点上写入数据,其他节点上也会同步复制,如何从从节点上读取数据?

  • 进入从节点数据库

[root@localhost]# mongo --port 27018

abc:SECONDARY> show dbs   //此时从节点不允许读取数据

abc:SECONDARY> rs.slaveOk()        //允许默认从节点读取数据

abc:SECONDARY> show dbs   //再次查看时就可以了

查看复制状态信息

abc:SECONDARY> rs.help()     //查看命令帮助手册
abc:SECONDARY> rs.printReplicationInfo()
configured oplog size:   990MB
log length start to end: 1544secs (0.43hrs)
oplog first event time:  Mon Jul 16 2018 05:49:12 GMT+0800 (CST)
oplog last event time:   Mon Jul 16 2018 06:14:56 GMT+0800 (CST)
now:                     Mon Jul 16 2018 06:14:59 GMT+0800 (CST)

abc:SECONDARY> rs.printSlaveReplicationInfo()
source: 192.168.235.200:27018
    syncedTo: Mon Jul 16 2018 06:16:16 GMT+0800 (CST)
    0 secs (0 hrs) behind the primary 
source: 192.168.235.200:27019
    syncedTo: Mon Jul 16 2018 06:16:16 GMT+0800 (CST)
    0 secs (0 hrs) behind the primary 

abc:ARBITER> rs.printReplicationInfo()
cannot provide replication status from an arbiter.     
  //会发现仲裁节点并不具备数据复制

更改oplog日志大小

  • oplog即operation log的简写,存储在local数据库中。oplog中新操作会自动替换旧的操作,以保证oplog不会超过预设的大小。默认情况下,oplog大小会占用64位的实例5%的磁盘空间。
  • 在MongoDB复制的过程中,主节点应用业务操作修改到数据库中,然后记录这些操作到oplog中,从节点复制这些oplog,然后应用这些修改、这些操作是异步的,如果从节点的操作已经被主节点落下很远,oplog日志在从节点上还没执行完,oplog可能已经轮滚一圈了,从节点跟不上同步,复制就会停下,从节点需要重新做完整的同步,为了避免这种情况,尽量保证主节点的oplog足够大,能够存放相当长时间的操作记录。

查看当前oplog日志文件大小

abc:PRIMARY> db.printReplicationInfo()
configured oplog size:   1613.301513671875MB    //默认大小
log length start to end: 18650secs (5.18hrs)
oplog first event time:  Tue Jul 17 2018 11:08:30 GMT+0800 (CST)
oplog last event time:   Tue Jul 17 2018 16:19:20 GMT+0800 (CST)
now:                     Tue Jul 17 2018 16:19:21 GMT+0800 (CST)

离线升级,更改oplog日志大小

  • 针对于主节点服务器oplog日志大小,如果主节点服务器存在于复制集当中,我们需要先将主节点服务关闭,然后再在配置文件中关闭replication复制相关选项,并且修改端口号,因为如果端口号不改,当服务启动时,还是会被加入到复制集队列。将其服务作为单实例启动。

mongo

abc:PRIMARY> use admin
switched to db admin
abc:PRIMARY> db.shutdownServer()

也可以采用mongod -f /etc/mongod.conf --shutdown  方式关闭服务

vim /etc/mongod.conf

  • 注销replication:相关启动参数,并修改port端口号27027
...
# network interfaces
net:
  port: 27027     //修改端口
  bindIp: 0.0.0.0  # Listen to local interface only, comment to listen on all interfaces.

#security:

#operationProfiling:

#replication:       //注释复制功能
 # replSetName: abc
...
  • 主节点的单实例启动

mongo -f /etc/mongod.conf

  • 备份当前oplog日志

mongodump --port 27027 --db local --collection 'oplog.rs' //全备份当前节点oplog记录

  • 进入当前节点MongoDB

mongo --port 27027

> use local            //进入local数据库
> db.oplog.rs.drop()   //删除oplog原有集合
> db.runCommand( { create: "oplog.rs", capped: true, size: (2 * 1024 * 1024 * 1024) } )  //重建oplog,并指定大小
> use admin
> db.shutdownServer()   //关闭服务
  • 把配置文件修改回来
...
# network interfaces
net:
  port: 27017     //端口修改回原有端口
  bindIp: 0.0.0.0  # Listen to local interface only, comment to listen on all interfaces.

#security:

#operationProfiling:

replication:       //取消注释复制功能
  replSetName: abc
  oplogSizeMB:2048   //添加指定oplog日志大小
...
  • 启动节点服务

mongod -f /etc/mongod.conf
mongo --port 27017

abc:SECONDARY> db.printReplicationInfo()
configured oplog size:   2048MB       //oplog日志大小已经改变
log length start to end: 30secs (0.01hrs)
oplog first event time:  Tue Jul 17 2018 17:33:18 GMT+0800 (CST)
oplog last event time:   Tue Jul 17 2018 17:33:48 GMT+0800 (CST)
now:                     Tue Jul 17 2018 17:33:54 GMT+0800 (CST)
abc:SECONDARY> 

部署认证复制

mongo

  • 进入primary

    kgcrs:PRIMARY> use admin
    kgcrs:PRIMARY> db.createUser({"user":"root","pwd":"123","roles":["root"]})   //创建管理用户,并且使用管理用户认证
  • 在每个实例配置文件中打开认证功能

[root@localhost]# vim /etc/mongod.conf
[root@localhost]# vim /etc/mongod2.conf
[root@localhost]# vim /etc/mongod3.conf
[root@localhost]# vim /etc/mongod4.conf

...
security:
   keyFile: /usr/bin/kgcrskey1
   clusterAuthMode: keyFile
...

cd /usr/bin/

  • 创建认证文件,并且输入统一认证密匙

    [root@localhost bin]# echo "kgcrs key"> kgcrskey1
    [root@localhost bin]# echo "kgcrs key"> kgcrskey2
    [root@localhost bin]# echo "kgcrs key"> kgcrskey3
    [root@localhost bin]# echo "kgcrs key"> kgcrskey4
    [root@localhost bin]# chmod 600 kgcrskey{1..4}     //设置权限,只有属主可以查看
  • 重启四个实例
进入primary
kgcrs:PRIMARY> show dbs   //无法查看数据库
kgcrs:PRIMARY> rs.status()   ///无法查看复制集

kgcrs:PRIMARY> use admin    //身份登录验证
kgcrs:PRIMARY> db.auth("root","123")

kgcrs:PRIMARY> rs.status()  //可以查看数据库
kgcrs:PRIMARY> show dbs   //可以查看复制集