本文介绍了如何在不使用mongodump/mongorestore的情况下以最少的停机时间从MMAPv1迁移到WiredTiger的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大多数指南建议使用mongodump/mongorestore,但是对于大型产品数据库,停机时间可能非常长

解决方案

如果负载允许,您可以为此服务器使用复制和其他服务器,也可以使用同一服务器.

  1. 您需要3个正在运行的MongoDB实例:

    • 您要更新的服务器(提醒您从3.0开始支持WiredTiger).
    • 可以在其他服务器上运行的MongoDB的第二个实例.数据库将通过复制临时复制到数据库中.
    • MongoDB的第三个实例是仲裁器,它不存储数据,仅参与主服务器的选举.仲裁程序可以在其他服务器上的单独端口上运行.
  2. 无论如何,您都需要备份数据库.您可以运行不带参数的" mongodump ",并且将使用数据库转储创建目录" ./dump ".您可以使用"-gzip "参数来压缩结果大小.

    mongodump --gzip
    

    以防万一,恢复命令:

    mongorestore --gzip
    

    如果在" mongodump"中使用,则应在添加" ./dump "目录和"-gzip "参数的目录下运行".

  3. 从其他服务器开始配置.我的目标系统是没有Internet的Linux RedHat,因此我通过RPM手动下载并安装MongoDB.将该部分添加到/etc/mongod.conf :

    replication:
       oplogSizeMB: 10240
       replSetName: REPLICA  
    

    检查网段是否看起来像这样,以允许从其他服务器进行访问:

    net:
      bindIp: 0.0.0.0
      port: 27017
    

    并运行:

    service mongod start
    

  4. 运行第三个MongoDB实例-仲裁器.它可以在其他端口上的其他服务器上工作.为仲裁服务器创建一个临时目录:

    mkdir /tmp/mongo
    chmod 777 -R /tmp/mongo
    

    并运行:

    mongod --dbpath /tmp/mongo --port 27001 --replSet REPLICA \
        --fork --logpath /tmp/mongo/db1.log
    

  5. 现在配置主服务器.编辑/etc/mongod.conf

    replication:
       oplogSizeMB: 10240
       replSetName: REPLICA   
    

    并在主服务器上重新启动MongoDB:

    service mongod restart
    

  6. 这很重要!重新启动主服务器后,读取操作可能不可用.我收到以下错误:

    { "ok" : 0, "errmsg" : "node is recovering", "code" : 13436 }
    

    因此,您需要尽快通过" mongo "控制台连接到主服务器上的MongoDB,并运行以下命令来配置复制:

    rs.initiate(
    {
      _id: "REPLICA",
      members: [
        { _id: 0, host : "<IP address of main server>:27017",
                  priority: 1.0 },
        { _id: 1, host : "<IP  address of additional server>:27017",
                  priority: 0.5 },
        { _id: 2, host : "<IP address of additional server(the arbiter)>:27001", 
                  arbiterOnly : true,  priority: 0.5  }
      ]
    }
    )
    

    执行此操作后,将可以使用MongoDB进行所有操作,并开始数据同步.

    与大多数教程一样,我不建议在不带参数的主服务器上使用 rs.initiate(),因为默认情况下,主服务器的名称将被配置为DNS名称. /etc/hostname .这对我来说不是很方便,因为我在项目中使用IP地址进行通信.

    要检查同步进度,可以从" mongo "控制台调用:

    rs.status()
    

    结果示例:

    {
       "set" : "REPLICA",
       "date" : ISODate("2017-01-19T14:30:34.292Z"),
       "myState" : 1,
       "term" : NumberLong(1),
       "heartbeatIntervalMillis" : NumberLong(2000),
       "members" : [
           {
               "_id" : 0,
               "name" : "<IP address of main server>:27017",
               "health" : 1.0,
               "state" : 1,
               "stateStr" : "PRIMARY",
               "uptime" : 165,
               "optime" : {
                   "ts" : Timestamp(6377323060650835, 3),
                   "t" : NumberLong(1)
               },
               "optimeDate" : ISODate("2017-01-19T14:30:33.000Z"),
               "infoMessage" : "could not find member to sync from",
               "electionTime" : Timestamp(6377322974751490, 1),
               "electionDate" : ISODate("2017-01-19T14:30:13.000Z"),
               "configVersion" : 1,
               "self" : true
           },
           {
               "_id" : 1,
               "name" : "<IP address of additional server>:27017",
               "health" : 1.0,
               "state" : 5,
               "stateStr" : "STARTUP2",
               "uptime" : 30,
               "optime" : {
                   "ts" : Timestamp(0, 0),
                   "t" : NumberLong(-1)
               },
               "optimeDate" : ISODate("1970-01-01T00:00:00.000Z"),
               "lastHeartbeat" : ISODate("2017-01-19T14:30:33.892Z"),
               "lastHeartbeatRecv" : ISODate("2017-01-19T14:30:34.168Z"),
               "pingMs" : NumberLong(3),
               "syncingTo" : "<IP address of main server>:27017",
               "configVersion" : 1
           },
           {
               "_id" : 2,
               "name" : "<IP address of additional server (the arbiter)>:27001",
               "health" : 1.0,
               "state" : 7,
               "stateStr" : "ARBITER",
               "uptime" : 30,
               "lastHeartbeat" : ISODate("2017-01-19T14:30:33.841Z"),
               "lastHeartbeatRecv" : ISODate("2017-01-19T14:30:30.158Z"),
               "pingMs" : NumberLong(0),
               "configVersion" : 1
           }
       ],
       "ok" : 1.0
    }
    

    将其他服务器的" stateStr "从" STARTUP2 "替换为" SECONDARY "后,我们的服务器即被同步. /p>

  7. 在等待同步结束时,有必要对客户端应用程序进行一些修改,使其可以与副本中的所有服务器一起使用.

    • 如果使用ConnectionString,则应将其替换为以下内容:

      mongodb://<IP address of main server>:27017,<IP address of additional server>:27017,<IP address of additional server (the arbiter)>:27001/?replicaSet=REPLICA
      

    • 如果您使用的是C ++ mongo-cxx-driver旧版,则应使用 mongo :: DBClientReplicaSet 代替 mongo :: DBClientConnection 并列出所有三个服务器的连接参数,包括仲裁器.

    • 还有第三种选择-切换 PRIMARY - SECONDARY 后,您可以简单地在客户端中更改MongoDB服务器的IP,但这不是很公平.

  8. 同步结束后,另外一个服务器状态为 SECONDARY ,我们需要切换 PRIMARY SECONDARY 通过在主服务器上的" mongo "控制台中执行命令.这很重要,因为命令将无法在其他服务器上使用.

    cfg = rs.conf()
    cfg.members[0].priority = 0.5
    cfg.members[1].priority = 1
    cfg.members[2].priority = 0.5
    rs.reconfig(cfg)
    

    然后通过执行以下命令检查服务器状态:

    rs.status()
    

  9. 在主服务器上停止MongoDB

    service mongod stop
    

    ,只需删除数据库目录的全部内容.这是安全的,因为我们在附加服务器上有一个工作副本,并且在一开始就进行了备份.当心. MongoDB本身不会创建数据库目录.如果已删除,则不仅需要还原

    mkdir /var/lib/mongo
    

    和设置所有者:

    chown -R mongod:mongod /var/lib/mongo
    

  10. 检查存储引擎wiredTiger是在/etc/mongod.conf 中配置的.从3.2开始,默认使用它:

    storage:
         ...
        engine: wiredTiger
        ...
    

    并运行MongoDB:

    service mongod start
    

    主服务器将自动从辅助服务器获取配置,数据将同步回WiredTiger存储.

  11. 同步完成后,请切换回 PRIMARY 服务器.此操作应在其他服务器上执行,因为它现在是 PRIMARY .

    cfg = rs.conf()
    cfg.members[0].priority = 1
    cfg.members[1].priority = 0.5
    cfg.members[2].priority = 0.5
    rs.reconfig(cfg)
    

  12. 返回旧版本的数据库客户端,或者将 ConnectionString 改回.

  13. 现在如有必要,请关闭复制.从主服务器中删除2个复制服务器:

    rs.remove("<IP address of additional server>:27017")
    rs.remove("<IP address of additional server (the arbiter)>:27001")
    

    /etc/mongod.conf 中删除所有"复制"部分,然后重新启动MongoDB:

    service mongod restart
    

    之后,通过" mongo "控制台连接时,我们会收到警告:

    2017-01-19T12:26:51.948+0300 I STORAGE  [initandlisten] ** WARNING: mongod started without --replSet yet 1 documents are present in local.system.replset
    2017-01-19T12:26:51.948+0300 I STORAGE  [initandlisten] **          Restart with --replSet unless you are doing maintenance and  no other clients are connected.
    2017-01-19T12:26:51.948+0300 I STORAGE  [initandlisten] **          The TTL collection monitor will not start because of this.
    

    要摆脱它,您需要删除数据库" local ".在默认状态下,该数据库中只有一个集合" startup_log ",因此您可以通过" mongo "控制台

    轻松执行此操作.

    use local
    db.dropDatabase()
    

    并重新启动MongoDB:

    service mongod restart
    

    如果要从/etc/mongod.conf 中的"复制"部分之前删除" local "数据库,则将立即还原该数据库. .所以我不能只重启一次MongoDB.

  14. 在其他服务器上执行相同的操作:

    • /etc/mongod.conf
    • 中删除"复制"部分
    • 重新启动MongoDB
    • 删除"本地"数据库
    • 再次重启
  15. 仲裁者只需停止并删除:

    pkill -f /tmp/mongo
    rm -r /tmp/mongo
    

Most guidelines recommend to use mongodump/mongorestore, but for large product databases downtime can be very long

解决方案

You can use replication and an additional server for this or the same server if the load allows.

  1. You need 3 running MongoDB instance:

    • Your server you want to update (remind that WiredTiger support since 3.0).
    • Second instance of MongoDB which can be run on an additional server. Database will be temporarily copied to it by the replication.
    • And the third instance of MongoDB is arbiter, which doesn’t store data and only participates in the election of primary server. The arbiter can be run on the additional server on a separate port.
  2. Anyway you need to backup your database. You can run "mongodump" without parameters and directory "./dump" will be created with the database dump. You can use "--gzip" parameter to compress result size.

    mongodump --gzip
    

    Just in case, the command to restore:

    mongorestore --gzip
    

    It should be run in the same directory where "./dump" dir and "--gzip" parameter should be added if used in "mongodump".

  3. Begin configure from the additional server. My target system is Linux RedHat without Internet, so I download and install MongoDB via RPM manually. Add the section to /etc/mongod.conf:

    replication:
       oplogSizeMB: 10240
       replSetName: REPLICA  
    

    Check that the net section look like this to allow access from other servers:

    net:
      bindIp: 0.0.0.0
      port: 27017
    

    and run:

    service mongod start
    

  4. Run the third MongoDB instance - arbiter. It can work on the additional server on a different port. Create a temporary directory for the arbiter database:

    mkdir /tmp/mongo
    chmod 777 -R /tmp/mongo
    

    and run:

    mongod --dbpath /tmp/mongo --port 27001 --replSet REPLICA \
        --fork --logpath /tmp/mongo/db1.log
    

  5. Now configure the main server. Edit /etc/mongod.conf

    replication:
       oplogSizeMB: 10240
       replSetName: REPLICA   
    

    and restart MongoDB on the main server:

    service mongod restart
    

  6. It’s important! After restarting the main server read operations may be unavailable. I was getting the following error:

    { "ok" : 0, "errmsg" : "node is recovering", "code" : 13436 }
    

    So as quickly as possible you need to connect to MongoDB on the main server via "mongo" console and run the following command to configure replication:

    rs.initiate(
    {
      _id: "REPLICA",
      members: [
        { _id: 0, host : "<IP address of main server>:27017",
                  priority: 1.0 },
        { _id: 1, host : "<IP  address of additional server>:27017",
                  priority: 0.5 },
        { _id: 2, host : "<IP address of additional server(the arbiter)>:27001", 
                  arbiterOnly : true,  priority: 0.5  }
      ]
    }
    )
    

    After this operation all actions with MongoDB will be available and data synchronization will be started.

    I don’t recommend to use rs.initiate() on the main server without parameters as in most tutorials, because name of the main server will be configured by default as DNS-name from the /etc/hostname. It's not very convenient for me because I use IP-addresses for communications in my projects.

    To check the synchronization progress you can call from "mongo" console:

    rs.status()
    

    Result example:

    {
       "set" : "REPLICA",
       "date" : ISODate("2017-01-19T14:30:34.292Z"),
       "myState" : 1,
       "term" : NumberLong(1),
       "heartbeatIntervalMillis" : NumberLong(2000),
       "members" : [
           {
               "_id" : 0,
               "name" : "<IP address of main server>:27017",
               "health" : 1.0,
               "state" : 1,
               "stateStr" : "PRIMARY",
               "uptime" : 165,
               "optime" : {
                   "ts" : Timestamp(6377323060650835, 3),
                   "t" : NumberLong(1)
               },
               "optimeDate" : ISODate("2017-01-19T14:30:33.000Z"),
               "infoMessage" : "could not find member to sync from",
               "electionTime" : Timestamp(6377322974751490, 1),
               "electionDate" : ISODate("2017-01-19T14:30:13.000Z"),
               "configVersion" : 1,
               "self" : true
           },
           {
               "_id" : 1,
               "name" : "<IP address of additional server>:27017",
               "health" : 1.0,
               "state" : 5,
               "stateStr" : "STARTUP2",
               "uptime" : 30,
               "optime" : {
                   "ts" : Timestamp(0, 0),
                   "t" : NumberLong(-1)
               },
               "optimeDate" : ISODate("1970-01-01T00:00:00.000Z"),
               "lastHeartbeat" : ISODate("2017-01-19T14:30:33.892Z"),
               "lastHeartbeatRecv" : ISODate("2017-01-19T14:30:34.168Z"),
               "pingMs" : NumberLong(3),
               "syncingTo" : "<IP address of main server>:27017",
               "configVersion" : 1
           },
           {
               "_id" : 2,
               "name" : "<IP address of additional server (the arbiter)>:27001",
               "health" : 1.0,
               "state" : 7,
               "stateStr" : "ARBITER",
               "uptime" : 30,
               "lastHeartbeat" : ISODate("2017-01-19T14:30:33.841Z"),
               "lastHeartbeatRecv" : ISODate("2017-01-19T14:30:30.158Z"),
               "pingMs" : NumberLong(0),
               "configVersion" : 1
           }
       ],
       "ok" : 1.0
    }
    

    After "stateStr" of the additional server will be replaced from "STARTUP2" to "SECONDARY", our servers are synchronized.

  7. While we wait for the end of the synchronization, it is necessary to modify client applications a little bit they can work with all servers in replica.

    • If you use the ConnectionString, you should replace it with something like:

      mongodb://<IP address of main server>:27017,<IP address of additional server>:27017,<IP address of additional server (the arbiter)>:27001/?replicaSet=REPLICA
      

    • If you use C++ mongo-cxx-driver legacy, as I am, you should to use mongo::DBClientReplicaSet instead mongo::DBClientConnection and list all three servers in connection parameters, including the arbiter.

    • There is a third option - you can simply change IP of MongoDB server in clients after switching PRIMARY-SECONDARY, but it's not very fair.

  8. After the synchronization has ended and an additional server status has established as SECONDARY, we need to switch the PRIMARY and SECONDARY by executing the command in "mongo" console on the main server. This is important because command will not work on the additional server.

    cfg = rs.conf()
    cfg.members[0].priority = 0.5
    cfg.members[1].priority = 1
    cfg.members[2].priority = 0.5
    rs.reconfig(cfg)
    

    Then check server status by executing:

    rs.status()
    

  9. Stop the MongoDB on the main server

    service mongod stop
    

    and simply delete the entire contents of a directory with database. It is safe, because we have a working copy on the additional server, and in the beginning we have made a backup. Be careful. MongoDB doesn’t create a database directory itself. If you've deleted it, you need not only to restore

    mkdir /var/lib/mongo
    

    and setup owner:

    chown -R mongod:mongod /var/lib/mongo
    

  10. Check storage engine wiredTiger is configured in /etc/mongod.conf. From 3.2 it is used by default:

    storage:
         ...
        engine: wiredTiger
        ...
    

    And run MongoDB:

    service mongod start
    

    The main server will get the configuration from the secondary server automatically and data will be synced back to WiredTiger storage.

  11. After the synchronization is finished switch the PRIMARY server back. This operation should be performed on an additional server because it is the PRIMARY now.

    cfg = rs.conf()
    cfg.members[0].priority = 1
    cfg.members[1].priority = 0.5
    cfg.members[2].priority = 0.5
    rs.reconfig(cfg)
    

  12. Return the old version of database clients or change ConnectionString back.

  13. Now turn off replication if necessary. Remove 2 replication servers from the main server:

    rs.remove("<IP address of additional server>:27017")
    rs.remove("<IP address of additional server (the arbiter)>:27001")
    

    Remove all "replication" section from /etc/mongod.conf and restart MongoDB:

    service mongod restart
    

    After these we get the warning when connected via the "mongo" console:

    2017-01-19T12:26:51.948+0300 I STORAGE  [initandlisten] ** WARNING: mongod started without --replSet yet 1 documents are present in local.system.replset
    2017-01-19T12:26:51.948+0300 I STORAGE  [initandlisten] **          Restart with --replSet unless you are doing maintenance and  no other clients are connected.
    2017-01-19T12:26:51.948+0300 I STORAGE  [initandlisten] **          The TTL collection monitor will not start because of this.
    

    To get rid of it, you need to remove the database "local". There is only one collection "startup_log" in this database in default state, so you can do this without fear via "mongo" console

    use local
    db.dropDatabase()
    

    and restart MongoDB:

    service mongod restart
    

    If you will remove the "local" database before "replication" section from /etc/mongod.conf, it is immediately restored. So I could not do only one MongoDB restart.

  14. On the additional server perform the same action:

    • remove "replication" section from /etc/mongod.conf
    • restart MongoDB
    • drop the "local" database
    • again restart
  15. The arbiter just stop and remove:

    pkill -f /tmp/mongo
    rm -r /tmp/mongo
    

这篇关于如何在不使用mongodump/mongorestore的情况下以最少的停机时间从MMAPv1迁移到WiredTiger的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-22 06:04