MongoDB副本集配置和数据迁移实战

MongoDB副本集配置和数据迁移实战

https://gitee.com/et/ops/blob/master/MongoDB副本集配置和数据迁移实战.md

环境:Ubuntu 16.04, MongoDB 3.6

基本概念

MongoDB 的副本集就是有自动故障恢复功能的 MongoDB 主从集群。由于 MongoDB 的主从复制功能不支持高可用,所以从 3.2 版本开始已经被废弃了,转而用副本集来代替。一个副本集总会有一个活跃节点(Primary)和若干个备份节点(Secondary),还有一个可选的一个仲裁者(Arbiter)节点来实现HA中的故障切换。

准备工作

配置副本集 Primary 和 Secondary 节点

  • 创建数据目录

    $ mkdir -p /mnt/mongodb/replset

  • 启动名为“my-repl”的副本集,端口为27017,绑定到任意IP(也可以指定IP)

    $ mongod --dbpath /mnt/mongodb/replset --port 27017 --replSet "my-repl" --bind_ip_all

  • 初始化副本集

    • 用mongo客户端连接 Primary 节点:

      $ mongo

    • 执行初始化脚本来创建副本集:

      rs.initiate({ _id:"my-repl", members:[ {_id:0, host:"192.168.10.58:27017"}, {_id:1, host:"192.168.10.59:27017"} ] });

    输出结果:

    1{ 2 "ok" : 1, 3 "operationTime" : Timestamp(1523237919, 1), 4 "$clusterTime" : { 5 "clusterTime" : Timestamp(1523237919, 1), 6 "signature" : { 7 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), 8 "keyId" : NumberLong(0) 9 } 10 } 11}
    • 查看配置结果

      rs.conf(); { "_id" : "my-repl", "version" : 1, "protocolVersion" : NumberLong(1), "members" : [ { "_id" : 0, "host" : "192.168.10.58:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : {

      1 }, 2 "slaveDelay" : NumberLong(0), 3 "votes" : 1 4 }, 5 { 6 "_id" : 1, 7 "host" : "192.168.10.59:27017", 8 "arbiterOnly" : false, 9 "buildIndexes" : true, 10 "hidden" : false, 11 "priority" : 1, 12 "tags" : { 13 14 }, 15 "slaveDelay" : NumberLong(0), 16 "votes" : 1 17 } 18], 19"settings" : { 20 "chainingAllowed" : true, 21 "heartbeatIntervalMillis" : 2000, 22 "heartbeatTimeoutSecs" : 10, 23 "electionTimeoutMillis" : 10000, 24 "catchUpTimeoutMillis" : -1, 25 "catchUpTakeoverDelayMillis" : 30000, 26 "getLastErrorModes" : { 27 28 }, 29 "getLastErrorDefaults" : { 30 "w" : 1, 31 "wtimeout" : 0 32 }, 33 "replicaSetId" : ObjectId("5acac41fded47067da446ddd") 34}

      }

    配置过程非常简单,可以看到在副本集成员中有0和1两个节点,此时主从两个服务器已经可以工作了,服务器0(Primary)有任何数据的变化都会同步到服务器1(Secondary)上。但是,此时的副本集只是提供了数据备份的功能,并不能达到高可用。如果要达到这一点,那么需要配置一个仲裁者节点(Arbiter)

配置仲裁者(Arbiter)

仲裁者在 Primary 节点发生故障时,参与副本集的选举投票决定哪个副本成为 Primary 节点。仲裁节点不保存数据也不会成为 Primary 节点。

  • 仲裁者通常不部署在大磁盘空间的服务器上,因此为了最小化默认创建数据,修改配置:

    1$ vim /etc/mongod.conf 2 3 4storage.journal.enabled=false 5storage.mmapv1.smallFiles = true.
  • 创建仲裁者目录并启动服务

    1$ mkdir /mnt/mongodb/arbiter 2$ mongod --port 27017 --dbpath /mnt/mongodb/arbiter --replSet 'my-repl' --bind_ip_all
  • 把仲裁者添加到副本集中

    • 连接至 Primary 服务器

      1$mongo --host 192.168.10.58 2 3 4my-repl:PRIMARY> rs.addArb("192.168.10.57:27017") 5{ 6 "ok" : 1, 7 "operationTime" : Timestamp(1523326877, 1), 8 "$clusterTime" : { 9 "clusterTime" : Timestamp(1523326877, 1), 10 "signature" : { 11 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), 12 "keyId" : NumberLong(0) 13 } 14 } 15}
  • 查看副本集的效果:

    1>rs.status(); 2my-repl:PRIMARY> rs.status(); 3{ 4 "set" : "my-repl", 5 "date" : ISODate("2018-04-10T02:21:44.826Z"), 6 "myState" : 1, 7 "term" : NumberLong(2), 8 "heartbeatIntervalMillis" : NumberLong(2000), 9 "optimes" : { 10 "lastCommittedOpTime" : { 11 "ts" : Timestamp(1523326895, 1), 12 "t" : NumberLong(2) 13 }, 14 "readConcernMajorityOpTime" : { 15 "ts" : Timestamp(1523326895, 1), 16 "t" : NumberLong(2) 17 }, 18 "appliedOpTime" : { 19 "ts" : Timestamp(1523326895, 1), 20 "t" : NumberLong(2) 21 }, 22 "durableOpTime" : { 23 "ts" : Timestamp(1523326895, 1), 24 "t" : NumberLong(2) 25 } 26 }, 27 "members" : [ 28 { 29 "_id" : 0, 30 "name" : "192.168.10.58:27017", 31 "health" : 1, 32 "state" : 1, 33 "stateStr" : "PRIMARY", 34 "uptime" : 2891, 35 "optime" : { 36 "ts" : Timestamp(1523326895, 1), 37 "t" : NumberLong(2) 38 }, 39 "optimeDate" : ISODate("2018-04-10T02:21:35Z"), 40 "electionTime" : Timestamp(1523324284, 1), 41 "electionDate" : ISODate("2018-04-10T01:38:04Z"), 42 "configVersion" : 2, 43 "self" : true 44 }, 45 { 46 "_id" : 1, 47 "name" : "192.168.10.59:27017", 48 "health" : 1, 49 "state" : 2, 50 "stateStr" : "SECONDARY", 51 "uptime" : 2624, 52 "optime" : { 53 "ts" : Timestamp(1523326895, 1), 54 "t" : NumberLong(2) 55 }, 56 "optimeDurable" : { 57 "ts" : Timestamp(1523326895, 1), 58 "t" : NumberLong(2) 59 }, 60 "optimeDate" : ISODate("2018-04-10T02:21:35Z"), 61 "optimeDurableDate" : ISODate("2018-04-10T02:21:35Z"), 62 "lastHeartbeat" : ISODate("2018-04-10T02:21:43.080Z"), 63 "lastHeartbeatRecv" : ISODate("2018-04-10T02:21:43.083Z"), 64 "pingMs" : NumberLong(0), 65 "syncingTo" : "192.168.10.58:27017", 66 "configVersion" : 2 67 }, 68 { 69 "_id" : 2, 70 "name" : "192.168.10.57:27017", 71 "health" : 1, 72 "state" : 7, 73 "stateStr" : "ARBITER", 74 "uptime" : 27, 75 "lastHeartbeat" : ISODate("2018-04-10T02:21:43.079Z"), 76 "lastHeartbeatRecv" : ISODate("2018-04-10T02:21:42.088Z"), 77 "pingMs" : NumberLong(0), 78 "configVersion" : 2 79 } 80 ], 81 "ok" : 1, 82 "operationTime" : Timestamp(1523326895, 1), 83 "$clusterTime" : { 84 "clusterTime" : Timestamp(1523326895, 1), 85 "signature" : { 86 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), 87 "keyId" : NumberLong(0) 88 } 89 } 90}

    可以看到状态显示:服务器0为 Primary, 服务器1为 Secondary, 服务器2为 Arbiter。
    此时带有高可用的副本集已经配置完成,Arbiter 会监控 Primary 节点的运行情况,如果服务器0发生了宕机,那么仲裁者 Arbiter 节点会发起选举,最终选取多个 Secondary 中的某一个来作为 Primary 节点。我们测试的架构中只有一个 Secondary 节点,那么此服务器1就会成为 Primary。而当服务器0恢复工作时,它会被当成 Secondary 来运行。

  • 副本优先级
    副本集会在 Primary 节点出现故障时把 Secondary 提升为 Primary,但是很多情况下 Secondary 只是作为备用节点,我们不希望它长期作为 Primary 节点运行。那么为了达到这个目的,我们修改副本的优先级。

    • 连接 Primary 节点,执行以下脚本:

      cfg = rs.conf() cfg.members[0].priority = 10 cfg.members[1].priority = 5 rs.reconfig(cfg) { "ok" : 1, "operationTime" : Timestamp(1523411797, 2), "$clusterTime" : { "clusterTime" : Timestamp(1523411797, 2), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }

    • 如果在非 Prmiary 上比如Arbiter上运行,会报下面的错误:

      { "ok" : 0, "errmsg" : "replSetReconfig should only be run on PRIMARY, but my state is ARBITER; use the "force" argument to override", "code" : 10107, "codeName" : "NotMaster" }

    • 以上操作让服务器0的优先级高于服务器1,那么当服务器0从故障中恢复时,它会重新成为 Primary 节点来提供服务。


数据迁移

在配置副本集之前,你可能已经存在了一个单独的 MongoDB 实例存储了一些数据,你需要把原来实例中的数据迁移到新的副本集中。(你也可以一开始就把原来的单个实例配置成副本集的 Primary 节点,然后新增副本来同步数据,此方法不在本文讨论范围之内)

  • 登录原实例所在的服务器,导出数据:

    $ mongoexport -h localhost -p 27017 -u xxx -p xxx -d MY_DB_NAME -c MY_COLLECTION_NAME -o MY_COLLECTION_NAME.dmp
    

    在阿里云上测试了一个导出数据大约为1.2G大小的集合,导出性能如下:

    • 时间:3分11秒
    • 导出1728423条记录,每秒读取记录数=1728423/191=9050条/秒
    • 导出1264441038字节,每秒处理字节数=1264441038/191=6.6M/秒
  • 将导出的数据文件 MY_COLLECTION_NAME.dmp 已任何方式(比如scp)同步到 Primary 节点所在的服务器0上

  • 导入数据至副本集 Primay 节点

    mongoimport -h my-repl/192.168.10.58:27017 -d MY_DB_NAME -c MY_COLLECTION_NAME --file MY_COLLECTION_NAME.dmp
    

    测试导入性能

    • 时间:82秒
    • 导入1728423条记录,每秒写入记录数=1728423/82=21078条/秒
    • 导入1264441038字节,每秒处理字节数=1264441038/82=14.7M/秒

    注意:由于不是相同的服务器,所以不能通过这个来比较导入和导出的性能差别,只能所谓一个参考:

  • 总结:

    • 在 Primary 节点导入数据后,登录 Secondary 节点查看,可以看到一百七十多万条数据全部复制过去了,主从复制成功。
    • 从性能分析结果来看,MongoDB的读取和写入性能是比较好的,特别是导入的同时还要和副本之间同步数据。
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

NoSQL之MongoDB

1.mongodb介绍2.mongodb安装3.连接mongodb4.mongodb用户管理5.mongodb创建集合、数据管理6.php的mongodb扩展7.php的mongo扩展8.mongodb副本集介绍9.mongodb副本集搭建10.mongodb副本集测试11.mongodb分片介

MongoDB 副本集之入门篇

前言:mongodb因为高性能、高可用性、支持分片等特性,作为非关系型数据库被大家广泛使用。其高可用性主要是体现在mongodb的副本集上面(可以简单理解为一主多从的集群),本篇文章主要从副本集介绍、本地搭建副本集、副本集读写数据这三个方面来带大家认识下mongodb副本集。一、mongodb副本集介绍—

MongoDB——主从复制&副本集

MongoDB——主从复制&副本集博客分类:javamongodb前面我说到了,MongoDB数据库支持服务器之间的数据复制。支持主从模式及服务器之间的相互复制。目的当然是实现负载均衡与故障恢复。Mongo中内置了两种技术:主从复制、副本集。下面就简单介绍这两种模式的配置。一、   主从复制主从复制是一个简单的数