Коллекция MongoDB, используемая для данных журнала: индекс или нет?

Я использую MongoDB в качестве временного хранилища журналов. Коллекция получает примерно 400 000 новых строк в час. Каждая строка содержит метку времени UNIX и строку JSON.

Периодически я хотел бы копировать содержимое коллекции в файл на S3, создавая файл для каждого часа, содержащий ~ 400 000 строк (например, today_10_11.log содержит все строки, полученные с 10 до 11 утра). Мне нужно сделать эту копию, пока коллекция получает вставки.

Мой вопрос: каково влияние на производительность наличия индекса в столбце меток времени для 400 000 почасовых вставок стихов по сравнению с дополнительным временем, которое потребуется для запроса строк на несколько часов.

Рассматриваемое приложение использует написанное на Ruby, работающее на Heroku и использующее плагин MongoHQ.


person Steve Wilhelm    schedule 09.02.2011    source источник


Ответы (4)


Mongo индексирует поле _id по умолчанию, а ObjectId уже начинается с временной метки, так что, по сути, Mongo уже индексирует вашу коллекцию по времени вставки за вас. Поэтому, если вы используете значения по умолчанию Mongo, вам не нужно индексировать второе поле метки времени (или даже добавлять его).

Чтобы получить время создания идентификатора объекта в ruby:

ruby-1.9.2-p136 :001 > id = BSON::ObjectId.new
 => BSON::ObjectId('4d5205ed0de0696c7b000001') 
ruby-1.9.2-p136 :002 > id.generation_time
 => 2011-02-09 03:11:41 UTC 

Чтобы сгенерировать идентификаторы объектов за заданное время:

ruby-1.9.2-p136 :003 > past_id = BSON::ObjectId.from_time(1.week.ago)
 => BSON::ObjectId('4d48cb970000000000000000') 

Так, например, если вы хотите загрузить все документы, вставленные за последнюю неделю, вы просто ищете _ids больше чем past_id и меньше чем id. Итак, через драйвер Ruby:

collection.find({:_id => {:$gt => past_id, :$lt => id}}).to_a
 => #... a big array of hashes.

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

Дополнительная информация об идентификаторах объектов.

person PreciousBodilyFluids    schedule 09.02.2011
comment
Это хороший совет относительно даты в идентификаторе BSON. Мне нужно было иметь трекер временных меток, потому что я также импортировал много старых журналов, где дата вставки не была датой события. Но я думаю, что для приложения здесь ваше решение, вероятно, будет хорошим. - person Michael Papile; 09.02.2011

У меня есть такое же приложение, как ваше, и в настоящее время оно содержит 150 миллионов записей журнала. При 400 тыс. в час эта БД быстро разрастется. 400 тыс. вставок в час с индексацией по отметке времени будут гораздо более полезными, чем выполнение неиндексированного запроса. У меня нет проблем с вставкой десятков миллионов записей в час с индексированной отметкой времени, но если я выполняю неиндексированный запрос по отметке времени, это занимает пару минут на сегменте из 4 серверов (с привязкой к процессору). Индексированный запрос появляется мгновенно. Так что определенно индексируйте его, накладные расходы на запись при индексировании не так высоки, а 400 000 записей в час - это немного для монго.

Одна вещь, на которую вы должны обратить внимание, это размер памяти. При 400 тысячах записей в час вы делаете 10 миллионов в день. Это потребовало бы около 350 МБ памяти в день, чтобы сохранить этот индекс в памяти. Так что, если это произойдет какое-то время, ваш индекс может быстро стать больше, чем память.

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

person Michael Papile    schedule 09.02.2011
comment
Михаил, спасибо за совет. Я удаляю записи, поэтому буду следить за производительностью ввода-вывода. - person Steve Wilhelm; 10.02.2011

Конечно, при каждой записи вам нужно будет обновлять данные индекса. Если вы собираетесь делать большие запросы к данным, вам определенно понадобится индекс.

Рассмотрите возможность сохранения метки времени в поле _id вместо идентификатора объекта MongoDB. Пока вы храните уникальные временные метки, все будет в порядке. _id не обязательно должен быть ObjectID, но имеет автоматический индекс для _id. Это может быть вашим лучшим выбором, так как вы не будете добавлять дополнительную нагрузку на индекс.

person Brendan W. McAdams    schedule 09.02.2011

Я бы просто использовал ограниченную коллекцию, неиндексированную, с пространством, скажем, для 600 тыс. строк, чтобы обеспечить слякоть. Раз в час выгружайте коллекцию в текстовый файл, а затем используйте grep для фильтрации строк, которые не относятся к вашей целевой дате. Это не позволяет вам использовать хорошие возможности БД, но это означает, что вам не нужно беспокоиться об индексах коллекций, сбросах или любой другой ерунде. Критичным для производительности является сохранение коллекции свободной для вставок, поэтому, если вы можете выполнять «жесткий» бит (фильтрация по дате) вне контекста БД, вы не должны оказывать заметного влияния на производительность. 400-600 тысяч строк текста тривиальны для grep и, вероятно, не должны занимать больше секунды или двух.

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

person Chris Heald    schedule 09.02.2011