Mongo服务器管理之备份

1.对服务器进行备份

  备份有许多种方法。但无论采用哪种方法,备份操作都会增加系统的负担:备份通常需将所有数据读取到内存中。因此,通常情况下,应对副本集的非主节点(与主节点相对)进行备份,或在空闲时段对独立服务器进行备份。

  如非特殊声明,本节中的所有技术均适用于任何mongod程序,无论是独立服务器还是副本集成员。

 

1.1 文件系统快照

  生成文件系统快照(snapshot)是最简单的备份方法。然而,该方法的实现需要两点条件,即文件系统本身支持快照技术,以及在运行mongod时必须开启日记系统 (journaling)。如系统满足这两点条件,则该方法无需其他准备,只需生成快照即可,时间不限。

  在恢复时,确保mongod没有在运行。从快照恢复数据的确切命令取决于不同的文件系统,不过基本上就是恢复快照,然后启动mongod即可。如果是对正在运行的系统生成快照,那么快照中的数据内容本质上相当于使用kill -9命令强制终止mongod后的数据内容。因此,mongod在启动时会对日志(journal)文件进行重放(replay),然后开始正常运行。

 

1.2 复制数据文件

  另一种备份方式是复制数据目录中的所有文件。没有文件系统的支持,我们就无法同时复制所有文件,因此在进行备份时必须防止数据文件发生改变。可使用fsynclock命令做到这一点:

> db.fsyncLock()

  该命令锁定(lock)数据库,禁止任何写入,并进行同步(fsync),即将所有脏页刷新至磁盘,以确保数据目录中的文件是最新的,且不会被更改。

  一旦运行了这一命令,mongod会将之后的所有写入操作加入队列等待,且在解锁前不会对这些写入操作进行处理。注意,这一命令会停止所有数据库的写入操作,而不只是已连接的那个数据库。

  当fsynclock命令返回命令行后,复制数据目录中的所有文件到备份位置。在Linux中,可使用以下命令等:

$ cp -R /data/db/* /mnt/external-drive/backup

  确保复制了数据目录中的每一个文件和文件夹到备份位置。漏掉文件或文件夹可能会损坏备份或使其不再可用。

  数据复制完成后,解锁数据库,使其能够再次进行写入操作:

> db.fsyncUnlock()

  数据库即开始正常处理写入操作。

  注意:身份验证和fsynclock命令存在一些锁定问题。如果启用了身份验证,则在调用fsyncLock()和fsyncUnlock()期间不要关闭shell。如果在这期间断开了连接,则可能无法进行重新连接,并不得不重启mongod。fsyncLock()的设定在重启后不会保持生效,mongod总是以非锁定模式启动。

  除使用fsynclock外,还可关闭mongod,复制文件,然后重启mongod。关闭mongod会将所有更改立即刷新到磁盘,防止备份期间出现新的写入操作。

  若要恢复数据目录备份,请保证mongod没有在运行,且所有待恢复的数据目录为空。将备份的数据文件复制到数据目录,然后启动mongod。例如,下列命令会使用前面提及的命令恢复备份文件:

$ cp -R /mnt/external-drive/backup/* /data/db/
$ mongod -f mongod.conf

  忽略那些有关复制部分数据目录的警告信息。只要知道要复制哪些文件,即可使用这种方式备份单独的数据库。例如,要备份名为myDB的数据库,只需复制所有名为myDB.*的文件,包括后缀名为.ns的文件。如使用了--directoryperdb选项,只需复制该数据库对应的整个数据目录。

  可复制数据库对应的文件到数据目录,完成指定数据库的恢复。如需进行这种部分恢复,应确保数据库上一次是正常关闭的。如遇到崩溃或突然停机,不要尝试恢复一个单独的数据库,而应用备份文件替换整个数据目录,然后启动mongod,从而允许日记文件进行重放。

  提示:不要同时使用fsyncLock和mongodump。数据库被锁定也许会使得mongodump永远处于挂起状态,这取决于数据库正在进行的其他操作。

 

1.3 使用mongodump

  最后一种备份方式是使用mongodump。之所以最后提到它,是因为mongodump有些许缺点。它备份和恢复的速度较慢,在处理副本集时存在一些问题。然而它也存在以下优点:当想备份单独的数据库、集合甚至集合中的子集时mongodump是个很好的选择。

  运行mongodump --help,可看到mongodump具有很多选项。此处我们重点关注那些与备份相关的实用选项。

  要备份所有数据库,只需运行mongodump即可。如果在同一台机器上运行mongod和mongodump,只需指定mongod运行时占用的端口即可:

$ mongodump -p 31000

  mongodump会在当前目录建立一个转储(dump)目录,其中包含了一份所有数据的倾卸。转储目录中的目录和子目录由数据库和集合构成。真正的数据存放在扩展名为.bson的文件里,其中以BSON格式依次存储了集合中的所有文档。可使用MongoDB自带的bsondump工具查看.bson文件。 

  使用mongodump时甚至无需服务器处于运行状态:可使用--dbpath选项来指定数据目录,mongodump会使用指定的数据文件进行备份。

$ mongodump --dbpath /data/db

  如果mongod正在运行,则不应使用--dbpath选项。

  mongodump存在一个问题,即它并非进行快照备份,也就是说在备份的过程中,系统可能会继续进行写入操作。于是可能出现,开始备份时mongodump先对数据库A进行转储,随后在mongodump正在对数据库B进行转储的同时,删除了数据库A。然而mongodump已经对数据库A进行了转储,于是最终转储得到的结果,是一个在原服务器上并不存在的数据快照。

  为避免这种情况的发生,如果运行mongod时使用了--replSet选项,则可使用mongodump的--oplog选项。这会将转储过程中服务器进行的所有操作记录下来,这样在恢复备份时就会重新执行这些操作。这样就可以得到源服务器上某一时间点的数据快照。

  如果给mongodump—个副本集的连接字串(例如,setName/seed1,seed2,seed3),如果备份节点存在的话,它会自动选择一个备份节点进行转储。

  恢复mongodump产生的备份,可使用mongorestore工具:

$ mongorestore -p 31000 --oplogReplay dump/

  如果转储数据库时使用了--oplog参数,运行mongorestore时必须使用--oplogReplay选项,以得到某一时间点的快照。

  如果在运行的服务器上进行数据替换,可使用--drop选项,以在恢复一个集合前先删除它。当然此选项并非必选项。

  随着版本的变化,mongodump和mongorestore命令的具体作用和用法发生了改变。为避免兼容性问题,应尽量使用同版本的mongodump和mongorestore。可运行mongodump --version 和 mongorestore --version来查看各自的版本。 

 

  1.使用mongodump和mongorestore来转移集合和数据库

  可从转储中恢复完全不同的数据库和集合。当在不同环境中使用不同的数据库名称 (例如,dev和prod),但集合的名称相同时,这一特性会很实用。

  将一个扩展名为.bson的文件恢复为特定的数据库和集合,只需在命令行中指定恢 复目标:

$ mongorestore --db newDb --collection someOtherColl dump/oldDB/oldColl.bson

 

  2.管理唯一索引带来的混乱

  在任何集合中,如果存在除_id以外的其他唯一索引(unique index),则应考虑使用mongodump和mongorestore以外的备份方式。具体地说,唯一索引要求复制期间数据不发生可能破坏其唯一索引约束的改变。最安全的方法是先想办法“冻结” 数据,然后使用前两节中提到的方法来进行备份。

  如果决定使用mongodump和mongorestore进行备份,那么在恢复备份时,可能需要对数据进行一定的预处理。

 

2.对副本集进行备份

  通常,应该对备份节点进行备份:这会为主节点减轻负担,也可以在不影响应用的情况下锁定备份节点(只要应用不向备份节点发送读取请求)。可使用之前提到过的三种方式中的任意一种,对副本集中的成员进行备份,但推荐使用文件系统快照或复制数据文件的方式。这两种方式在应用于副本集备份节点时无需做任何修改。

  副本集启用后,使用mongodump进行备份就不那么简单了。首先,如果使用mongodump,则必须在备份时使用--oplog选项,来得到一个基于某时间点的快照;否则备份的状态不会和任何其他集群成员的状态相吻合。在恢复时也必须创建一份oplog,否则被恢复的成员就不知道应该同步到哪里。

  要从mongodump生成的备份中,对副本集成员进行恢复,可将该成员作为一个单独的服务器启动,此时要使用一个空的数据目录。首先,像上一节中提到过的那样,使用--oplogReplay选项运行mongorestore。现在它应该包含了一份完整的数据副本,但还需要一份oplog。运行createColAection命令来建立oplog:

>  use local
>  db.createCollection("oplog.rs", {"capped" : true, "size" : 10000000})

  以字节为单位指定集合大小。

  现在需要填充oplog。最简单的方式是用备份中的oplog.bson文件来填充local.oplog.rs集合:

$ mongorestore -d local -c oplog.rs dump/oplog.bson

  注意:这并不是对于oplog的转储文件(dump/local/oplog.rs.bson),而是进行转储期 间发生的操作。一旦mongorestore完成,即可将服务器作为副本集成员重新启动。

 

3.对分片集群进行备份

  不可能对正在运行的分片集群进行“完美地”备份,因为无法及时得到集群在某一时间点完整状态的快照。然而,通常情况下都会避开该限制,因为随着集群的增大,从备份中恢复整个集群的可能性越来越小。因此,在面对分片集群时,我们更关注分块的备份,即单独备份配置服务器和副本集。

  在对分片集群进行备份和恢复操作之前,应先关闭均衡器。这是因为在过于混乱的环境中是无法得到一份前后一致的快照的。

 

3.1 备份和恢复整个集群

  当集群很小或正在进行开发时,我们可能想要转储和恢复整个集群。要达到这一目的,应先关闭均衡器,然后通过mongos运行mongodump。这会在mongodump所运行的机器上建立所有分片的备份。

  要恢复此种备份,需运行mongorestore并连接到一个mongos。

  关闭均衡器后,可使用文件系统快照或复制数据目录的方式,备份配置服务器和毎一个分片。然而不可避免的是,我们不可能在完全相同的时刻得到这些备份,这可能造成问题。另外,在打开均衡器时会进行数据合并,在分片中备份的某些数据可能会由此消失。

 

3.2 备份和恢复单独的分片

  更多时候,只需恢复集群中的某个单独分片。如果不是很挑剔的话,可使用刚刚在前面提到过的单独服务器处理方法进行分片的备份恢复。

  有一个问题要着重注意:假设在星期一对集群进行了备份。到了星期四,磁盘发生损坏,我们不得不恢复备份。然而,在这几天里,新的数据块可能移动到了这一分片上。而周一进行的分片备份中并不包含这些新增的数据块。也许我们能够使用配置服务器的备份,找到这些消失了的数据块在星期一时的位置,但这比只是恢复分片要困难得多。在大多数情况下,恢复分片,忽略那些消失的数据块,是更好的选择。

  可直接连接到一个分片上来恢复备份,而不需要通过mongos。

 

4.使用mongooplog进行增量备份

  以上提及的备份方式,即使和上一次备份时相比,只发生了很小的更改,也都必须对所有数据进行一次完整的复制。如果数据和写入量有很大的关系,那么我们可能希望了解一下增量备份。

  与每天或每周进行一次完整的数据复制不同,我们只需进行一次备份,然后使用oplog来备份这之后的所有操作。这种技术比之前提及的技术都要复杂,因此除非确实需要,否则应尽量选择其他技术。

  这一技术需要两台运行mongod的机器,即机器A和机器B。A是主机器(可能是副本集中的备份节点),B则用来进行备份:

    (1) 记录下A的oplog中最近一次的操作时间(optime):

>  op = db.oplog.rs.find().sort({$natural: -1}).limit(1).next();
>  start = op['ts']['t']/1000

      把该数值记录在安全的地方--等下会用到它。

    (2) 对数据进行备份,使用以上提及的任何一种方式,得到一份基于某时间点的备份。恢复备份至B上的数据目录。

    (3) 定期添加A上的操作至B,从而完成数据的复制。MongoDB的发行版中自带了一个特殊的工具mongooplog(读作mon-goop-log),将这一操作变得简单。mongooplog从一台服务器的oplog中复制数据,并将其中的操作应用在另一台服务器的数据集上。在B上运行:

$ mongooplog --from A --seconds 1234567

    其中--seconds选项后跟的参数,应为第一步中计算出的start变量和当前时间的差值,再额外加上几秒(重复地重放操作也好过数据丢失)。

  这使得备份更接近最新的数据。这种技术有些像是手动地同步一个备份节点,所以我们也许只是想在备份节点上使用延时复制以代替增量备份。

上一篇:JSP,PHP详细性能测试


下一篇:【Mongodb】数据库备份与还原