0

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

4

1 回答 1

1

如果负载允许,您可以为此服务器或同一服务器使用复制和附加服务器。

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

    • 您要更新的服务器(提醒 WiredTiger 自 3.0 起支持)。
    • 可以在附加服务器上运行的第二个 MongoDB 实例。数据库将通过复制临时复制到它。
    • 而MongoDB的第三个实例是arbiter,它不存储数据,只参与主服务器的选举。仲裁器可以在单独端口上的附加服务器上运行。
  2. 无论如何,您需要备份您的数据库。您可以不带参数运行“<em>mongodump”,并且将使用数据库转储创建目录“<em>./dump”。您可以使用“<em>--gzip”参数来压缩结果大小。

    mongodump --gzip
    

    以防万一,恢复命令:

    mongorestore --gzip
    

    如果在“<em>mongodump”中使用,它应该在“<em>./dump”目录和“<em>--gzip”参数应该添加的同一目录中运行。

  3. 从附加服务器开始配置。我的目标系统是没有网络的Linux RedHat,所以我通过RPM手动下载并安装了MongoDB。将该部分添加到/etc/mongod.conf

    replication:
       oplogSizeMB: 10240
       replSetName: REPLICA  
    

    检查 net 部分是否看起来像这样以允许来自其他服务器的访问:

    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 }
    

    因此,您需要尽快通过“<em>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(),因为默认情况下,主服务器的名称将配置为/etc/hostname中的 DNS-name 。这对我来说不是很方便,因为我在项目中使用 IP 地址进行通信。

    要检查同步进度,您可以从“<em>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
    }
    

    在附加服务器的“<em>stateStr”将从“<em>STARTUP2”替换为“<em>SECONDARY”后,我们的服务器将同步。

  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 legacy,你应该使用mongo::DBClientReplicaSet而不是mongo::DBClientConnection并在连接参数中列出所有三个服务器,包括仲裁器。

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

  8. 在同步结束并且附加服务器状态建立为SECONDARY后,我们需要通过在主服务器上的“<em>mongo”控制台中执行命令来切换PRIMARYSECONDARY 。这很重要,因为命令在附加服务器上不起作用。

    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 中删除所有“<em>replication”部分并重新启动 MongoDB:

    service mongod restart
    

    在这些之后,我们在通过“<em>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.
    

    要摆脱它,您需要删除数据库“<em>local”。默认状态下,该数据库中只有一个集合“<em>startup_log”,因此您可以通过“<em>mongo”控制台进行操作,无需担心

    use local
    db.dropDatabase()
    

    并重新启动 MongoDB:

    service mongod restart
    

    如果您从/etc/mongod.conf中删除“<em>replication”部分之前的“<em>local”数据库,它会立即恢复。所以我不能只重启一次 MongoDB。

  14. 在附加服务器上执行相同的操作:

    • 从/etc/mongod.conf中删除“<em>replication”部分
    • 重启 MongoDB
    • 删除“<em>local”数据库
    • 再次重启
  15. 仲裁者只是停止并删除:

    pkill -f /tmp/mongo
    rm -r /tmp/mongo
    
于 2017-02-01T08:29:43.783 回答