自动压缩mongodb中删除的空间?

时间:2010-12-29 16:42:46

标签: mongodb diskspace repair

mongodb文件说

  

要压缩此空间,请从mongo shell运行db.repairDatabase()(注意此操作将阻塞并且速度很慢)。

http://www.mongodb.org/display/DOCS/Excessive+Disk+Space

中的

我想知道如何让mongodb免费删除磁盘空间自动

P.S。我们在mongodb中存储了许多下载任务,最高可达20GB,并在半小时内完成。

4 个答案:

答案 0 :(得分:65)

通常,如果您不需要缩小数据文件,则根本不应缩小它们。这是因为在磁盘上“增长”你的数据文件是一项相当昂贵的操作,MongoDB可以在数据文件中分配的空间越多,你所拥有的碎片就越少。

因此,您应该尝试为数据库提供尽可能多的磁盘空间。

然而如果你必须缩小数据库,你应该记住两件事。

  1. MongoDB通过增加数据文件     加倍,所以数据文件可能是     64MB,然后是128MB等,高达2GB(at     它指向它停止加倍     将文件保留到2GB。)

  2. 与大多数数据库一样......     做缩小你的行动     需要安排一个单独的工作     这样做,没有“自动收缩”     MongoDB的。实际上是主要的noSQL数据库     (讨厌那个名字)只有Riak     会自动收缩。所以,你需要     使用您的操作系统创建一份工作     调度程序运行收缩。您可以使用bash脚本,或者让作业运行php脚本等。

  3. Serverside Javascript

    您可以使用服务器端Javascript进行收缩并通过mongo的shell通过作业(如cron或Windows调度服务)定期运行该JS ...

    假设有一个名为 foo 的集合,您可以将下面的javascript保存到名为 bar.js 的文件中并运行...

    $ mongo foo bar.js
    

    javascript文件看起来像......

    // Get a the current collection size.
    var storage = db.foo.storageSize();
    var total = db.foo.totalSize();
    
    print('Storage Size: ' + tojson(storage));
    
    print('TotalSize: ' + tojson(total));
    
    print('-----------------------');
    print('Running db.repairDatabase()');
    print('-----------------------');
    
    // Run repair
    db.repairDatabase()
    
    // Get new collection sizes.
    var storage_a = db.foo.storageSize();
    var total_a = db.foo.totalSize();
    
    print('Storage Size: ' + tojson(storage_a));
    print('TotalSize: ' + tojson(total_a));
    

    这将运行并返回类似......

    的内容
    MongoDB shell version: 1.6.4
    connecting to: foo
    Storage Size: 51351
    TotalSize: 79152
    -----------------------
    Running db.repairDatabase()
    -----------------------
    Storage Size: 40960
    TotalSize: 65153
    

    按计划运行(在非高峰时段),你很高兴。

    上限收藏

    但是还有另外一个选项,capped collections

      

    加盖的集合是固定大小的   收藏率非常高   性能自动FIFO超时功能   (年龄取决于插入顺序)。   它们有点像“RRD”概念   如果你熟悉那个。

         

    此外,上限收藏   自动,高性能,   保持插入顺序   集合中的对象;这是   对某些用例非常强大   例如伐木。

    基本上你可以将集合的大小(或文档数量)限制为20GB,一旦达到该限制,MongoDB将开始丢弃最旧的记录,并在它们进入时用更新的条目替换它们。

    这是保存大量数据的好方法,随着时间的推移丢弃旧数据并保持相同的磁盘空间使用量。

答案 1 :(得分:26)

我有另一个解决方案可能比执行db.repairDatabase()更好,如果你不能锁定系统,或者没有两倍的存储空间。

您必须使用副本集。

我的想法是,一旦您删除了所有耗尽磁盘的数据,停止辅助副本,擦除其数据目录,启动它并让它与主服务器重新同步。

这个过程非常耗时,但是当你执行rs.stepDown()时,它只需要花费几秒的停机时间。

这也不能自动化。好吧,它可以,但我不认为我愿意尝试。

答案 2 :(得分:8)

运行db.repairDatabase()将要求您的空间等于文件系统上可用数据库的当前大小。当您知道剩下的集合或您需要在数据库中保留的数据当前使用的空间比分配的空间少得多并且您没有足够的空间来进行修复时,这可能很麻烦。

作为替代方案,如果您实际需要保留的集合很少或只需要数据的子集,那么您可以将需要保留的数据移动到新数据库中并删除旧数据库。如果需要相同的数据库名称,则可以使用相同的名称将它们移回新的数据库。只需确保重新创建任何索引。

use cleanup_database
db.dropDatabase();

use oversize_database

db.collection.find({},{}).forEach(function(doc){
    db = db.getSiblingDB("cleanup_database");
    db.collection_subset.insert(doc);
});

use oversize_database
db.dropDatabase();

use cleanup_database

db.collection_subset.find({},{}).forEach(function(doc){
    db = db.getSiblingDB("oversize_database");
    db.collection.insert(doc);
});

use oversize_database

<add indexes>
db.collection.ensureIndex({field:1});

use cleanup_database
db.dropDatabase();

具有许多集合的数据库的导出/删除/导入操作可能会获得相同的结果,但我还没有测试过。

此外,作为一项策略,您可以将永久集合保存在与瞬态/处理数据不同的数据库中,并在作业完成后删除处理数据库。由于MongoDB是无模式的,因此除了索引之外的任何内容都不会丢失,并且当下一个进程的插入运行时,将重新创建数据库和集合。只需确保您的作业包括在适当的时间创建任何nessecary索引。

答案 3 :(得分:4)

如果您使用的是最初编写此问题时无法使用的replica sets,那么您可以设置一个流程来自动回收空间而不会导致严重的中断或性能问题。

为此,您可以利用副本集中辅助节点的自动初始同步功能。要解释:如果关闭辅助节点,擦除其数据文件并重新启动它,则辅助节点将从头开始重新同步集中的其他节点之一(默认情况下,它通过查看ping响应来选择与其最接近的节点)次)。发生此重新同步时,所有数据都从头开始重写(包括索引),实际上与修复和回收的磁盘空间做同样的事情。

通过在辅助节点上运行它(然后逐步降低主节点并重复该过程),您可以有效地回收整个集合上的磁盘空间,同时将中断降至最低。如果你正在阅读辅助语言,你需要小心,因为这将在很长一段时间内不再轮换。您还需要确保oplog窗口足以成功进行重新同步,但这通常是您要确定是否执行此操作的原因。

要自动执行此过程,您只需要运行一个脚本,以便在您的集合中的每个成员的不同日期(或类似日期)执行此操作,最好是在您的安静时间或维护时段。这个脚本的一个非常天真的版本在bash

中看起来像这样

注意:这是基本的伪代码 - 仅用于说明目的 - 不用于生产系统而不会发生重大变化

#!/bin/bash 

# First arg is host MongoDB is running on, second arg is the MongoDB port

MONGO=/path/to/mongo
MONGOHOST=$1
MONGOPORT=$2
DBPATH = /path/to/dbpath

# make sure the node we are connecting to is not the primary
while (`$MONGO --quiet --host $MONGOHOST --port $MONGOPORT --eval 'db.isMaster().ismaster'`)
do
    `$MONGO --quiet --host $MONGOHOST --port $MONGOPORT --eval 'rs.stepDown()'`
    sleep 2
done    
echo "Node is no longer primary!\n"

# Now shut down that server 
# something like (assuming user is set up for key based auth and has password-less sudo access a la ec2-user in EC2)
ssh -t user@$MONGOHOST sudo service mongodb stop

# Wipe the data files for that server

ssh -t user@$MONGOHOST sudo rm -rf $DBPATH
ssh -t user@$MONGOHOST sudo mkdir $DBPATH
ssh -t user@$MONGOHOST sudo chown mongodb:mongodb $DBPATH

# Start up server again
# similar to shutdown something like 
ssh -t user@$MONGOHOST sudo service mongodb start