Автоматически сокращать удаленное пространство в mongodb? - программирование
Подтвердить что ты не робот

Автоматически сокращать удаленное пространство в mongodb?

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

  • Как и в большинстве баз данных...   делайте такие операции, как сокращение   необходимо запланировать отдельное задание   сделайте это, нет "автозапуска" в   MongoDB. Фактически основные базы данных noSQL   (ненавижу это имя) только Riak   будет автошина. Итак, вам нужно будет   создать работу с помощью ОС   планировщик для запуска сжатия. Вы можете использовать bash script или выполнить задание PHP скрипт и т.д.

Сервера Javascript

Вы можете использовать Javascript на стороне сервера для сжатия и запускать JS через оболочку mongo на регулярной основе через задание (например, 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));

Это запустится и вернет что-то вроде...

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 начнет выкидывать самые старые записи и заменять их новыми записями по мере их поступления.

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

Ответ 2

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

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

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

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

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

Ответ 3

Запуск 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();

Операция export/drop/import для баз данных со многими коллекциями, скорее всего, приведет к такому же результату, но я не тестировал.

Также в качестве политики вы можете хранить постоянные коллекции в отдельной базе данных из ваших данных переходного процесса/обработки и просто отбрасывать базу данных обработки после завершения ваших заданий. Поскольку MongoDB не имеет схемы, ничего, кроме индексов, не будет потеряно, и ваши db и коллекции будут воссозданы, когда вставки для процессов будут выполняться дальше. Просто убедитесь, что ваши задания включают в себя создание любых индексов в подходящее время.

Ответ 4

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

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

Запустив это на вторичных серверах (а затем отменив основной и повторив процесс), вы сможете эффективно освободить место на диске во всем наборе с минимальным сбоем. Вам нужно быть осторожным, если вы читаете от второстепенных, так как это займет некоторое время после поворота в течение потенциально долгого времени. Вы также хотите убедиться, что ваше окно oplog достаточно для успешной повторной синхронизации, но это, как правило, то, что вы хотели бы убедиться в делаете вы это или нет.

Чтобы автоматизировать этот процесс, вам просто нужно запустить script для выполнения этого действия в отдельные дни (или аналогичные) для каждого члена вашего набора, предпочтительно во время вашего тихого времени или окна обслуживания. Очень наивная версия этого script будет выглядеть так в 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 [email protected]$MONGOHOST sudo service mongodb stop

# Wipe the data files for that server

ssh -t [email protected]$MONGOHOST sudo rm -rf $DBPATH
ssh -t [email protected]$MONGOHOST sudo mkdir $DBPATH
ssh -t [email protected]$MONGOHOST sudo chown mongodb:mongodb $DBPATH

# Start up server again
# similar to shutdown something like 
ssh -t [email protected]$MONGOHOST sudo service mongodb start