Авто сжимать удаленное пространство в mongodb? - PullRequest
39 голосов
/ 29 декабря 2010

В документе mongodb говорится, что

Чтобы сжать это пространство, запустите db.repairDatabase () из оболочки Монго (обратите внимание, что эта операция блокируется и выполняется медленно).

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

Интересно, как сделать mongodb свободным удаленным дисковым пространством автоматически ?

p.s. Мы сохранили много задач загрузки в mongodb, до 20 ГБ, и завершили их за полчаса.

Ответы [ 4 ]

65 голосов
/ 30 декабря 2010

В общем, если вам не нужно сжимать ваши файлы данных, вы не должны сжимать их вообще.Это связано с тем, что «наращивание» ваших файлов данных на диске является довольно дорогой операцией, и чем больше MongoDB выделяет в файлах данных, тем меньше у вас фрагментации.

Итак, вам следует попытаться выделить как можно больше дискового пространства.насколько это возможно для базы данных.

Однако если вам необходимо уменьшить базу данных, вы должны иметь в виду две вещи.

  1. MongoDB увеличивает свои файлы данныхудваивая таким образом, файлы данных могут иметь размер 64 МБ, затем 128 МБ и т. д. до 2 ГБ (после чего он перестает удваиваться, чтобы сохранить файлы до 2 ГБ.)

  2. Как и в большинстве других баз данных ...для выполнения таких операций, как сжатие, вам нужно запланировать отдельную работу, в MongoDB нет «автоусадки».На самом деле из основных баз данных noSQL (ненавижу это имя) только Riak будет автоматически сжиматься.Итак, вам нужно будет создать задание, используя планировщик вашей ОС для запуска сжатия.Вы можете использовать bash-скрипт, или запустить работу php-скрипта и т. Д.

Javascript на стороне сервера

Вы можете использовать Javascript на стороне серверачтобы сжимать и запускать этот JS через оболочку Монго на регулярной основе через задание (например, cron или службу планирования Windows) ...

Предполагая, что коллекция называется 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));

Thisбудет запускаться и возвращать что-то вроде ...

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

Запустите это по расписанию (в часы без пиковых нагрузок), и все готово.

Ограниченные коллекции

Однако есть еще один вариант, ограниченные коллекции .

Закрытые коллекции - это коллекции фиксированного размера, обладающие очень высокой производительной функцией автоматического истечения срока действия FIFO (срок действия зависит от порядка вставки).Они немного похожи на концепцию «RRD», если вы с ней знакомы.

Кроме того, закрытые коллекции автоматически, с высокой производительностью, поддерживают порядок вставки объектов в коллекции;это очень полезно для определенных случаев использования, таких как ведение журнала.

По сути, вы можете ограничить размер (или количество документов) в коллекции, скажем .. 20 ГБ, и как только этот предел будет достигнут, MongoDB будетначинайте выбрасывать самые старые записи и заменять их новыми записями по мере их поступления.

Это отличный способ сохранить большой объем данных, отбросить более старые данные с течением времени и сохранить тот же объемиспользуемого дискового пространства.

26 голосов
/ 14 ноября 2012

У меня есть другое решение, которое может работать лучше, чем db.repairDatabase (), если вы не можете позволить себе заблокировать систему или у вас нет двойного хранилища.

Вы должны использовать набор реплик.

Мне кажется, что как только вы удалите все лишние данные, которые поглощают ваш диск, остановите вторичную реплику, сотрите каталог данных, запустите его и дайте ему повторно синхронизироваться с мастером.

Процесс занимает много времени, но он должен стоить всего несколько секунд простоя, когда вы выполняете rs.stepDown ().

Также это не может быть автоматизировано. Ну, может, но я не думаю, что хочу попробовать.

8 голосов
/ 14 января 2013

Для запуска 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 не содержит схемы, ничего, кроме индексов, не будет потеряно, и ваша БД и коллекции будут воссозданы, когда вставки для процессов будут запущены в следующий раз. Просто убедитесь, что ваши задания включают создание любых необходимых индексов в соответствующее время.

4 голосов
/ 23 октября 2014

Если вы используете наборы реплик , которые не были доступны при первоначальном написании этого вопроса, то вы можете настроить процесс для автоматического восстановления пространства без значительных сбоев или проблем с производительностью.

Для этого вы используете возможности автоматической начальной синхронизации вторичного устройства в наборе реплик.Объяснение: если вы выключите вторичный сервер, сотрете его файлы данных и перезапустите его, вторичный сервер будет синхронизироваться с нуля с одного из других узлов в наборе (по умолчанию он выбирает ближайший к нему узел, просматривая ответ пингараз).Когда происходит повторная синхронизация, все данные перезаписываются с нуля (включая индексы), фактически выполняют те же действия, что и восстановление, и освобождают дисковое пространство.

Запустив это на вторичных серверах (а затем отключив первичный иповторяя процесс), вы можете эффективно освободить место на диске во всем комплекте с минимальными перебоями.Вы должны быть осторожны, если вы читаете из вторичных серверов, так как это может вывести вторичное устройство из строя на потенциально долгое время.Вы также хотите убедиться, что ваше окно 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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...