本节我会介绍三个最常用的MongoDB维护任务,首先要讨论的是备份。和其他数据库一样,你也该有个日常备份策略。随后,我会介绍压紧(compaction),因为在少数几种情况下,数据文件需要压紧。最后再简要地说一下升级,在条件允许时,你会希望运行最新的稳定版MongoDB。
10.3.1 备份与恢复
在运行生产环境数据库时,有一部分工作内容就是准备应对灾难,备份在其中扮演了重要的角色。当灾难不期而至时,好的备份能力挽狂澜,这时你绝不会为日常备份所投入的时间和精力而感到后悔。但还是有些用户决定不做备份,当他们遇到问题无法恢复自己的数据库时,只能说是自作自受,你可千万别向他们学习。
MongoDB数据库有两个常规的备份策略,第一个是使用mongodump
和mongorestore
工具;第二,而且很可能是更常用的,是复制原始的数据文件。
1. mongodump
与mongorestore
mongodump
能把数据库的内容导出成BSON文件,而mongorestore
则能读取并还原这些文件。这些工具在备份单个集合、数据库乃至整个服务器时都非常有用。它们能运行于线上服务器(无需锁定或关闭服务器),你也可以在服务器被锁定或关闭时将它们指向一组数据文件。最简单的mongodump
运行方法如下:
$ mongodump -h localhost --port 27017
这能把localhost
服务器上的每个数据库和集合都导出到名为dump
的目录里。导出的内容包含每个集合里的所有文档,还包含定义了用户和索引的系统集合。但值得注意的是索引本身并不包含其中,也就是说,在恢复时必须重建全部索引。如果你的数据集特别大,或是拥有大量索引,那么这会花费不少时间。
在还原BSON文件时,运行mongorestore
,将它指向dump
文件夹:
$ mongorestore -h localhost --port 27017 dump
请注意,在还原过程中mongorestore
默认不会删除数据。因此,如果你向一个现有数据库还原数据,请务必带上--drop
标志。
2. 基于数据文件的备份
大多数用户选择基于文件的备份,将原始数据文件复制到一个新的位置。这种方法在大多数情况下比mongodump
要快,因为在备份和还原时无需转换数据。3唯一潜在的问题是基于文件的备份要求锁定数据库,但是通常你都会锁定从节点,因此在备份的过程中应用程序应该能够保持在线。
3. 举个例子,采用这种策略会保留全部的索引——无需在还原时重建索引。
复制数据文件
用户经常会犯错误,没有先锁定数据库就去复制数据文件或制作快照。在禁用Journaling日志时,这会造成数据文件损坏。在开启Journaling日志时,制作快照没问题,但复制数据文件有点麻烦,容易发生状况。
因此,无论是否开启了Journaling日志,本书建议总是在复制数据文件或制作磁盘快照前锁定数据库。比起锁定数据库所带来的安宁和对文件完整性的保障,由此引发的轻微延时是值得的。
复制数据文件,先要确认它们都处于一致状态,为此可以关闭数据库或是锁定它。由于关闭数据库在一些部署情况下太麻烦了,所以大多数用户都选择进行锁定。以下是用来同步并锁定数据库的命令:
> use admin> db.runCommand({fsync: 1, lock: true})
此时,数据库是写锁定的,数据文件都同步到了磁盘上,也就是说可以安全地复制数据文件了。如果正运行在一个支持快照的文件系统或存储系统上,最好先制作一个快照,以后再做复制,这能让你快点解锁。
如果无法制作快照,就必须在复制数据文件时让数据库保持在锁定状态。如果是从一个从节点复制数据文件,请确保该节点仍连着主节点,并有足够的oplog让它在备份期间保持离线状态。
一旦完成快照或者备份,就可以解锁数据库了。看似神秘的解锁命令是这样的:
> db.$cmd.sys.unlock.findOne> { /"ok/" : 1, /"info/" : /"unlock requested/" }
请注意,这仅仅是请求解锁,数据库可能不会立刻解锁,可以运行db.currentOp
方法验证数据库是否已经解锁。
10.3.2 压紧与修复
MongoDB包含了修复数据库的功能,可以通过命令行触发修复服务器上的所有数据库:
$ mongod --repair
也可以运行repairDatabase
命令修复单个数据库:
> use cloud-docs> db.runCommand({repairDatabase: 1})
修复是个离线操作,在执行时,数据库的读写都将被锁定。修复就是读取和重写所有数据文件并重建各个索引,在此过程中丢弃掉损坏的文档。也就是说要修复数据库,需要有足够的空余磁盘空间来存储重写的数据。要说修复的开销很大,那还是轻的,修复大型数据库能花好几天。
MongoDB的修复最初是用作恢复受损数据库的最后一道防线。在未正常关闭,又没有开启Journaling日志时,修复是让数据文件回到一致状态的唯一途径。幸运的是,如果部署时使用了复制,至少有一台机器开启了Journaling日志,并且进行日常线下备份,你应该永远也用不上执行修复的恢复功能。依靠修复来进行恢复是种愚蠢的做法,应尽量避免这么做。
那么数据库修复又有什么好处呢?运行修复能压紧数据文件并重建索引。自v2.0版本起,MongoDB对数据文件压紧并没有太好的支持,因此如果执行了很多随机删除,尤其是删除小文档(小于4 KB),那么总存储大小可能仍然保持不变甚至是继续增长。压紧数据文件能有效应对此类对空间的过度使用。
要是没有时间或资源执行完整的修复,还有两个选择,它们都是针对单个集合进行操作的:可以重建索引或是压紧集合。要重建索引,可以使用reIndex
方法:
> use cloud-docs> db.spreadsheets.reIndex
这招很管用,但一般而言,索引空间是能高效重用的;数据文件空间才是问题。所以compact
命令通常是更好的选择。compact
会重写数据文件,并重建集合的全部索引。下面展示如何在Shell中运行compact
命令:
> db.runCommand({ compact: /"spreadsheets/" })
该命令的初衷是在运行中的从节点上压紧,以此避免停机时间。一旦完成副本集中所有从节点的压紧,可以降级主节点,再对它进行压紧。如果必须在主节点上运行compact
命令,可以向命令键中添加{force: true}
。请注意,如果选择这种方式,该命令会对系统进行写锁定:
> db.runCommand({ compact: /"spreadsheets/", force: true })
10.3.3 升级
MongoDB还是一个相对比较“年轻”的项目,这意味着它的新版本中一般都包含很多重要的补丁和性能改进。出于这些原因,你应该尽可能运行最新的稳定版本。至少到v2.0为止,升级的过程就是简单地关闭老的mongod
进程,用老的数据文件启动新的mongod
进程。MongoDB的后续版本可能会对索引和数据文件格式做些小的改变,这可能会让升级过程稍微烦琐一点。请查看最新的发布说明以了解正确的推荐做法。
当然,在升级MongoDB时,可能会要升级副本集集群,这种情况下,常规的策略是一次升级一个节点,先从从节点开始。