compact命令
v1.9+
压缩命令会对一个集合进行压缩和除碎片。索引也会被重建和压缩。这会为数据库中其他集合释放空间。在概念上它和repairDatabase类似,但是它仅仅作用于一个集合而不是整个数据库。
运行(mongo shell上面的示例):
> db.runCommand( { compact : 'mycollectionname' } )
OR
> db.mycollection.runCommand( "compact" )
这个命令直到压缩全部完成才会返回。你可以通过查看mongod记录文件或者在另一个shell实例中运行db.currentOp()来查看中间进展。
由于它会阻塞所有的活动,因此该命令默认情况下不会在复制组的主节点运行。否则它会返回错误。想要强制在复制组主节点上运行,使用将force:true作为参数的压缩命令。
运行一个压缩
与repairDatabase不同,压缩命令不需要两倍的硬盘空间来完成工作。它在工作的时候只需要少量额外的空间。另外,压缩要更快一些。
尽管比repairDatabase要快一些,该命令在运行期间会阻塞所有其他操作,并且慢吞吞的。可以在安排的维护期间运行它。
如果你在复制组的辅助节点运行这个命令,辅助节点会自动把自己降级为"recovery"状态,直到压缩完成。
取消一个压缩
在压缩的开始,集合的索引会被删除。压缩结束时,索引会重建。因此如果在压缩操作的中间你把它取消了,使用killOp或者服务器失效,你的集合的索引可能会丢失。如果你使用了参数--journal运行,在压缩过程中的宕机应该不会有数据丢失,虽然在启动时索引可能不存在了。(尽管如此,永远在系统维护之前像这样做一次备份)当索引重建后,它们将会是2.0版本的索引格式。
如果在这个命令执行期间发生了宕机,只要日志功能启用了,你的数据将会是安全的。不过,一块不可恢复盘区还是留下来了。唯一可以移除这块盘区的办法就是在整个数据库上面执行修复操作。但是除非使用了额外空间,否则这孤立的盘区不会表现出任何问题。
另外,如果压缩操作被中断了,那么这个集合中大部分空闲空间可能变得不可用。在这种情况下推荐再执行一次压缩,完成压缩,恢复空闲空间。
压缩的效果
你可能会在压缩之前和之后运行collstats命令(在shell中是db.collectionname.stats())来查看集合的存储空间都怎么变化了。
这个命令对集合中没有填充因素(Padding Factor)的文档做了充分压缩。如果你常常执行会使文档增大的更新操作,这会降低更新的性能因为文档需要经常移动。
压缩可能会将你的数据文件的总大小增长到2GB。即使在这种情况下,集合使用的总的存储空间还是会下降。
详细信息
- 压缩可能在复制组辅助节点和从节点上面执行。压缩命令不会复制,因此每一台主机需要单独的进行压缩。
- 当前,压缩是发布给mongod的命令。在一个分片环境,应该作为一个维护操作对每一个分片单独的执行压缩。(在将来的版本中可能会改变,和其他增强功能一起)
- 固定大小的集合是不能被压缩的。(然而,固定大小集合中的文档是不受碎片管理的。)
复制组
- 单独的对每一个成员压缩。
- 理想的压缩是运行在一个辅助节点(看上面关于force:true的评论)。
- 如果压缩运行在辅助节点上,辅助节点会自动进入"recovering"状态(阻止在压缩过程中被路由来的读操作)。一旦压缩结束,它会自动返回到辅助状态。
拷贝数据库命令
mongodb包含有将一个数据库从一台服务器拷贝到另外一台服务器的命令。
这些选项比可选的方法执行mongodump和mongorestore要快,因为它跳过了在磁盘上创建临时BSON描述的步骤。
copydb命令
将一台服务器上面一个名字的整个数据库拷贝到另外一台服务器并使用另外一个名字。在相同的服务器拷贝一个数据库到另外名称的数据库可以省略掉<from_hostname>.拷贝命令必须发送并在目标服务器执行。
> // shell helper syntax:
> db.copyDatabase(<from_dbname>, <to_dbname>, <from_hostname>);
> // if you must authenticate with the source database
> db.copyDatabase(<from_dbname>, <to_dbname>, <from_hostname>, <username>, <password>);
> // pure command syntax (runnable from any driver):
> db.runCommand(
... {copydb: 1, fromhost: <hostname>, fromdb: <db>,
... todb: <db>[, slaveOk: <bool>, username: <username>,
... nonce: <nonce>, key: <key>]}";
> // command syntax for authenticating with the source:
> n = db.runCommand( { copydbgetnonce : 1, fromhost: ... } );
db.runCommand( { copydb : 1, fromhost: ..., fromdb: ..., todb: ..., username: ..., nonce: n.nonce,
key: <hash of username, nonce, password > } );
cloneDatabase
和copydb相似,但是使用了简单化的语法。适用于我们只不过拷贝一个数据库到这台服务器,并使用原来的名称。
> db.cloneDatabase(<from_hostname>);
注释:
- copyDatabase 可以对从节点/辅助节点运行(换句话说,源服务器可以是一个从节点/辅助节点)。
- copyDatabase没有任何意义上的快照:如果在拷贝期间源数据库正在变化,目标数据库会接收到不同时间点的文档。
- 这个命令必须运行在目标服务器。
- 这个命令在执行期间不会锁定源服务器和目标服务器。每一段都会周期性的允许其他的读/写操作通过。
fsync命令
fsync命令允许我们将所有挂起写操作刷新到数据文件。更重要的,它还提供了锁选项让备份更加容易。
fsync命令强制让数据库刷新所有的数据文件:
> use admin
> db.runCommand({fsync:1});
默认情况下这个命令在同步完成后返回。需要立即返回,请使用:
> db.runCommand({fsync:1,async:true});
要定期同步,在命令行选项中使用--syncdelay命令(查看mongod --help输出)。默认每60s做一次强制完全刷新。
锁,快照和解锁
同步命令支持锁选项,这样就可以安全的对数据库的数据文件进行快照。当被锁住后,所有的写操作会阻塞,虽然读操作依旧允许。快照完成后,使用解锁命令对数据库解锁并允许再次上锁。例如:
> use admin
switched to db admin
> db.runCommand({fsync:1,lock:1})
{
"info" : "now locked against writes",
"ok" : 1
}
> db.currentOp()
{
"inprog" : [
],
"fsyncLock" : 1
}
>// do some work here: for example, snapshot datafiles...
>// runProgram("/path/to/my-filesystem-snapshotting-script.sh")
> db.$cmd.sys.unlock.findOne();
{ "ok" : 1, "info" : "unlock requested" }
> // unlock is now requested. it may take a moment to take effect.
> db.currentOp()
{ "inprog" : [ ] }
附加说明
当数据库因为快照而被锁住时是可读的,如果尝试进行写,这会阻塞读的人因为数据库使用了一个读/写锁。这将来会被处理掉。
对从节点快照
上面的流程都是针对复制组从节点的。从节点在被锁期间不会执行任何操作。无论如何,请看附件说明部分。
分片
同步命令只能发给一个单独的节点,而不是整个分片集群。
1.9的改变
mongodb1.9中引入了两个新的shell辅助函数:db.fsyncLock()和db.fsyncUnlock().它们是出于方便的原因提供的,它们包装了上面关于这个接口描述的功能。接下来你可以看一下它们的实现:
> db.fsyncLock
function () {
return db.adminCommand({fsync:1, lock:true});
}
> db.fsyncUnlock
function () {
return db.getSiblingDB("admin").$cmd.sys.unlock.findOne();
}
现在解锁调用会阻塞
值得注意的是,解锁命令做了小小的改动。在1.9.0以前,这个命令会请求解锁并立即返回。这样就很难知道数据库实际上是否已经解锁。
现在的这个命令会阻塞知道数据库被解锁。当它返回时,你就可以确定数据库已经将数据文件同步到磁盘并准备好接收写入了。