主从复制

在本页面

Warning

自版本 3.6 起不推荐使用:MongoDB 3.6 不推荐使用主从复制。

自 MongoDB 3.2 起,分片群集组件已弃用主从复制。

Important

大多数情况下,Replica sets替换master-slave复制。如果可能,请对所有新生产部署使用副本集而不是主从复制。该文档仅用于支持旧式部署,并且仅用于存档目的。

除了提供主从部署的所有功能外,副本集还更适合生产使用。主从复制位于副本集之前,可以有大量的非主(即从)节点,并且可以将复制操作限制为仅一个数据库;但是,主从复制提供的冗余较少,并且无法自动执行故障转移。请参阅使用副本集部署等效的主从服务器以获取与主从复制等效的副本集配置。如果希望将现有的主从部署转换为副本集,请参见将主从部署转换为副本集

Fundamental Operations

Initial Deployment

要配置master-slave部署,请启动两个mongod实例:一个在主模式下,另一个在从模式下。

要以主模式启动mongod实例,请按以下方式调用mongod

mongod --master --dbpath /data/masterdb/

使用--master选项,mongod将创建一个local.oplog.$main集合,该集合将对操作进行排队的“操作日志”排队,这些操作将从服务器将应用于从主服务器复制操作。 --dbpath是可选的。

要以从属模式启动mongod实例,请按以下方式调用mongod

mongod --slave --source <masterhostname><:<port>> --dbpath /data/slavedb/

--source参数指定主实例的主机名和端口。 --dbpath是可选的。

对于从属实例,MongoDB 将有关源服务器的数据存储在local.sources集合中。

主从部署的配置选项

作为指定--source运行时选项的替代方法,可以将文档添加到local.sources以指定主实例,如mongo shell 中的以下操作所示:

use local
db.sources.find()
db.sources.insert( { host: <masterhostname> <,only: <databasename>> } );

在第 1 行中,将上下文切换到local数据库。在第 2 行中,find()操作不应返回任何文档,以确保sources集合中没有文档。最后,第 3 行使用db.collection.insert()将源文档插入local.sources集合。 local.sources文档的模型如下:

  • host

    • 主机字段指定主mongod实例,并保存一个可解析的主机名,即 IP 地址,或host文件中的名称,或者最好是完全限定的域名。

如果mongod不在默认的27017端口上运行,则可以在主机名后附加<:port>

  • only

    • 可选的。指定数据库名称。指定后,MongoDB 将仅复制指定的数据库。

使用主从部署进行复制的操作注意事项

主实例将操作存储在oplog(即capped collection)中。结果,如果从属设备与主设备的状态相差太远,它就不能“追赶”,必须从头开始重新同步。在以下情况下,从站可能与主站不同步:

  • 从机远远落后于该主机的可用数据更新。

  • 从站停止(即关闭)并在主站覆盖了主站的相关操作后稍后重新启动。

当从站不同步时,复制将停止。Management 员必须手动干预才能重新开始复制。使用resync命令。或者,当从属服务器与主服务器不同步时,暂停十秒钟后,--autoresync允许从属服务器自动重新启动复制。在指定--autoresync的情况下,从站将仅尝试在十分钟内重新同步一次。

为避免出现这些情况,您应在启动master实例时指定较大的操作日志,方法是在启动mongod时添加--oplogSize选项。如果未指定--oplogSize,则mongod将在启动 oplog 时分配 5%的可用磁盘空间,对于 64 位计算机,最小为 1 GB,对于 32 位计算机,最小为 50 MB。

运行时主从配置

MongoDB 为master-slave部署中的mongod实例提供了许多命令行选项。有关选项,请参见主从复制命令行选项

Diagnostics

master实例上,在mongo shell 中发出以下操作以从主服务器角度返回复制状态:

rs.printReplicationInfo()

2.6 版的新功能:rs.printReplicationInfo()。对于以前的版本,请使用db.printReplicationInfo()

slave实例上,在mongo shell 中使用以下操作从从属的角度返回复制状态:

rs.printSlaveReplicationInfo()

2.6 版的新功能:rs.printSlaveReplicationInfo()。对于以前的版本,请使用db.printSlaveReplicationInfo()

使用serverStatus进行以下操作,以返回复制状态:

db.serverStatus( { repl: 1 } )

有关输出的相关部分的文档,请参见服务器状态替换字段

Security

在启用authorization的情况下运行时,在master-slave部署中配置keyFile,以便从属mongod实例可以进行身份验证并与主mongod实例进行通信。

要启用身份验证并配置keyFile,请在配置文件中添加以下选项:

keyFile = /srv/mongodb/keyfile

Note

您可以选择使用命令行上的--keyFile选项设置这些运行时配置选项。

设置keyFile启用身份验证,并为彼此进行身份验证时要使用的mongod实例指定密钥文件。密钥文件的内容是任意的,但在部署的所有成员上都必须彼此连接才能相同。

密钥文件的大小必须小于 1 KB,并且只能包含 base64 集中的字符。密钥文件在 UNIX 系统上不能具有组或“世界”权限。使用以下命令来使用 OpenSSL 程序包生成用于密钥文件中的“随机”内容:

openssl rand -base64 741

See also

Security了解有关 MongoDB 中安全性的更多信息

正在进行的主从部署 Management 和操作

使用副本集部署等效主从

如果要使用replica sets副本集进行类似于master-slave复制的复制配置,请考虑以下副本配置文档。在此部署中,主机<master><slave> [1]提供的复制大致等效于两实例主从部署:

{
  _id : 'setName',
  members : [
    { _id : 0, host : "<master>", priority : 1 },
    { _id : 1, host : "<slave>", priority : 0, votes : 0 }
  ]
}

有关副本集配置的更多信息,请参见副本集配置

[1]在副本集配置中,members[n].host字段必须包含可解析的主机名。

将主从部署转换为副本集

要将主从部署转换为副本集,请以单成员副本集的形式重新启动当前的主副本。

  • 要确认当前实例是主实例,请运行:
db.isMaster()

这应该返回类似于以下内容的文档:

{
   "ismaster" : true,
   "msg" : "isdbgrid",
   "maxBsonObjectSize" : 16777216,
   "maxMessageSizeBytes" : 48000000,
   "maxWriteBatchSize" : 100000,
   "localTime" : ISODate("2017-11-15T17:50:05.775Z"),
   "logicalSessionTimeoutMinutes" : 30,
   "maxWireVersion" : 6,
   "minWireVersion" : 0,
   "ok" : 1,
   "$clusterTime" : {
      "clusterTime" : Timestamp(1510768200, 1),
      "signature" : {
         "hash" : BinData(0,"VKMQp+F/p+nDZldmWTUzBz7A8Kc="),
         "keyId" : NumberLong("6488693018630029321")
      }
   },
   "operationTime" : Timestamp(1510768200, 1)
}
  • 连接到每个实例时,使用以下命令关闭主节点和所有从节点上的mongod进程:
db.adminCommand({shutdown : 1, force : true})
  • 备份/data/db目录,以防您需要恢复为主从部署。

  • 使用--replSet选项启动前一个主机,如下所示:

mongod --replSet <setname>
  • 使用mongoShell 连接到mongod,并使用以下命令启动副本集:
rs.initiate( { _id: "<setname>", members: [ { _id: 0, host: "<host:port>" } ] } )

命令返回时,您将成功部署一个成员副本集。您可以通过运行以下命令随时检查副本集的状态:

rs.status()

要将以前的从属服务器作为从属服务器添加到副本集中,请删除它们的数据目录并添加到副本集中。请参阅将成员添加到副本集中将新成员添加到副本集。

故障转移到奴隶(促销)

要从不可用或损坏的master(在下面的示例中为A)永久故障转移到slave(B),请执行以下操作:

  • 关闭A

  • B上停止mongod

  • 备份并从dbPath移到B上以local开头的所有数据文件。

Warning

删除local.*是不可撤销的,并且无法撤消。极其谨慎地执行此步骤。

Note

这是一次操作,并且不可逆。 A不能成为B的从属,直到它完成完全重新同步。

反转主从

如果您有master(A)和slave(B),并且想要调换它们的角色,请按照以下步骤操作。该过程假定A是健康的,最新的并且可用。

如果A状况不佳,但硬件正常(停电,服务器崩溃等),请跳过步骤 1 和 2,并在步骤 8 中用B的文件替换所有A的文件。

如果A状况不佳且硬件不正常,请用新机器替换A。还要遵循上一段中的说明。

在部署中反转主服务器和从服务器:

  • 使用fsync命令暂停在A上写。

  • 确保B是最新状态A

  • 关闭B

  • 备份并从dbPath移出B上以local开头的所有数据文件,以删除现有的local.sources数据。

Warning

删除local.*是不可撤销的,并且无法撤消。极其谨慎地执行此步骤。

  • 使用--master选项开始B

  • B上执行写操作,这会为oplog赋值,以提供新的同步起点。

  • 关闭B。现在B将具有一组以local开头的新数据文件。

  • 关闭A并将_5 开头的AdbPath中的所有文件替换为local开头的BdbPath中的文件的副本。

复制时,请考虑从B压缩local文件,因为它们可能很大。

  • 使用--master选项开始B

  • 以所有常用的从属选项开始A,但要包含fastsync

从现有主磁盘映像创建从磁盘

如果您可以无限期地停止对master的写操作,则可以将数据文件从主机复制到新的slave,然后使用--fastsync启动从机。

Warning

小心--fastsync。如果两个实例上的数据不相同,则将永远存在差异。

fastsync是通过从现有的主磁盘映像/备份启动来启动从机的方法。此选项声明 Management 员保证映像是正确的,并且完全与主映像保持最新。如果您有来自主服务器的完整数据副本,则可以使用此选项来避免在启动从服务器时进行完全同步。

从现有从站的磁盘映像创建从站

您可以复制其他slave's数据文件快照,而无需任何特殊选项。仅在以下情况下拍摄数据快照:

db.fsyncLock()确保可以使用cpscptar等低级备份 Util 安全地复制数据文件。开始使用复制的文件的mongod包含与锁定的mongod上的用户写入数据没有区别的用户写入数据。

由于诸如journaling syncsWiredTiger snapshots之类的操作,被锁定的mongod的数据文件可能会更改。尽管这对逻辑数据(例如,Client 端访问的数据)没有影响,但某些备份 Util 可能会检测到这些更改并发出警告或失败并出现错误。有关 MongoDB 建议的备份 Util 和过程的更多信息,请参见MongoDB 备份方法

重新同步太旧而无法恢复的从站

Slavesmaster异步应用写操作,从服务器从主oplog查询轮询。操作日志的长度是有限的,并且如果从站的位置太远,则需要完全重新同步。要重新同步从站,请使用mongo连接到从站并发出resync命令:

db.adminCommand( { resync: 1 } )

这将强制所有数据完全重新同步(在大型数据库上这将非常慢)。通过在从站上停止mongod,删除从站上dbPath的全部内容,然后重新启动mongod,可以达到相同的效果。

Slave Chaining

Slaves不能被“链接”。他们必须都直接连接到master

如果一个从属尝试从另一个从属“从属”,则您将在 Shell 的mongod long 中看到以下行:

assertion 13051 tailable cursor requested on non capped collection ns:local.oplog.$main

纠正从属源

要更改slave's源,请手动修改从属的local.sources集合。

Example

请考虑以下事项:如果不小心为从属服务器的source设置了错误的主机名,如以下示例所示:

mongod --slave --source prod.mississippi

您可以通过重新启动没有--slave--source参数的从属设备来更正此问题:

mongod

使用mongo shell 连接到该mongod实例,并按照以下操作 Sequences 更新local.sources集合:

use local

db.sources.update( { host : "prod.mississippi" },
{ $set : { host : "prod.mississippi.example.net" } } )

使用正确的命令行参数或不使用--source选项重新启动从站。首次配置local.sources之后,--source将没有任何后续作用。因此,以下两个调用都是正确的:

mongod --slave --source prod.mississippi.example.net

or

mongod --slave

现在,从站轮询来自正确master的数据。